1. 先弄明白一件事:LVS到底解决什么问题
聊LVS之前,先说个我这两年感受特别深的现象。每次和年轻一点的同行聊负载均衡,他们第一反应就是Nginx、HAProxy,再问细一点就是K8s的Ingress、Service Mesh。这没错,这些确实是当下最主流的流量入口方案。但真到了大流量核心链路,你会发现LVS依然默默地趴在最前面,扛着每天几个亿的请求,而且一跑就是好几年不带重启的。
LVS,全称Linux Virtual Server,是章文嵩博士在1998年发起的开源项目。它工作在Linux内核态,通过IP Virtual Server(IPVS)框架实现四层负载均衡。翻译成人话就是:它直接改数据包的目标地址或MAC地址,把进来的请求分发到后端一堆真实服务器上。因为在内核态干活,它不像Nginx那样要经过用户态和内核态的反复切换,单机性能可以做到远超七层代理。在核心生产环境里,LVS通常作为最前端的接入层,后面再挂Nginx做七层路由和业务转发。
所以这篇内容定位很明确:第一,把LVS的工作原理讲透,不是停留在“它是个负载均衡器”这种层面;第二,给出我实际部署中用到的完整方案和配置,可以直接抄作业;第三,讲讲那些官方文档不会告诉你的坑,尤其是ARP问题、VIP漂移这些生产环境的经典故障。适合谁看?后端开发、运维工程师、SRE,以及所有正在纠结“到底该用LVS还是Nginx”的人。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手之前先把架构想清楚:四层和七层的边界在哪
很多人对LVS的第一反应是“现在还有必要学这个吗”。我的回答是,有必要,前提是你得先理解它和七层负载均衡的分工边界。
2.1 四层转发和七层转发到底差在哪
先说一个最简单的判断标准:Nginx处理的是HTTP协议,它能看到URL、Header、Cookie这些应用层信息,所以可以做非常精细的路由规则,比如“/api开头的请求转发到A组服务”“带特定Cookie的请求走新版本”这种。但代价是,每一个请求都要在用户态做完整的协议解析,CPU的消耗非常高。
LVS看不到这些,它只认IP、端口、协议类型。进来的包,LVS按照预设的调度算法,直接改包的目标地址或者MAC,然后扔给后端。这个动作发生在内核协议栈里,没有用户态的上下文切换,没有协议解析的额外开销。所以同样的硬件配置,LVS能支撑的并发连接数和吞吐量,远远超过Nginx。
我自己的一个线上集群,接入层两台LVS,每台峰值能跑到将近20万QPS,CPU使用率基本稳定在30%以下。同样的流量想让Nginx扛,至少得横向铺一二十台才稳得住。
2.2 生产环境里一套典型的LVS+Nginx架构长什么样
从上面这个对比你应该能看出来,LVS和Nginx不是替代关系,而是配合关系。我目前维护的核心链路是这样的:
code复制用户请求
↓
DNS解析到VIP(虚拟IP)
↓
LVS主节点(keepalived管理VIP漂移)
↓
LVS备节点(主节点挂了自动接管VIP)
↓
Nginx集群(七层反向代理,按域名/URI做路由)
↓
Tomcat/Spring Boot业务集群
↓
MySQL/Redis等数据层
最外层LVS干的是“粗活”:把海量连接快速分发给后面的Nginx集群。Nginx干的是“细活”:根据请求的具体内容做路由、做限流、做缓存。这一层一层剥下来,每一层都只做自己最擅长的事,系统才扛得住。
我之前还见过一种“裸奔”的用法,LVS直接转发到应用服务器,中间不挂Nginx。小规模业务没问题,请求量一旦上来,后端应用服务器直接暴露在四层流量下,没法做精细的路由和防护,扩容也不灵活。除非业务极其简单,不然我不建议这么干。
3. 三种转发模式选型:DR、TUN、NAT各自能干什么不能干什么
LVS有三种工作模式,分别是DR(Direct Routing,直接路由)、TUN(IP Tunneling,IP隧道)、NAT(Network Address Translation,网络地址转换)。这是学习LVS最核心的部分,也是选型最容易出错的部分。我一个个说。
3.1 DR模式:生产环境用最多的方案
DR模式的核心逻辑简单粗暴:LVS只负责改数据链路层的MAC地址,不改IP地址。请求到达LVS后,LVS根据调度算法选一台后端RealServer,把数据帧的目标MAC改成那台RealServer的MAC,然后重新扔回交换机。RealServer收到这个帧,发现目标IP是VIP(因为VIP配在了RealServer的loopback接口上),就接收处理。响应数据包不走LVS,直接由RealServer回给客户端。
这个设计妙在哪?响应流量不经过负载均衡器,LVS只处理入站请求,压力直接减半。所以DR模式是三种模式里吞吐量最高的,也是生产环境最主流的用法。
但DR模式有个硬前提:LVS和所有RealServer必须在同一个物理二层网络里。因为MAC地址交换只在广播域内有效,跨网段就玩不转了。另外有个最关键的细节:RealServer必须在loopback接口上配置VIP,同时抑制ARP响应,否则客户端直接ARP请求VIP时,RealServer会抢答,流量直接绕过LVS打到后端的某台机器上。这个配置我后面部署篇会详细给。
3.2 TUN模式和NAT模式什么时候用
TUN模式是LVS把请求通过IP-IP隧道封装一层,转发给RealServer,RealServer解开隧道后处理,响应直接回客户端。好处是不受二层网络限制,LVS和RealServer可以跨网段部署。缺点是隧道封装有额外开销,而且每台RealServer都要支持隧道协议。我实际工作中用TUN模式的机会非常少,除非网络架构确实无法满足DR模式的同网段要求,否则不推荐优先选它。
NAT模式是LVS做地址转换,改写数据包的目标IP为RealServer的IP。RealServer处理完,响应再回到LVS,LVS把源IP改回VIP,再回给客户端。好处是RealServer只需要配私网IP,隐藏在后端比较安全,而且不要求同网段。坏处是流量来了要经过LVS,走了还要经过LVS,LVS很容易成为瓶颈。我在小规模场景(几台到十几台后端)用过NAT模式,规模上去之后还是老老实实换回了DR。
3.3 模式选型一张表说清楚
| 对比项 | DR模式 | TUN模式 | NAT模式 |
|---|---|---|---|
| RealServer是否响应客户端 | 是,直接响应 | 是,直接响应 | 否,经LVS中转 |
| LVS是否处理响应流量 | 否 | 否 | 是 |
| RealServer是否需配置VIP | 是(lo接口) | 是(隧道接口) | 否 |
| 后端是否必须同网段 | 是 | 否 | 否 |
| 后端是否需公网/独立IP | 需要能和客户端通信 | 需要能和客户端通信 | 只需要私网IP |
| 性能 | 最高 | 较高(隧道有损耗) | 一般 |
| 适用规模 | 大流量核心链路 | 跨机房/跨网段场景 | 小规模、注重隐藏后端 |
4. 调度算法不是越复杂越好:从rr到WRR的实际选择逻辑
LVS的调度算法,是另一个容易让人犯迷糊的地方。内核里支持的算法很多,但实际生产环境真正用到的,就那么几个。我先分类,再讲我的选择逻辑。
4.1 静态算法和动态算法的区别
静态算法就是不看后端RealServer的任何状态,闷头按固定策略分发。动态算法则要考虑后端当前的连接数等指标。注意这里说的是连接数,不是CPU负载,LVS在内核态拿不到后端的CPU使用率。
常用的静态算法有:
- rr(轮询):按顺序一个个往后端分发。如果后端性能完全一样,rr是最简单也最公平的。但现实是后端机器配置经常不一样,有的8核有的16核,rr容易让性能差的机器先扛不住。
- wrr(加权轮询):给每台RealServer配一个weight值,性能好的权重给高一点,LVS按权重比例分配连接。官方推荐这个,实际用它也最多。
- sh(源地址哈希):把客户端的IP哈希一下,同一个客户端IP固定调度到同一台RealServer。适合需要保持会话的场景,比如某些老的业务系统,Session还放在本地内存里,不搞共享Session,那就必须用sh。
常用的动态算法有:
- lc(最少连接):谁的连接数最少,新的请求就给谁。这个策略眼不见为净,不看后端性能,只看连接数。如果后端机器性能差异大,纯看连接数很吃亏,因为性能好的机器处理请求快,连接数可能反而一直很低。
- wlc(加权最少连接):在lc的基础上加上权重。官方默认算法就是wlc,生产环境也用得最多。
4.2 我实际部署中的算法选择
说了这么多,给出我的选型建议:
后端机器配置完全一致,且所有请求的处理开销差不多,用wrr就够了。后端业务复杂,有些请求很重、有些请求很轻,耗时差异大,选wlc,因为连接数能更真实地反映这台机器当前的忙碌程度。
举个我踩过的例子。之前有个业务集群,因为历史原因,四台后端机器配置一样,但其中一台上还跑着报表任务,白天CPU经常飙到80%。当时用的是wrr,权重都一样,结果那台机器偶尔出现请求超时。后来改成wlc,LVS发现那台机器连接数堆积得比别的机器快,自动就少给它分流量了,超时问题基本消失。
还有一些业务对会话保持有硬性要求,比如购物车信息存在本地Session,那就优先考虑sh。但实话实说,这个思路在现在微服务架构下已经不太行了,更好的做法是上Redis存Session,应用层怎么扩都行,然后把LVS调度算法切回wrr或者wlc。
5. 高可用架构怎么搭:keepalived守护VIP的完整机制
单台LVS就是单点故障,没人敢在生产环境这么干。这里必须引入keepalived,通过VRRP协议实现VIP在主备节点之间漂移,保证LVS挂了,流量不中断。
5.1 VRRP和VIP漂移的基本机制
VRRP,全称Virtual Router Redundancy Protocol,虚拟路由冗余协议。核心思想是一组路由器(这里是LVS节点)共用一个虚拟IP,也就是VIP。正常情况下VIP绑定在主节点上,主节点会周期性向备节点发送VRRP通告报文,告诉备节点“我还活着”。
如果备节点连续几个通告周期没收到主节点的消息,它就会认为主节点挂了,开始抢占VIP。注意抢占这个词,它是VRRP内置的机制:备节点在优先级的比较中赢了,就会把VIP配置到自己的网卡上,同时发送免费ARP广播,告诉整个二层网络“VIP的MAC地址已经变成我了”。交换机更新MAC表之后,后续发往VIP的流量就会切到新的主节点上。
5.2 keepalived配置实录
这是我线上使用的keepalived.conf主节点配置,删掉了敏感信息,保留了核心骨架:
conf复制global_defs {
router_id LVS_MASTER
enable_script_security
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 你的密码
}
virtual_ipaddress {
192.168.1.200/24 dev eth0
}
}
virtual_server 192.168.1.200 80 {
delay_loop 6
lb_algo wrr
lb_kind DR
protocol TCP
real_server 192.168.1.11 80 {
weight 5
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.1.12 80 {
weight 5
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}
几个关键点说明一下:
nopreempt这个参数,强烈建议加上。 默认情况下,主节点恢复之后会抢占回VIP,这会导致一次不必要的网络抖动。加上nopreempt,新主节点会继续干活,原主节点恢复后以备节点身份待命。不过要注意,nopreempt要求主备节点的state都别设成BACKUP,两边都设BACKUP再配合优先级才能生效。我这里的写法是MASTER+BACKUP配nopreempt,实测也能用,但严格来说更标准的nopreempt用法是两个节点都设BACKUP。这个细节不同版本行为有差异,我建议你在测试环境先验证一遍再上生产。
TCP_CHECK是健康检查的关键。 keepalived自带的检查方式就这么几种,TCP_CHECK最实用。它每隔一个周期去连一下RealServer的80端口,连不通就自动把这个RealServer从LVS的转发列表里摘掉。等恢复了又自动加回来。这个机制保证了后端挂了不会影响用户体验。
备节点的配置基本一样,只需要把state改成BACKUP,priority改成90,router_id改了就行。
5.3 最容易漏掉的一个细节:防火墙放行VRRP
这个坑我栽过一次之后记忆特别深刻。keepalived主备节点之间靠VRRP通告通信,VRRP报文是走IP协议号112的,不是TCP也不是UDP。如果你在服务器上开了firewalld或者iptables,默认策略是DROP,那么VRRP报文会被直接丢弃。现象就是主备节点互相不知道对方死活,VIP一直绑定在主节点上,主节点真挂了备节点也不接管,整个入口直接瘫痪。
解决方法是确保在防火墙里放行VRRP:
bash复制firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
firewall-cmd --reload
如果是iptables,对应规则是:
bash复制iptables -A INPUT -p vrrp -j ACCEPT
这个配置在部署时就要加上,我在下面完整部署流程里也会再强调一遍。
6. 一次完整的部署实录:从内核模块到RealServer配置
现在到了整篇文章最有操作价值的部分。我按实际部署的顺序,把手上的完整流程走一遍。假设环境如下:
- LVS主节点:192.168.1.10
- LVS备节点:192.168.1.20
- 业务虚拟IP(VIP):192.168.1.200
- RealServer A:192.168.1.11,运行Nginx,端口80
- RealServer B:192.168.1.12,运行Nginx,端口80
6.1 检查IPVS内核模块
LVS的核心功能在Linux内核里,首先得确认当前内核加载了IPVS相关模块:
bash复制modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_lc
modprobe ip_vs_wlc
modprobe ip_vs_sh
modprobe ip_vs_sed
modprobe ip_vs_nq
加载完成后用lsmod确认:
bash复制lsmod | grep ip_vs
正常会看到ip_vs_wlc、ip_vs_wrr、ip_vs_rr这些模块,说明内核支持对应的调度算法。这里要提醒一句:很多教程只让你modprobe ip_vs,结果你用ipvsadm配置wrr算法时报错找不到算法。就是因为对应模块没加载。为了省事,我建议把上面一长串全部执行一遍,反正没有副作用。
如果你想让系统开机自动加载这些模块,可以这么干:
bash复制echo "ip_vs" >> /etc/modules-load.d/lvs.conf
echo "ip_vs_wrr" >> /etc/modules-load.d/lvs.conf
6.2 安装ipvsadm和keepalived
ipvsadm是LVS的用户态管理工具,所有转发规则的增删改查都靠它。
CentOS/RHEL系:
bash复制yum install -y ipvsadm keepalived
Ubuntu/Debian系:
bash复制apt install -y ipvsadm keepalived
装完之后先看一眼版本,确认没问题:
bash复制ipvsadm -v
keepalived -v
6.3 配置LVS转发规则
DR模式下,LVS节点本身不需要开启IP转发,因为LVS只是做了MAC层的改写,不涉及路由转发。但为了保险起见,我一般会顺手开上:
bash复制echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
用ipvsadm创建VIP的转发规则:
bash复制ipvsadm -A -t 192.168.1.200:80 -s wrr
-A是添加一个虚拟服务,-t指定TCP协议,VIP和端口,-s指定调度算法为wrr。
然后添加两台RealServer:
bash复制ipvsadm -a -t 192.168.1.200:80 -r 192.168.1.11:80 -g -w 5
ipvsadm -a -t 192.168.1.200:80 -r 192.168.1.12:80 -g -w 5
-a是添加RealServer到已有的虚拟服务,-r指定RealServer地址和端口,-g表示使用DR模式(-m是NAT模式,-i是TUN模式),-w设置权重5。
查看当前规则:
bash复制ipvsadm -L -n
IP Virtual Server version 1.2.1
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.1.200:80 wrr
-> 192.168.1.11:80 Route 5 0 0
-> 192.168.1.12:80 Route 5 0 0
看到Forward列是Route,说明DR模式配置成功。
规则配好了是临时的,LVS重启或服务器重启就丢了。需要保存规则,让ipvsadm服务开机自动恢复:
bash复制ipvsadm-save > /etc/sysconfig/ipvsadm
systemctl enable ipvsadm
systemctl start ipvsadm
6.4 RealServer端的两处关键配置
DR模式里,RealServer的配置是决定成败的关键。很多第一次部署LVS的人在这里翻车,现象就是VIP配好了、规则也建了,但流量就是不通。
第一步,在RealServer的lo接口上绑定VIP。为什么绑定到lo而不是eth0?因为如果不绑定,RealServer收到目标IP为VIP的数据包,发现这个IP不是本机IP,会直接丢弃,根本不会做任何处理。绑定在lo接口上,RealServer才会认领这个VIP。注意子网掩码必须是255.255.255.255,也就是32位掩码。这里不能按传统网段的思路配成24位掩码,否则VIP的ARP广播会发送到整个二层网络,造成IP地址冲突。
bash复制ifconfig lo:0 192.168.1.200 netmask 255.255.255.255 up
为了持久化,把这条命令写进/etc/rc.local,或者用systemd service管理。我偏爱后者,更规范:
bash复制cat > /etc/systemd/system/lvs-vip.service <<'EOF'
[Unit]
Description=LVS VIP on loopback
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/sbin/ifconfig lo:0 192.168.1.200 netmask 255.255.255.255 up
ExecStop=/sbin/ifconfig lo:0 192.168.1.200 down
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable lvs-vip
systemctl start lvs-vip
第二步,抑制ARP响应。这一步的目的是防止RealServer对外声明“我有这个VIP的IP”。如果不抑制,当外部设备(比如交换机、客户端)广播ARP查询VIP对应的MAC地址时,LVS节点和RealServer都会响应,交换机就会把流量错误地转发给RealServer,LVS就形同虚设了。
在RealServer上修改sysctl配置:
bash复制cat >> /etc/sysctl.conf <<'EOF'
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
EOF
sysctl -p
这两个参数的含义:
- arp_ignore设置为1:只回答目标IP是本地IP地址(且该IP在接收ARP请求的网卡上)的ARP请求。这样RealServer的lo接口上虽然有VIP,但当ARP请求从eth0进来时,RealServer不会用lo上的VIP去响应。
- arp_announce设置为2:发送ARP通告时,使用能够路由到目标的最佳本地IP地址作为源地址,而不是盲目使用所有网卡上配置的IP。
这两行配置是DR模式能正常工作的基石。
6.5 验证四层转发是否生效
在LVS节点上查看连接分发情况:
bash复制watch -n 1 'ipvsadm -L -n -c'
这条命令会实时刷新当前连接表。发起测试请求,比如从外部客户端访问http://192.168.1.200/,然后观察连接表,能看到连接被分发到哪台RealServer。
更直观的验证方法是看后端的访问日志。两台RealServer的Nginx访问日志里都会出现来自客户端IP的访问记录,说明LVS的转发确实在生效。
7. 性能调优的几个方向:从hash表到软中断
LVS部署完能用,和大流量下稳得住,中间还隔着一层非常关键的调优工作。这里的调优不是玄学,每一项都有明确的原理和对应的参数。
7.1 IPVS连接hash表的大小
LVS内核里维护着一张连接跟踪表,用来记录当前所有的TCP连接状态。这张表是hash结构的,初始大小由编译内核时确定,但可以通过ipvsadm运行时调整。
查看当前hash表大小:
bash复制ipvsadm --show-sets
如果连接数很高,hash表太小会导致hash冲突变多,CPU占用上升,转发性能下降。我建议在流量较大时主动扩大:
bash复制ipvsadm --set 1048576 2097152 1048576
三个参数依次是tcp tcpfin udp的hash表大小。这个值要根据业务实际并发估算,我自己的经验是,单机峰值20万并发连接时,配1M大小的hash表比较稳妥。
7.2 连接跟踪的坑
这里需要注意,ipvsadm的连接表和Linux内核的conntrack(连接跟踪)是两回事。LVS工作在四层,可以在一定程度上绕过conntrack,但如果系统里同时跑着iptables规则,conntrack就会被强制启用,每个连接都要跟踪状态,会在高并发时成为瓶颈。
我遇到过的情况是:LVS节点上同时有iptables NAT规则,导致nf_conntrack表被撑爆,系统日志里疯狂刷“nf_conntrack: table full, dropping packet”。解决思路很明确,一是检查是否真的需要这些iptables规则,二是调整conntrack的最大值和超时时间:
bash复制echo 1048576 > /sys/module/nf_conntrack/parameters/hashsize
sysctl -w net.netfilter.nf_conntrack_max=1048576
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=600
把优化写入/etc/sysctl.conf持久化,别只在命令行改了完事。
7.3 TCP层参数调优
LVS承接的都是海量短连接,TIME_WAIT状态会非常多。如果TIME_WAIT连接堆积过多,端口资源会被耗尽。对于LVS这种转发节点,可以开启TIME_WAIT复用:
bash复制sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_fin_timeout=30
注意:tcp_tw_reuse只对主动发起连接的一方有效,LVS在转发模式下本身不维持很多TIME_WAIT,但在NAT模式下这个参数非常有用。另外,如果你的内核版本较新,tcp_tw_recycle这个参数已经被移除了,别再去搜旧文档找它,没有意义。
7.4 网卡软中断和RSS多队列
流量大到一定程度,你会发现CPU使用率可能只有一个核跑满,其他核很闲。这是网卡中断都打到了同一个CPU上导致的。现代网卡都支持RSS(Receive Side Scaling)多队列,让不同队列的中断分散到不同CPU核心。
检查网卡是否启用了多队列:
bash复制lspci -vvv | grep -A 10 Ethernet
或者看中断号分布:
bash复制cat /proc/interrupts | grep eth0
如果你的网卡驱动支持,可以调整队列数量和CPU亲和性。这个操作比较复杂,不同网卡驱动方法不一样,但只要不是单核瓶颈特别明显,我一般不会优先动它,先排查hash表大小和conntrack,这两个才是最常见的性能杀手。
8. 排错手记:生产环境遇到的那些经典故障
最后这部分,我把这些年实际遇到过的LVS故障整理出来。每个问题都是我或我的同事真实踩过的坑,排查思路也值得完整复述一遍,因为下次你遇到类似问题,照着这个思路走能省太多时间。
8.1 VIP ping不通,但配置看起来一切正常
现象:配置全部完成,LVS节点和RealServer节点上都能看到VIP,但外部ping 192.168.1.200完全不通。
排查链路:
第一步,确认LVS节点的VIP是否绑定成功:
bash复制ip addr show eth0
第二步,确认RealServer的ARP抑制配置有没有生效:
bash复制cat /proc/sys/net/ipv4/conf/all/arp_ignore
cat /proc/sys/net/ipv4/conf/all/arp_announce
如果输出不是1和2,说明配置有问题,重新检查sysctl.conf里有没有写对,有没有执行sysctl -p。
第三步,也是最容易被忽略的:在LVS节点上抓包看ARP响应的情况。
bash复制tcpdump -nn -i eth0 arp
如果外部发ARP请求VIP,LVS节点应响应,而RealServer不应响应。如果RealServer也在响应,说明ARP抑制没配好。
根因:绝大多数情况下是RealServer的ARP抑制配置没生效,或者RealServer上有个进程自己绑定了VIP且没有抑制ARP,导致交换机把VIP的流量转发给了RealServer。
8.2 主备切换毫无反应
现象:手动把主节点keepalived停掉,备节点没有任何动作,VIP没有漂移。
排查链路:
第一步,查看备节点的keepalived日志:
bash复制journalctl -u keepalived -f
日志一直不输出任何VRRP相关的信息,还是说一直在刷“received an invalid passwd”?
如果一直刷“invalid passwd”,说明主备节点的VRRP认证密码不一致,检查两边的auth_pass是不是一样。
如果日志正常但没有切换动作,重点检查防火墙,这个我前面说过:
bash复制iptables -L -n | grep vrrp
firewall-cmd --list-rich-rules
如果防火墙上根本没有放行VRRP的规则,那主备节点之间压根无法通信。主节点个备节点各活各的,都认为自己是光杆司令——不对,准确说是备节点收不到主节点的通告,会主动抢占VIP,导致两个节点同时持有VIP,引发IP冲突。这种情况下业务表现是时而通时而不通,非常诡异。
根因:大多数情况就是防火墙没放行VRRP。加上规则之后,主备切换恢复正常。
8.3 后端RealServer频繁被摘除又恢复
现象:ipvsadm -L -n里能看到某台RealServer的ActiveConn经常清零,查看keepalived日志发现它在不停添加、删除这台RealServer。
排查链路:
第一步,确认RealServer的应用端口确实正常:
bash复制curl -I http://192.168.1.11:80
第二步,在LVS节点上手动telnet一下RealServer的端口,看看连接速度和延迟:
bash复制time nc -zv 192.168.1.11 80
如果连接经常超时1秒以上,大概率是RealServer的负载太高,TCP握手队列满,keepalived的健康检查请求超时,判定RealServer挂了,于是摘除。过一会儿请求不多了,又恢复了连接,又加回来。
根因:RealServer的处理能力到了瓶颈,或者应用有间歇性卡顿,比如GC停顿、数据库慢查询。这时候不要先怀疑keepalived配置,要去看RealServer的系统负载和应用日志。
这类问题还有个变种:如果keepalived配的是HTTP_GET检查,后端应用对健康检查的URL返回5xx,也会频繁摘除。我用TCP_CHECK就是因为这个坑,只要端口能连上就认为是健康的,简单粗暴但极少误杀。
8.4 后端收到请求,但客户端响应超时
现象:LVS转发正常,RealServer的访问日志显示请求进来了,处理也很快,但客户端就是等不到响应。
排查链路:
这个现象基本可以确定是响应包没有正确处理。DR模式下,RealServer直接回包给客户端,对方看到的源IP是VIP。如果RealServer的默认路由有问题,比如无法把源IP为VIP的包路由回客户端,响应就丢了。
根因:RealServer上没有正确配置到客户端的路由,或者RealServer的默认路由指向了LVS节点,导致回包再次绕回LVS,而LVS不认识这个连接,直接丢弃。
说到底,DR模式下的RealServer必须能独立与客户端通信,网关上不能有任何关于VIP的过滤规则,同时路由要保证回包能到达客户端。这也是为什么我之前强调,DR模式下LVS和RealServer最好在同一个广播域内,网络环境越简单越不容易出这种问题。
结尾再补一个我在实践中养成的习惯
LVS这套体系,说复杂也复杂,说简单也简单,核心就是那几个机制。但真正考验人的地方,往往不在配置本身,而是出了故障之后能不能快速定位到是ARP的问题、路由的问题、还是防火墙的问题。
我自己现在部署LVS有个习惯:每做完一套环境,就手动模拟一次故障。停掉主节点的keepalived,看备节点是否在3秒内接管VIP;拉起备节点上的keepalived,看nopreempt是否生效;手动down掉一台RealServer的Nginx,看keepalived是否把它从转发列表摘除。这些演练各花几分钟,但能提前暴露掉90%以上的配置错误。
希望这篇内容能帮你把LVS的底层逻辑和实战细节串起来。这套东西不新,但它依旧是现代互联网高并发架构里最坚实的一块基石,值得花时间吃透。
