ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

LVS负载均衡全解析:从原理到DR模式配置与超时排障

LVS负载均衡全解析:从原理到DR模式配置与超时排障 前阵子有个朋友在群里问“LVS到底还值不值得学现在云原生一堆网关是不是不用折腾这个了”我的回答一直是值得而且很多大流量入口现在还在用LVS扛着。Linux Virtual Server这套东西从1998年走到今天靠的不是情怀而是它内核态转发带来的极致性能。这篇文章我打算把LVSLinux Virtual Server负载均衡器的原理、三种工作模式、调度算法、完整配置和排障思路从头到尾过一遍。尤其会重点聊聊被问得最多的空闲超时问题——很多人配置好后线上频繁断连十个里有八个是栽在timeout上。不管你是刚接触四层负载均衡的运维新人还是准备在生产环境正式落地LVS的进阶选手这篇文章都能给你一个可以直接参考的完整路线。1. LVS整体设计与方案选型思路1.1 LVS是什么它到底解决了什么问题LVS全称Linux Virtual Server是一套基于Linux内核实现的服务器集群方案。它的核心逻辑就一句话对外提供一个虚拟IPVIP把所有请求通过内核中的IPVSIP Virtual Server模块按预设的调度算法转发到后端的真实服务器Real Server简称RS上。它工作在OSI模型的第四层也就是传输层只看TCP/UDP的IP加端口不关心HTTP头、URL、Cookie这些七层内容。这个特点既是它的“边界”也是它的优势。因为不需要解析应用层数据所以LVS的处理路径极短数据包从网卡进来在内核里直接改写目的地址或MAC后发出去根本不经过用户态拷贝。对比Nginx、HAProxy这类工作在应用层的软件LVS在同等硬件条件下能支撑的并发连接数要高出一个量级这也是大型网站至今仍把LVS放在最前端的原因。它解决的核心问题有三个一是高性能单机可以支撑百万级别并发连接二是高可用结合Keepalived可以实现Director节点故障自动切换三是高扩展后端RS可以随时加减容量不够就加机器对客户端完全透明。1.2 三种工作模式怎么选LVS有三种包转发模式NAT、DR、TUN。理解这三者的区别是后续配置不出错的前提。NAT模式VS/NAT最直接Director收到客户端请求后通过DNAT把包的目的IP改成选中的RS地址RS处理完再把响应回给Director由Director改写源IP后转回客户端。这样来回流量都要过DirectorDirector很容易成为瓶颈。但好处是RS可以跨网段RS的网关指向Director就行架构简单适合小规模场景。DR模式VS/DR是生产中用的最多的方案。Director在转发时只改数据链路层的目标MAC地址把帧直接发给RS网络层的IP完全不变。RS在回环接口上绑定VIP收到数据后发现自己就是目标地址于是正常处理响应时直接以VIP作为源地址回给客户端走的是原路返回完全不经过Director。这意味着入向流量走Director出向流量各回各家Director的压力小了很多性能最好。代价是Director和RS必须在同一个二层网络里而且RS必须做ARP抑制否则客户端ARP请求VIP时会同时收到多台机器的响应。TUN模式VS/TUN是把请求包用IP隧道封装后送给RSRS解封装处理响应直接回客户端。它兼顾了NAT的跨网段能力和DR的吞吐性能但要求RS支持隧道协议配置和排障复杂度都高一些实际中用得不如DR普遍。放在一起看对比项NATDRTUN转发方式修改目的IP修改目标MACIP隧道封装响应路径必须经过DirectorRS直接回客户端RS直接回客户端网络要求可跨网段RS网关指Director必须同二层网络可跨网段需支持隧道Director压力大容易成瓶颈小理论性能最优较小配置复杂度低中要处理ARP中高适用场景小规模、跨网段同机房大流量首选跨机房、异构网络我的经验是同机房场景无脑优先DR反正现在机房里的RS基本都在同一个交换机下面DR的性价比最高只有RS分散在不同网段、又不想引入更复杂的方案时才考虑NAT或TUN。1.3 为什么现在还要选LVS很多人纠结Nginx也能做负载均衡为什么要多套一层LVS我的理解是它们根本不是竞争关系而是上下游关系。Nginx工作在七层能拿到HTTP完整信息适合做路由分发、缓存、限流、WAF这类精细化控制但七层解析本身就消耗CPU并发上来之后性能下降明显。LVS工作在四层逻辑简单、转发快适合挡在最前面处理海量TCP连接把流量“粗分”给后面的七层集群。于是就有了非常经典的“四层七层”分层架构客户端 - LVS四层负载均衡 - Nginx集群七层反向代理 - 业务服务器。LVS负责扛流量Nginx负责做业务路由各干各的活谁也不抢谁的资源。这个架构我现在搭系统还在用实测在高并发场景下比单纯堆Nginx稳定得多。2. 核心细节解析调度算法与关键参数2.1 静态调度算法有哪些LVS内置了十种调度算法先看静态的几种。RRRound Robin就是轮流分发每个请求按顺序分给下一台RS大家机会均等。前提是RS的硬件配置、处理能力都差不多否则弱的机器会先被打垮。WRRWeighted Round Robin在RR基础上加了权重权重越高的RS收到的连接越多。比如8核和16核的机器权重可以配成1和2。权重不是越高越好要根据实际处理能力压测得出拍脑袋配权重照样会把机器压垮。SHSource Hashing按客户端源IP做哈希同一个源IP的请求会固定落到同一台RS上天然实现了会话保持适合那些不方便用Cookie做会话粘滞的协议。但缺点也明显某台RS挂了哈希到它的那批客户端全部受到影响会话集中失效的风险比较大。DHDestination Hashing按目的IP做哈希多用于多台防火墙或缓存服务器的场景按目标地址把流量分流。日常业务负载均衡里用得少。2.2 动态调度算法怎么选动态算法的共同点是每次调度时都会去看后端的实时负载状态最常见的指标是连接数。LCLeast Connections把新请求分给当前活跃连接数最少的RS。这个算法在长连接场景下比较准但在短连接风暴下活跃连接数跳动很快调度可能不够均匀。WLCWeighted Least Connections在LC基础上结合了权重也是LVS的默认调度算法。计算公式是当前连接数除以权重取结果最小的RS。它兼顾了静态权重和动态负载大部分业务场景下用它都不会出大问题。SEDShortest Expected Delay在WLC基础上加了“延迟预估”优先选连接数除以权重后预期延迟最小的RS。NQNever Queue是SED的改进版保证不会有RS一直处于空闲排队状态适合响应速度差异较大的后端。LBLC基于局部性的最少连接和LBLCR带复制的局部性最少连接是专门给缓存服务器设计的。前者让相同目的IP的请求尽量走同一台缓存RS提高缓存命中率后者允许缓存复制到多台RS容忍单点故障。普通业务用不上但如果你是做缓存网关这两个算法值得研究。MHMaglev Hashing是后来加入的一致性哈希算法它解决的是SH在RS增删时大量会话迁移的问题只有少量连接会重新映射适合需要平滑扩缩容的场景。2.3 我常用的算法选型参考算法这个东西没有绝对的对错只有适不适合。我整理了这份参考后端配置均衡、无特殊要求直接默认WLC省心。需要会话保持、后端又不支持应用层粘滞SH或带持久性参数的WLC。长连接为主数据库连接池、WebSocketLC或WLC。短连接高并发HTTP接口WLC配合合理的超时参数。缓存集群LBLC或LBLCR。扩缩容频繁、尽量少的会话迁移MH。另外提醒一句调度算法解决的是“转发给谁”的问题会话保持不能只靠算法。生产环境里我通常会配合Keepalived的persistence_timeout一起用双保险。3. 实操过程与核心环节实现3.1 部署前要准备什么以DR模式为例假设我有两台RS一台Director都跑在同一个网段192.168.100.0/24Director192.168.100.10RS1192.168.100.11权重1RS2192.168.100.12权重2VIP192.168.100.100第一步是确认内核有没有IPVS模块。LVS的核心功能都在内核里目录系统一般默认编译了ip_vs模块但保险起见还是手动加载一下modprobe ip_vs modprobe ip_vs_wlc modprobe ip_vs_sh modprobe ip_vs_mh lsmod | grep ip_vsip_vs加载成功后会显示一批模块。接着安装用户态管理工具# Debian/Ubuntu apt install ipvsadm # CentOS/RHEL yum install ipvsadm如果ipvsadm -L -n执行时报“No such file or directory”基本就是ip_vs模块没加载回去加载模块再试。3.2 DR模式完整配置步骤先配置Director。把VIP配置到物理网卡上然后添加虚拟服务和两台RSip addr add 192.168.100.100/32 dev eth0 ipvsadm -A -t 192.168.100.100:80 -s wlc ipvsadm -a -t 192.168.100.100:80 -r 192.168.100.11:80 -g -w 1 ipvsadm -a -t 192.168.100.100:80 -r 192.168.100.12:80 -g -w 2这里的要点-A表示添加虚拟服务-t指定TCP协议加VIP端口-s指定调度算法。-a添加RS-r指定RS地址-g代表DR模式gatewayNAT模式用-mTUN模式用-i。-w配权重。VIP用/32掩码因为DR模式下VIP不应该出现在路由表中参与网段广播。然后是两台RS上的配置。RS要把VIP绑定到回环接口上同时必须做ARP抑制否则客户端ARP广播问VIP时RS也会应答流量就不经过Director了ip addr add 192.168.100.100/32 dev lo echo 1 /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 /proc/sys/net/ipv4/conf/all/arp_announce echo 1 /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 /proc/sys/net/ipv4/conf/lo/arp_announcearp_ignore设为1表示只应答目标IP是本机且属于到达网卡接口的ARP请求arp_announce设为2表示ARP响应使用源IP所在网卡的最佳本地地址。两行配合RS就不会对外宣告自己有VIP了。这些配置要写进/etc/sysctl.conf和开机脚本里别重启机器就失效。现在从客户端访问http://192.168.100.100请求会被转发到RS1或RS2。验证一下ipvsadm -L -n输出里能看到虚拟服务和两台RS的状态ActiveConn和InActConn会随着访问增长。再开一个终端跑ipvsadm -L -n -c能看到连接表里每一条转发记录的来源IP、目的IP和当前状态排障时这个命令是黄金工具。3.3 用Keepalived管好健康检查和高可用裸配ipvsadm的问题有两个一是RS挂了LVS不会感知请求照样转发过去用户直接报错二是Director自身单点Director挂了整个集群就瘫了。这两件事都交给Keepalived解决。Keepalived同时承担两个角色VRRP负责Director高可用两个Director抢一个VIPIPVS管理负责维护LVS规则和RS健康检查。配置核心部分如下vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.100.100/24 dev eth0 } } virtual_server 192.168.100.100 80 { delay_loop 6 lb_algo wlc lb_kind DR persistence_timeout 50 protocol TCP real_server 192.168.100.11 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.100.12 80 { weight 2 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }几个配置的坑我得单独说persistence_timeout是持久连接超时单位秒。它保证来自同一个源IP的请求在50秒内都发往同一台RS对不带会话的应用来说这是最简单的会话保持方案。但它也有副作用——某个源IP流量特别大时会长时间压在单台RS上导致负载不均。我见过有人把persistence_timeout设成3600结果一台机器被打爆另一台闲着。默认值或略高即可除非业务确实需要长时间粘滞。TCP_CHECK是Keepalived在Director上主动向RS发起TCP连接探活。这里有个容易忽略的细节如果RS上对应端口只允许特定来源访问探活会失败Keepalived会把健康RS误判为宕机。我踩过这种坑后来习惯在RS的iptables里单独放行Director的探活IP。另外Keepalived里的lb_kind DR和-g是对应的如果用了NAT模式记得改成NAT。两个Director的配置除了state和priority不同其他要保持一致否则VRRP会出现脑裂。配置完在Director上启动Keepalivedsystemctl enable --now keepalived此时LVS规则由Keepalived自动维护不再需要手动执行ipvsadm命令。用ipvsadm -L -n还能看到规则但增删由Keepalived管理。3.4 权重和容量怎么定权重不是拍脑袋定的。我一般先做压测分别压RS1和RS2得到单机QPS上限然后按QPS比例反推权重。比如RS1压测上限是8000 QPSRS2是16000 QPS权重就配1比2。权重真需要调整时用以下命令在线修改不用重启服务ipvsadm -e -t 192.168.100.100:80 -r 192.168.100.11:80 -g -w 3容量规划上DR模式下Director只处理入向请求理论上单台Director可以支撑的并发连接数主要受内存限制。每个连接条目在内核里占的内存很小4GB内存的Director扛几十万并发连接是常见的。但别忘了给Director留出足够的内核连接跟踪表空间必要时调大net.netfilter.nf_conntrack_max否则连接数上来之后新连接会被丢弃表现就是莫名其妙的超时。4. 空闲超时问题深挖线上断连的头号元凶4.1 空闲超时是怎么发生的被问得最多的问题就是“我的WebSocket连上之后过一会儿就被断了为什么”这就要说到LVS的连接表超时机制。IPVS在内核里维护一张连接表记录每一条转发连接的元数据。一条连接如果空闲太久IPVS会认为它已经结束了把表项清掉。默认的清理时间是ipvsadm -L --timeout输出结果一般是这样Timeout (tcp tcpfin udp): 900 120 300TCP空闲900秒15分钟、TCP FIN状态120秒、UDP空闲300秒。如果一条TCP连接在15分钟内没有数据包经过LVS连接表项就会被回收。问题在于表项被回收后客户端和后端其实还在维持着这条连接比如WebSocket的ping/pong间隔超过了15分钟或者某些长连接应用根本不发心跳。当下一个数据包到达LVS时LVS查不到对应表项只能把它当作一条新连接重新调度结果包被发到了另一台RS上甚至直接被丢弃原连接就断了。还有一种常见场景是UDPDNS、NTP这类短请求无所谓但部分基于UDP的实时通信服务300秒超时远不够一旦空闲超过5分钟就掉线。4.2 如何调整超时参数调整方法很简单ipvsadm --set 3600 120 300这会把TCP空闲超时改为3600秒TCP FIN超时120秒UDP空闲超时300秒。TCP FIN保持120秒没问题UDP如果有长时间无数据的业务也要相应调大。但这里我要多说一句超时改大不是没有代价的。连接表项是内存资源超时越长表里堆积的死连接越多。如果业务大部分是短连接、又开着很长的TCP超时表项会被大量无效连接占满新连接反而无法建立。商城里卖的“统一改大超时”方案真到线上是要出事的。正确姿势是短连接业务保持默认900秒就好别动。长连接、有心跳的业务把TCP超时调到比心跳间隔大2到3倍比如心跳30秒超时设90秒足够没必要上3600。无心跳但长时间空闲的连接首先考虑在应用层加心跳而不是无限调大LVS超时。另外Keepalived的persistence_timeout会和这个超时产生叠加效果。持久连接模板的超时控制的是“同一个源IP是否继续粘滞到同一台RS”它到期后连接不会被断开只是重新参与调度。所以如果你的会话保持失效、出现请求跑到另一台RS的情况查的不是ipvsadm --set而是persistence_timeout。4.3 长连接场景的更多处理技巧除了调超时还有几个内核参数能优化长连接场景。expire_nodest_conn默认0。如果设为1当RS不可用被Keepalived摘除时连接表里指向该RS的表项会被立即清理而不是干等到超时。这样RS恢复后老连接不会继续被错误地转发过去。我建议开启echo 1 /proc/sys/net/ipv4/vs/expire_nodest_connexpire_quiescent_templateKeepalived把RS标记为“静止”状态时是否清理对应的持久连接模板默认0。如果希望摘除RS后原先粘滞到它的客户端马上被重新散列到别的RS就把它设成1。sloppy_tcp允许IPVS在连接状态不完整时继续转发TCP包。如果你的环境里出现过连接表不同步、重启Director后大量连接异常的情况这个开关能减少连接中断但也会削弱对异常包的过滤能力生产环境谨慎开。对于WebSocket这类需要长时间维持连接的业务除了调大LVS超时我还会在应用层加心跳并且把心跳间隔控制在30到60秒。这样即使未来LVS超时配置被重置或迁移也不至于两分钟就断连。5. 常见问题与排查技巧实录5.1 典型报错速查表我把自己和同行遇到的高频问题整理成了表方便遇到问题时直接对号入座。现象可能原因解决办法ipvsadm -L -n报“No such file or directory”ip_vs模块未加载modprobe ip_vs重新执行客户端访问VIP不通Director上VIP没配或Keepalived没起来检查ip addr和keepalived状态后端RS能通但请求总打到固定一台RS调度算法是SH或persistence_timeout过大换WLC调小持久超时RS已经被摘除请求还是过去健康检查未生效或摘除前连接表还有残留确认TCP_CHECK配置开启expire_nodest_conn客户端偶尔超时连接瞬间断开空闲超时过短表项被回收按4.2节调整ipvsadm --set多台RS都在回ARPRS收不到包或Director和RS抢VIP没有做ARP抑制按3.2节设置arp_ignore/arp_announceDirector性能不错但吞吐上不去网卡中断不均、连接跟踪表满开网卡多队列调大nf_conntrack_maxKeepalived主备一直在切VRRP配置不一致或网络丢包对比vrrp_instance配置检查advert_int超时5.2 用连接表定位问题的思路排查LVS问题我有一套固定的操作顺序。先用ipvsadm -L -n确认规则在不在再看连接表ipvsadm -L -n -c连接表里每行都有连接状态。TCP场景下如果看到大量SYN_RECV状态堆积说明包到了LVS但RS没有正确回应赶紧去查RS的应用端口和防火墙。如果看到NONE状态很多多半是UDP转发或者连接已经被回收。再看统计数据ipvsadm -L -n --stats ipvsadm -L -n --rate--stats看累计包数、字节数、连接数--rate看每秒速率。通过对比两台RS的流量是否按权重比例分配能快速判断调度是否正常。如果确认LVS规则正常但请求还是不通用tcpdump在Director上看包有没有进来再到RS上看包有没有到达tcpdump -i eth0 host 192.168.100.100 and port 80包到了RS但应用没反应问题在RS包根本没到RS问题在网络或LVS转发路径上。用这个方式一步步缩小范围比瞎猜效率高得多。5.3 我踩过的三个实战坑第一个坑是DR模式下忘了关RS的rp_filter反向路径过滤。某些发行版默认开启了rp_filterRS收到VIP的数据包后发现源路由和到达接口不一致直接丢弃表现就是LVS转发正常但服务一直超时。解决办法是确认RS网卡配置里net.ipv4.conf.all.rp_filter和net.ipv4.conf.网卡.rp_filter为0或者2。第二个坑是Keepalived的virtual_ipaddress配置里忘了指定网卡。默认它会把VIP挂在默认路由对应的网卡上你要是服务器有多个网卡VIP可能被挂到了业务流量根本不走的接口上导致VIP能ping通的人和真正访问你的人不是同一条路径。后来我所有VIP配置都显式写成192.168.100.100/24 dev eth0再没出过这事。第三个坑是线上扩容时直接对RS执行ipvsadm -a添加新机器忘了在RS上做ARP抑制。新RS一上线整个集群的VIP ARP响应被打乱客户端部分流量直连新RS全部转发绕过Director问题持续到大半夜才定位到是ARP广播冲突。扩容操作前一定把RS侧配置检查清单过一遍尤其是ARP和sysctl项宁可慢一点也不要带病上线。6. 生产环境落地的一点个人体会LVS配置本身并不复杂复杂的是你对自己业务的流量模型有没有清晰的认知。是短连接还是长连接需不需要会话保持后端机器能力是否均衡这些问题的答案直接决定了调度算法、超时参数和持久化时间该怎么配。我每接一个项目第一件事永远是梳理业务流量特征再动手写配置而不是把上一套架构的配置原封不动复制过来。最后再分享一个实用习惯我会把所有LVS相关参数算法、超时、权重、持久化时间、内核开关写进配置管理里并标注清楚每个参数的调整理由。这样每次变更都有据可查线上出问题回滚也快。负载均衡是流量入口改动影响面极大宁可多花时间做预案也不要在半夜靠手速救命。希望这篇文章能让你少踩几个我当年踩过的坑。
返回列表