尧图精选

LVS负载均衡实战:DR模式、keepalived高可用与性能调优

🕒 发布时间:2026/10/2 4:55:44 📁 来源:尧图网络
搞负载均衡这一挂的朋友应该都绕不开LVSLinux Virtual Server这个名字。尤其是在早年互联网架构里LVS几乎是四层负载均衡的代名词。现在很多团队一上来就扔一台Nginx在前面扛流量但真正到了大规模、高并发、追求极致性能的场景内核态的LVS依然是很多架构师心里最稳的那张底牌。这篇文章我不打算念文档而是结合我自己从搭实验环境到压测、再到生产环境排障的真实经历把LVS的核心设计、三种工作模式、调度算法选型、keepalived高可用组合、性能调优方向和常见坑位一次讲透。无论你是刚接触负载均衡的运维新人还是已经在用Nginx但想搞明白LVS为什么更快的老手这篇文章都值得花几分钟读进去。1. LVS到底是什么东西为什么它能这么硬先说个可能很多人都没仔细想过的事实LVS是1998年由章文嵩博士发起的开源项目到现在二十多年了它依然是Linux内核里自带的一套负载均衡解决方案核心模块叫ipvs用户态的管理工具叫ipvsadm。2017年ipvs正式合并进Linux内核主线也就是说不管你用的是什么发行版只要内核够新LVS的能力其实一直躺在系统里。它和Nginx、HAProxy最大的区别在哪LVS跑在内核态工作在TCP/IP协议栈的IP层属于四层负载均衡。这意味着数据包从网卡进来之后直接在内核里就被改写和转发根本不需要把数据拷贝到用户态也不需要建立TCP连接来做代理转发。Nginx处理每一个请求都要经过“内核收包 - 用户态解析HTTP - 内核发包”这样反复的上下文切换和数据拷贝而LVS直接把这一段路给省了。用一句直白的话说LVS是在网络栈的“高速公路”上做立交桥Nginx是在收费站里做路线引导前者天然就快一个量级。实际项目里LVS最常见的用法是放在整个流量入口的最前端比如架构是LVS - Nginx - 应用服务。LVS用极低的资源消耗扛住海量TCP连接请求再把流量分发给后端的Nginx层去做HTTP层面的处理。我在压测环境里做过对比同样是一台8核16G的机器Nginx单机扛个几万QPS就要开始紧张CPU而LVS跑在纯转发模式下几十万PPS的连接处理是很轻松的事情资源的消耗几乎可以忽略不计。不过说句公道话LVS不是万能的。它是四层设备看不到HTTP的URL、Header、Cookie这些七层信息没法做路径级别的路由也没法做内容缓存。所以它适合负责流量分发和接入层高可用而不是替代Nginx那层业务逻辑。理解了这个定位后面所有的架构选择和调优思路就都顺了。2. 三种工作模式拆解NAT、DR、Tunnel到底怎么选LVS支持三种工作模式很多初学者就是在这里被绕晕的。我在带团队的时候经常打一个比方LVS就像个前台快递分发中心NAT模式是每一份快递都要寄回分发中心再发出去DR模式是分发中心只管把快递塞给快递员快递员直接送到客户手里Tunnel模式则是用特快专递通道把包裹整个空投到其他城市的分站点。三种模式各有各的适用场景选错了要么性能上不去要么网络结构搞不定。2.1 NAT模式最简单但容易成为瓶颈NAT模式下客户端请求到达LVS后LVS通过改写数据包的目的IP地址把流量转发给后端的Real Server简称RS。RS处理完请求后回包要再送回给LVS由LVS改写源IP地址伪装成VIP再返回给客户端。这个模式的优点是非常直观后端RS只需要配置一个私网IP不需要做任何额外设置网关直接指向LVS的内网IP就行。但它的瓶颈也很明显所有的入向流量和出向流量都要经过LVSLVS既要改请求包的目的IP又要改回包的源IP压力非常大。一旦业务流量大了LVS节点最先崩的不是CPU而是网卡带宽。所以我通常只在集群规模小、流量可控的场景下推荐NAT模式比如几十台以内的Web集群或者对LVS不熟悉、想快速验证负载均衡效果的实验环境。配置NAT模式前记得确认一件事把LVS的IP转发功能打开也就是设置net.ipv4.ip_forward 1不然数据包到了LVS手里也转发不出去。2.2 DR模式生产环境用得最多的方案DR模式全称是Direct Routing相比之下它巧妙得多。请求到达LVS后LVS不改IP只把数据链路层的MAC地址改为目标RS的MAC地址然后在同一个二层网络内把包转发出去。RS接收到请求后发现自己的一块虚拟网卡上也绑定了VIP就是写在lo接口上的那个VIP地址于是直接处理请求并且以VIP为源IP直接把响应包返回给客户端网关。这里最妙的一点是响应流量完全不用再绕回LVS。客户端发一个请求给LVSLVS只负责“分发包裹”RS拿到包裹后直接“送货上门”。所以DR模式下LVS节点的压力只有入向流量的一半吞吐能力比NAT模式高出好几倍这也是为什么绝大多数线上架构都采用DR模式的原因。DR模式有个硬性前提LVS和所有RS必须在同一个二层广播域里也就是同一台交换机下不能跨路由转发否则MAC改写就没法到达目标机器了。另外RS上必须做ARP抑制否则RS上的VIP一旦响应ARP广播客户端就会发现VIP对应多个MAC地址直接绕过LVS把请求发到某台RS上负载均衡就全乱套了。这部分我在后面的实操章节会详细展开。2.3 Tunnel模式跨机房分发的最佳解Tunnel模式全称是IP Tunneling原理有点像DR模式的远程版。LVS把原始数据包用IPIP隧道封装成新的IP包通过互联网或者专线隧道发送给位于不同物理位置的RS。RS收到后解封装还原出原始请求包并处理响应包同样直接返回给客户端。这种模式解决的核心问题是跨机房、跨地域的流量调度。比如你在北京部署了LVS入口后端的RS分别在华北、华南两个机房Tunnel模式就能把流量调度过去。缺点就是需要RS支持并开启IPIP隧道协议一般要在RS上建立tunl虚拟隧道接口运维复杂度比DR模式高不少。三种模式的选型思路我整理成了一张表方便对照模式请求转发方式响应流量路径RS要求网络要求适用场景NAT修改目的IP必须经LVS返回无需额外配置支持跨网段小规模集群、快速验证DR修改MAC地址RS直连返回客户端绑定VIPARP抑制必须在同一二层网络大多数生产环境Tunnel封装成隧道包RS直连返回客户端开启IPIP隧道接口可跨机房/跨网段多机房异地调度3. 调度算法轮询之外的那些门道LVS自带了十种调度算法很多人配置的时候就选默认的wlc然后就不管了其实算法的选择直接决定了流量分配的均衡程度和后端资源的利用率。我先把这些算法按固定和动态分成两大类再聊聊实际选型中的一些体会。固定调度算法不关心后端RS当前的负载情况只管按逻辑分配rr轮询、wrr加权轮询、dh目标地址哈希、sh源地址哈希。动态调度算法则会根据后端RS当前的活跃连接数等指标来动态判断该把请求交给谁lc最少连接、wlc加权最少连接、sed最短期望延迟、nq永不排队、lblc基于局部性的最少连接、lblcr带复制的基于局部性的最少连接。默认的wlc算法它的实际计算公式是(active_conn 1) / weight谁的比值小就把请求给谁。这个算法最大的优点是在集群内RS性能有差异的时候能自动倾斜性能好的机器配上更大的权重就会承担更多流量性能弱的机器也不至于被打爆。我在生产环境用wlc配不同权重的经验是2C4G的机器权重给28C16G的机器权重给5到6效果比平均轮询好得多。不过wlc不是万能的。如果后端所有RS的配置完全一致用最简单的rr反而更省心因为wlc需要维护实时的连接状态调度器本身会多一点点开销。长连接场景下比如WebSocket、数据库连接池这类我反而建议用sh源地址哈希确保同一个客户端的请求总是被发往同一台RS这样连接状态可以保证不漂移业务逻辑上也不需要额外的状态同步。至于lblc和lblcr它们在处理缓存类业务时很好用发往同一目标地址的请求会被尽量调度到同一台RS这样缓存的命中率能提得很高。但这类算法的状态维护复杂对调度器内存有一点压力一般的业务用不上碰到了再深入研究不迟。4. 调度算法选型实战推荐给一个最直接的参考表吧这是我在不同业务场景下实际验证过的推荐业务场景推荐算法理由普通HTTP短连接服务wlc默认算法综合均衡效果好后端机器配置差异大wrr或wlc用权重控制流量比例WebSocket等长连接sh保证同一会话固定调度到同一台RS数据库连接层sh避免连接跨实例漂移缓存服务lblcr提升缓存命中率减少回源同配置简单集群rr开销最小逻辑最透明5. 实操手把手搭一套LVS DR模式负载均衡纸上谈兵没意思这里我直接用一套最小化配置带你走一遍DR模式的完整落地流程。假设我用三台机器前面是LVS调度器后面两台RS提供Web服务。VIP我用192.168.10.100两台RS的内网IP分别是192.168.10.11和192.168.10.12。5.1 调度器配置先用ipvsadm定义虚拟服务注册后端真实服务器并指定DR模式和权重ipvsadm -A -t 192.168.10.100:80 -s wlc ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.11:80 -g -w 1 ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.12:80 -g -w 1这里-A表示添加虚拟服务-t指定协议类型为TCP-s wlc指定调度算法-a表示添加Real Server-r指定RS地址-g表示使用DR模式gatewaying-w设置权重。LVS调度器自身的网卡或lo接口上还必须有VIP地址。一般建议绑在lo接口上避免影响外部通信ip addr add 192.168.10.100/32 dev lo同时打开路由转发虽然DR模式不依赖三层转发但保持标准设置更稳sysctl -w net.ipv4.ip_forward15.2 后端RS配置每台RS同样要在lo接口上绑定VIP并设置严格的ARP抑制参数。为什么要抑制ARP因为VIP如果通过ARP广播出去交换机上就会同时出现多个VIP的MAC记录客户端的ARP缓存表也会混乱流量就不走LVS了。ip addr add 192.168.10.100/32 dev lo sysctl -w net.ipv4.conf.all.arp_ignore1 sysctl -w net.ipv4.conf.all.arp_announce2 sysctl -w net.ipv4.conf.lo.arp_ignore1 sysctl -w net.ipv4.conf.lo.arp_announce2arp_ignore1的意思是只回答目标IP是本接口地址的ARP请求arp_announce2的意思是ARP通告使用网络接口自身的最优本地地址避免把VIP的MAC地址广播出去。这两个参数必须同时设置而且要覆盖到lo接口和all接口一个都不能少。生产环境里还要把这两个参数写进/etc/sysctl.conf防止重启后失效。5.3 验证与检查配置完成后你可以在调度器上查看当前的负载均衡列表ipvsadm -L -n --stats如果看到两台RS的ActiveConn和InActConn都在增长说明转发已经正常。再用一台测试机反复请求VIP观察请求是否随机落在两台RS上。for i in $(seq 1 20); do curl -s http://192.168.10.100/ | grep hostname; done我自己在刚接触LVS的时候最常犯的错就是RS上只把VIP绑上去却忘了做ARP抑制结果客户端直接绕过LVS打到了RS上怎么查都查不出问题。这个细节建议新手反复确认。6. keepalived组合高可用版本的LVS才是真的能上线单台LVS调度器无论性能多强都只是单点。生产环境里LVS必须和keepalived组合使用形成主备双机甚至多机。keepalived的核心是VRRP协议它通过组播报文在主备节点之间传递心跳信息。正常情况下主节点持有VIP并提供服务备份节点在持续收不到主节点的心跳后会接管VIP这样就实现了故障转移。架构上其实是一个虚拟路由组对外始终只暴露那个VIP客户端根本感觉不到后端调度器的变化。一个精简的keepalived配置大致是下面这样global_defs { notification_email { adminexample.com } router_id LVS_DEVEL } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.10.100 } } virtual_server 192.168.10.100 80 { delay_loop 6 lb_algo wlc lb_kind DR persistence_timeout 50 protocol TCP real_server 192.168.10.11 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.10.12 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }两个节点配置里的state分别是MASTER和BACKUPpriority主高备低advert_int是心跳间隔秒数virtual_ipaddress就是对外提供的VIP。keepalived不仅负责VIP的漂移还会周期性地用TCP_CHECK探测后端的RS健康状态RS一旦宕机就自动摘除恢复后自动加回。我在配置了keepalived之后最常遇到的一个问题是主备切换频繁触发。追查下来基本都是VRRP的心跳报文被防火墙拦了或者主备节点的时间偏差太大。V2版本的VRRP用的是组播地址224.0.0.18必须在防火墙放行这个组播地址排查方向直接往这上面靠基本都是这个原因。还有一个小细节persistence_timeout 50表示50秒的持久连接时间这是为了让同一个用户在短时间内始终访问同一台RS对需要保持会话的Web应用很友好。但如果后端是无状态服务这个值建议设成0否则流量会集中在某个RS上等持久时间过了才重新均衡浪费了后端资源。7. 性能调优的几个关键参数以及我踩过的坑LVS本身的性能很高但前提是你得把系统层面的参数配合上。这一节我挑几个真正影响吞吐量和稳定性的关键点来讲。7.1 连接超时设置LVS内核会维护一张连接状态表不同协议的连接空闲多久后被回收是用ipvsadm --set来控制的ipvsadm --set tcp tcpfin udp # 例如 ipvsadm --set 3600 120 300三个参数依次是TCP空闲超时时间、TCP FIN状态超时时间、UDP空闲超时时间。如果业务里有很多长连接建议把TCP超时调高一些比如3600秒如果主要是短连接HTTP保持默认就行。这个值太大会导致连接表里堆积大量过期连接浪费内核内存太小则会让正常的慢速连接被误杀。7.2 连接Hash表大小LVS的连接查找依赖哈希表默认大小是2的16次方即65536条左右的连接跟踪能力。高并发场景下可以调大这个表sysctl -w net.ipv4.vs.conn_tab_bits20conn_tab_bits20代表哈希表大小是2的20次方能支撑约100万个并发的连接跟踪。改这个参数最直观的收益是当并发数接近表的上限时不会被哈希碰撞拖慢查找速度。7.3 内核TCP栈参数我在调优LVS的时候还会检查这几个参数sysctl -w net.ipv4.tcp_tw_reuse1 sysctl -w net.ipv4.tcp_max_tw_buckets100000 sysctl -w net.ipv4.tcp_fin_timeout30tcp_tw_reuse允许新的TCP连接复用处于TIME_WAIT状态的端口在大量短连接场景下能明显缓解端口耗尽问题。但注意这个参数在LVS NAT模式下要格外小心因为NAT模式会修改数据包开启TIME_WAIT复用可能导致连接状态异常我实际在NAT模式下遇到过服务无响应的问题后来关掉就正常了。所以这两个参数要结合模式来判断不要无脑照抄。7.4 网卡多队列与RSSLVS转发性能再高最终流量还是得从物理网卡进出。单队列网卡在高PPS下会触发软中断瓶颈表现为单个CPU核心被打满而其他核心闲置。解决方法是用网卡的RSSReceive Side Scaling特性让每个队列绑定不同的CPU核心ethtool -l eth0 # 查看队列数量 ethtool -L eth0 combined 16 # 设置为16个队列对于不支持RSS的虚拟机网卡可以启用RPSReceive Packet Steering把收到的包分发到多个CPU软中断中处理echo ffff /sys/class/net/eth0/queues/rx-0/rps_cpus这里ffff是CPU掩码表示16个CPU。配合中断亲和性设置LVS在16核机器上跑满线速转发是完全可以做到的。8. LVS与Nginx、HAProxy的选型对比聊到这儿肯定有人会问LVS这么好那我是不是就把Nginx扔了直接全上LVS答案绝对是否定的。这三者在负载均衡体系里根本不是互相替代的关系而是分层的合作关系。LVS的优势是纯粹的内核态四层转发性能天花板最高但它不理解HTTP协议无法根据URL做路由也做不了SSL卸载和HTTP缓存。Nginx的优势恰恰是七层能力正则路由、Rewrite、反向代理、缓存、gzip、SSL终止都是它的强项但它每处理一个请求都要经过用户态和内核态之间的多次切换单机的数据拷贝开销大性能上限比LVS低。HAProxy则比较折中它支持四层和七层代理四层模式在用户态里也算非常优秀的配置简单灵活但它同样受限于用户态开销不敌LVS的内核态转发。所以真正成熟的架构从来都是分层配合的流量入口用LVS做四层分发保证超大规模并发和高可用中间层用Nginx做七层路由处理URL匹配、静态资源、SSL落地后端连接应用服务比如PHP-FPM、Tomcat、Go应用进程我自己在做过一次大型活动的压测时流量峰值从平时的几千QPS突增到几十万QPS如果前端只挂NginxCPU早就飙红了。但加了LVS在前端Nginx只需要处理被LVS分发进来的有效业务流量系统整体稳定得多。那次经历之后我在架构设计里只要预估流量规模会过万QPS就一定会把LVS层加上。9. 那些年我在LVS上踩过的坑完整排查实录9.1 VIP始终curl不通ping也丢刚配好的LVS外部访问VIP超时。用ip addr查看VIP也确实在节点上。后来排查出问题出在RS的ARP抑制没有生效。RS把VIP绑在自己的lo接口上同时还响应了ARP请求导致客户端的ARP缓存里存了RS的MAC数据包直接到RS就绕过了LVS。这种问题最典型的查法是在一台客户端机器上执行arp -a看VIP对应的MAC地址是不是LVS调度器的MAC。不是的话先去把所有RS上的arp_ignore和arp_announce改对再清空客户端的ARP缓存重新访问故障基本都能解决。这个过程我后面每次搭LVS都会第一件事检查避免浪费一整天抓包排障。9.2 keepalived主备交替切换服务间歇性不可用用keepalived搭完主备之后发现主节点和备节点的VIP经常在切换每次切换都有几秒的请求中断。抓虚拟组播报文发现主备都能收到对方的VRRP心跳但偶尔会丢失几次。最终定位到是交换机的组播泛洪抑制策略把224.0.0.18的组播包丢了。把VRRP的通信改成单播模式或者给keepalived单独设置一个组播源端口问题就不出现了。配置VRRP单播的方式是在实例里加unicast_src_ip和unicast_peer让心跳走指定的IP单播不依赖组播网络环境稳定性更好。具体原理是用单播替代组播避免依赖网络组播质量很多云机房环境里组播根本不通用单向单播模式是个很实用的方案。9.3 权重已经调低流量还是往某台机器跑这是我踩过的一个特别容易让人蒙圈的坑。LVS的wlc算法基于活跃连接数如果一个RS上有大量长连接一直没有断开即使它的权重已经调低算法算下来的比值依然可能比其他RS小流量该来还是来。解决方法是在ipvsadm里手动清空那台RS的连接或者把persistence_timeout调成0让新连接尽快重新分布。9.4 一台RS宕机后新连接仍然往里发keepalived的健康检查机制需要时间发现RS异常并把它摘除。如果RS挂了但keepalived的探测周期内没有及时反应过来LVS仍会转发一部分流量过去表现为部分请求直接超时。实际经验是把delay_loop设成3秒TCP_CHECK的connect_timeout设成2秒整体检出速度在5秒以内对大多数业务来说损失就已经很小了。更精细的做法是写一个自定义健康检查脚本检测HTTP接口状态码而不是只探TCP端口。10. 写在最后的一点个人经验总结LVS这套东西放在今天来看依然没有过时原因在于它解决的问题是网络栈层面的“分发”这个需求永远不会消失。做架构选型的时候我个人的体会是不要盲目追求最强大的技术而是找到与业务规模最匹配的工具。几台机器的小集群用Nginx完全够了甚至系统自带的DNS轮询都能撑住但如果你的流量在往上走、团队想认真设计高可用架构把LVS接入进来绝对是一笔划算的投资。最后分享一个小技巧维护LVS的时候一定要养成定期执行ipvsadm -L -n --stats和ipvsadm -L -n -t的习惯一个看流量统计一个看连接分布。这两条命令输出的数据就能帮你快速判断流量是否偏斜、哪台RS连接数异常比上线后到处抓包效率高太多了。希望这篇文章能让你少走一些我走过的弯路。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →