LVS DR模式与Keepalived高可用实战:核心原理、配置排错与实验验证
写这篇博文之前先聊个我经常在社区里看到的现象不少做运维的朋友一提到四层负载均衡第一反应就是Nginx或者HaProxy。Nginx做七层转发确实顺手但你要是后端是海量动态请求、服务器规模动辄几十台四层入口用Nginx硬顶连接数和CPU很快就成了瓶颈。LVS在这个场景下依然是绕不开的经典方案而LVS的DR模式配合keepalived做VIP高可用又是其中最有实战价值的组合之一。这篇文章不打算只贴配置我会把DR模式的数据流原理、ARP抑制的底层逻辑、keepalived的高可用切换机制全部拆开讲再带你把实验从头到尾做一遍适合有一定Linux基础、想真正搞懂LVS而不是只会抄命令的朋友。1. 为什么DR模式是生产环境的首选从数据流路径拆解核心原理1.1 一条请求在DR模式下的完整旅程LVS有三种工作模式NAT、DR、TUN。DR模式之所以被生产环境大量采用根本原因在于它把“转发”二字做到了极致轻量。我们假设客户端IP为CIPVIP是192.168.100.100两台后端Real ServerRS分别是192.168.100.20和192.168.100.30调度器Director是192.168.100.10。请求从客户端发出后数据包的源IP是CIP目标IP是VIP目标MAC是以太网帧头里的目的MAC。这个MAC是谁的正常情况下是VIP所在主机的MAC也就是当前Master Director的MAC。Director收到这个包之后不会修改源IP和目标IP而是根据调度算法从RS列表里挑一台比如挑中192.168.100.20然后把以太网帧头里的目标MAC改成192.168.100.20的MAC再通过二层交换机把帧转发出去。重点来了RS收到这个包之后它会发现目标IP 192.168.100.100 正好配在自己本机的lo:0接口上所以内核会正常收包交由用户态的HTTP服务处理。处理完成后RS生成响应包源IP是VIP目标IP是CIP直接通过自己的物理网卡发给客户端完全不经过Director。这个过程用一句话概括请求经过Director响应不经过Director。Director在这里只干了一件事——改写目标MAC所以它可以轻轻松松扛住极高的并发而这正是NAT模式做不到的。1.2 和NAT模式对比一张表看清本质差异很多新手一开始都分不清NAT和DR到底差在哪我直接给个对比表对比项NAT模式DR模式Director改写的对象源IP和目标IP只有目标MAC响应包是否经过Director必须经过不经过Director性能瓶颈响应包流量大时明显远小于请求流量瓶颈不明显后端RS是否要绑VIP不需要需要且要配在lo上并抑制ARPRS与Director网络要求可以跨网段必须同一网段二层可达RS操作系统要求通用需允许修改内核ARP参数端口复用能力支持支持从这个表能看出来DR模式不是没有代价的。它把一部分复杂度转移到了RS上RS必须绑定VIP同时又必须“闭嘴”不对外广播这个VIP否则整个网络就乱了。而这个“闭嘴”的操作恰恰是后面实验里最容易出错的地方。1.3 一台机器只能有一个IPVIP为什么能同时出现在多台机器上这里先解决一个认知问题很多人觉得VIP只能配置在一台机器上否则会冲突。其实IP地址绑定在网卡上多台机器完全可以在逻辑上拥有同一个IP关键在于谁能“应答”这个IP的ARP请求。在LVS DR架构里存在两个层面对客户端和交换机来说VIP在同一时刻只应该有一个活跃应答者也就是当前Master Director它通过VRRP协议保证“一主一备”。对RS来说VIP只是静静躺在lo:0别名接口上的一个逻辑地址RS只用它来接收目标IP为VIP的请求包不主动对外宣告所以不会造成冲突。理解了这个“绑定但不广播”的机制你再看后面的ARP配置就不会晕。2. keepalived在这里到底干了什么高可用远不是“抢个IP”那么简单2.1 VRRP的“抢班”机制keepalived的核心作用有两个一是通过VRRP协议实现Director节点的高可用二是对后端RS做健康检查并动态维护LVS规则。很多人只盯着第一点忽略了第二点实际上第二点在故障自愈里同样关键。先看VRRP。所有keepalived节点只要虚拟路由器ID一致就属于同一个VRRP实例。Master节点默认每1秒由advert_int控制向组播地址224.0.0.18发送一次VRRP通告报文我干活呢你们都别动。Backup节点收到Master的通告后会持续保持静止状态。一旦Master宕机、网卡故障或者keepalived进程退出Backup超过3到5个通告周期没收到组播就会判定Master失效然后晋升为新Master为本机配置VIP同时发送一组免费ARP报文用来刷新交换机的ARP缓存表让后续发往VIP的数据帧都被送到新Master的MAC地址上。这个“超时—晋升—刷新ARP”的过程就是VIP漂移的本质。2.2 MASTER挂了再恢复VIP会不会回来这个问题我见过太多人搞错。keepalived默认开启了抢占模式也就是说当原来的Master恢复后会重新夺回VIP哪怕Backup当时工作得好好的。这在某些场景下会导致连接闪断因为VIP MAC地址又切了一次。那怎么避免来回抢把两个节点的state都设置为BACKUP然后在配置里加上nopreempt同时依靠priority来区分谁是实际主节点。我实验环境里习惯直接用MASTER/BACKUP加默认抢占方便观察漂移过程但真实生产环境如果对抖动敏感建议认真考虑双BACKUP加nopreempt的方案。有一点必须牢记VRRP的priority取值范围是1到254数字越大优先级越高。很多时候你配置了半天VIP不漂移先把两个节点的priority和virtual_router_id检查一遍再说。2.3 keepalived的另一半职责对后端RS做实时健康检查keepalived不是普通的高可用软件它本身就是为LVS量身定做的所以在keepalived.conf里可以直接定义virtual_server和real_server它会在启动时自动调用ipvsadm帮你把LVS规则配好。真正有价值的是健康检查机制。例如我们常用TCP_CHECKkeepalived会定期向后端RS的80端口发起TCP连接如果探测失败连续超过重试次数这条RS会被自动从内核的LVS规则列表中摘除后续请求不会被调度到这台故障机等探测恢复成功后它又会自动加回来。整个摘除和恢复过程都可以通过ipvsadm -L -n实时看到不需要人工干预。理论部分先说到这下面进入实验环节。3. 实验环境与拓扑设计IP规划是排错的第一依据3.1 部署拓扑全貌实验环境我建议用虚拟机模拟五台机器两台Director做高可用两台RS跑HTTP服务一个客户端用来验证。节点IP规划如下节点角色IP地址服务Director-Master主调度器192.168.100.10keepalived ipvsadmDirector-Backup备用调度器192.168.100.11keepalived ipvsadmRS1后端Web服务器192.168.100.20Nginx 或 httpdRS2后端Web服务器192.168.100.30Nginx 或 httpdClient测试终端192.168.100.50curl / arpingVIP虚拟业务地址192.168.100.100由主Director持有所有节点都在192.168.100.0/24这个网段内保证二层互通这是DR模式的前提条件。3.2 环境版本与软件准备操作系统我用的是CentOS 7.9内核3.10版本对应的keepalived和ipvsadm通过yum安装即可yum install -y keepalived ipvsadm httpd如果你习惯Ubuntu也可以只是网卡名变成了ens33之外的命名配置文件里的interface字段要对应改。后端Web服务用httpd或者Nginx都行关键是让RS1和RS2的首页内容不一样比如RS1返回“RS1-Node”RS2返回“RS2-Node”这样验证负载均衡效果时一眼就能分辨出到底是哪台RS在响应。3.3 实验前先把“环境脏东西”清干净下面这几步看起来基础但漏掉任何一个都可能导致你实验做到一半想砸键盘关闭firewalld或者至少放行80端口和VRRP协议报文协议号为112。我实验时直接关闭省心。关闭SELinux或者保证httpd上下文正确。建议直接setenforce 0。检查每台机器的时间同步。VRRP本身对绝对时间不敏感但日志排查依赖时间线一致配个chrony或ntp更省事。统一关闭NetworkManager干扰CentOS 7里如果你用的是systemd-networkd或者NetworkManager有时会影响VIP绑定建议用传统network服务。准备工作做完先从后端RS开始。4. 后端RS的ARP抑制配置实验失败的根源几乎都在这里4.1 如果不抑制ARP会发生什么我先描述一个典型翻车现场RS上配好lo:0的VIP客户端访问VIP发现有的请求正常有的请求直接超时再一看ARP缓存VIP对应的MAC竟然在Director和RS之间跳来跳去。这个现象就是RS“抢答”造成的。当网关或客户端发出ARP广播“谁是192.168.100.100”时因为RS的lo:0上确实绑着这个IP默认内核行为下它会回应。一旦客户端把数据帧发给RS而RS根本不是调度器那请求就永远进不了LVS调度池整个负载均衡直接失效。所以RS必须做两件事装傻和闭嘴。装傻就是禁止对VIP的ARP请求应答闭嘴就是避免使用VIP做ARP通告的源地址。4.2 arp_ignore和arp_announce到底怎么填在RS上新建配置文件vi /etc/sysctl.d/lvs-rs.conf写入以下内容net.ipv4.conf.all.arp_ignore 1 net.ipv4.conf.all.arp_announce 1 net.ipv4.conf.default.arp_ignore 1 net.ipv4.conf.default.arp_announce 1 net.ipv4.conf.lo.arp_ignore 1 net.ipv4.conf.lo.arp_announce 1别急着加载我们先明白这几个值的意思。arp_ignore控制的是“收到ARP请求后要不要回”。0只要目标IP是本机任意IP就回。1只有当目标IP恰好等于收到请求的那个接口自己的IP时才回。因为我们把VIP绑在lo:0上而ARP请求通常是从物理网卡ens33收到的物理网卡自己的IP是192.168.100.20不等于VIP所以RS不会回应关于VIP的ARP请求。这就实现了装傻。arp_announce控制的是“对外发送ARP通告时源IP怎么挑”。0随便用哪个本机IP都行。1尽量选择到达目标地址的出接口IP如果目标不在本接口网段则可以用其他IP。2必须使用与目标地址同一网段的最佳本机IP。配置为1基本够用更严格可以设成2。我实验环境用1安全性足够。加载配置并验证sysctl -p /etc/sysctl.d/lvs-rs.conf cat /proc/sys/net/ipv4/conf/lo/arp_ignore输出为1即生效。这里有一个很容易被忽略的细节仅配all和lo这两个作用域其实不完全够因为有些系统行为会读取具体物理网卡的参数。所以稳妥起见把ens33也一起配了net.ipv4.conf.ens33.arp_ignore 1 net.ipv4.conf.ens33.arp_announce 1不知道网卡名的用ip addr查别照抄。4.3 绑定VIP到lo:0的两个硬性细节先在RS1和RS2上分别绑定VIPifconfig lo:0 192.168.100.100 netmask 255.255.255.255 up route add -host 192.168.100.100 dev lo:0这里有两个雷点。第一掩码必须是32位也就是255.255.255.255。如果你图省事写成255.255.255.0VIP会带一个完整的网段路由内核可能把本网段的包也路由到lo上出现各种奇怪的路由回环问题。第二加上route add -host这条静态主机路由是为了确保本机收到目标IP为VIP的包后能通过lo接口正确接收而响应包源地址也就能顺理成章地取到VIP。少了这一步某些内核条件下回包可能异常。两台RS操作完成后用ip addr命令确认RS的lo上能看到VIP但不要急着测试连通性因为真正应答VIP ARP的是Director这时候Director还没配置。4.4 如何验证ARP抑制是否真的生效验证方法很简单在RS3也就是Client机器上执行arping -I eth0 192.168.100.100 -c 3在Director keepalived还没启动的情况下这个命令应该收不到任何回应因为VIP没人应答。如果这时RS响应了arping说明你的ARP配置有问题回到上一步检查。等后面Director配置完成后再执行arping应该能收到来自Director的MAC地址回应这就是正常状态。5. Director上的keepalived完整配置从vrrp_instance到virtual_server5.1 主Director的keepalived.conf主Director上编辑/etc/keepalived/keepalived.conf直接给完整配置vim /etc/keepalived/keepalived.conf! Configuration File for keepalived global_defs { router_id LVS_MASTER enable_script_security } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.100.100/24 dev ens33 label ens33:0 } } virtual_server 192.168.100.100 80 { delay_loop 6 lb_algo rr lb_kind DR persistence_timeout 0 protocol TCP real_server 192.168.100.20 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 2 connect_port 80 } } real_server 192.168.100.30 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 2 connect_port 80 } } }这段配置分两大块vrrp_instance管高可用virtual_server管负载均衡。在vrrp_instance里interface指定VIP绑定到哪个物理网卡virtual_router_id就是前面说的VRRP实例ID两台Director必须一致。priority是竞选权重Master为100Backup设为90。在virtual_server里lb_kind DR表示使用DR模式lb_algo rr表示轮询算法persistence_timeout 0表示不启用连接持久化这样每次请求都会轮询。TCP_CHECK是健康检查配置每隔几秒探测RS的80端口失败则摘除。5.2 备用Director的配置差异把/etc/keepalived/keepalived.conf复制到Backup节点后只需要改三个地方router_id改为LVS_BACKUP。state改为BACKUP。priority改为90。其余保持完全一致尤其是virtual_router_id、auth_pass、VIP、virtual_server块任何一处不一致都可能导致脑裂或规则不同步。5.3 启动顺序与首次校验在Backup和Master上都执行systemctl enable --now keepalived先看Masterip addr show ens33:0正常情况下Master的ens33:0上应该出现192.168.100.100。Backup上这条命令应该没有输出因为VIP只在Master存活时存在于Master上。再看LVS规则ipvsadm -L -n如果看到类似下面的输出说明规则已经由keepalived自动创建IP Virtual Server version 1.2.1 (size4096) Prot LocalAddress:Port Scheduler Flags - RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.100.100:80 rr - 192.168.100.20:80 Route 1 0 0 - 192.168.100.30:80 Route 1 0 0注意Forward列显示Route这就是DR模式。5.4 如果发现规则没自动生成先查三件事第一件事看keepalived日志journalctl -u keepalived -f第二件事确认VRRP组播没有被防火墙拦截。keepalived的VRRP报文走协议号112的组播224.0.0.18很多环境firewalld默认会拦实验环境直接关闭最省事。第三件事确认keepalived版本和配置文件语法没有低级错误。用keepalived -t可以测试配置语法。配置完成后在Client上执行arping -I eth0 192.168.100.100 -c 3这时如果收到Master Director的MAC回应说明整个链路已经通了一半。6. 实验验证与高可用切换实测从curl结果到VRRP抓包6.1 验证负载均衡效果让每个RS亮明身份为了直观我在RS1的默认首页写入一行“This is RS1”RS2写入“This is RS2”。然后客户端连续请求VIPfor i in $(seq 1 6); do curl -s http://192.168.100.100/; echo; done因为调度算法是rr预期输出应该是RS1和RS2交替出现This is RS1 This is RS2 This is RS1 This is RS2 This is RS1 This is RS2如果连续多次都返回同一个RS优先检查persistence_timeout是不是没有设成0或者客户端带有保持连接的参数导致连接复用。6.2 RS故障摘除停掉Web服务后发生了什么模拟RS1宕机在RS1上执行systemctl stop httpdkeepalived的TCP_CHECK会探测到RS1的80端口不再响应经过delay_loop 6秒加上重试时间通常在几十秒内内核LVS规则中RS1会被摘掉。在Master上观察ipvsadm -L -n这时输出了只有RS2curl VIP也只会返回“This is RS2”。再把RS1的httpd恢复systemctl start httpd大概过一轮检查周期RS1会自动回到列表里。整个过程中不需要人工干预这就是keepalived相比单纯脚本巡检的最大价值。6.3 Director主备切换keepalived进程被杀之后在Master上执行systemctl stop keepalived然后去Backup上执行ip addr show ens33:0正常情况下约3到5秒后Backup上会出现192.168.100.100。Client继续curl VIP依然成功只是响应可能有一两秒中断这是VRRP切换的正常现象。此时已经漂移到Backup再用ipvsadm -L -n查看规则也自动出现在Backup上。再把Master的keepalived启动回来systemctl start keepalived大概3秒后Master重新夺回VIPBackup自动释放。这个行为就是前面说的抢占模式。如果你希望生产环境里尽量少做这种来回切换把两台Director都设成BACKUP在优先级高的那台上加nopreempt这样一来即使原主恢复VIP也不会抢回来直到下一次故障再切换。6.4 抓包看VRRP通告和免费ARP想在“上帝视角”看整个过程在Master或Backup上执行tcpdump -i ens33 vrrp -nn正常情况下每秒能看到一次VRRP组播报文。执行Master故障切换时你会看到Backup突然开始发VRRP通告紧接着发送ARP通告宣告自己对VIP的持有权。两台机器同时执行tcpdump对比你能直观看到组播报文的发送方从Master的IP变为Backup的IP这个体验比看日志直观得多。7. 我在实验中踩过的坑和最终调优建议7.1 RS上开了反向路径过滤VIP访问时通时断这是我的一个真实翻车现场。实验做到一半客户端curl VIP有时成功有时超时ping却正常。后来定位到是RS上开启了rp_filter也就是反向路径过滤。rp_filter的作用是检查收到的数据包的源IP如果按源IP查路由表最佳出接口不是收到这个包的接口就判定为非法丢包。在DR模式下客户端发来的包虽然目标是RS的VIP但实际到达接口是ens33源IP是CIP如果客户端网段不在ens33路由范围内就可能被RS丢弃。解决办法是在RS上调整sysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.ens33.rp_filter0生产环境建议设成2也就是宽松模式只对确实能确定接口错误的情况做校验这比直接关闭更稳妥。7.2 VIP放在哪块网卡上有讲究这是另一个经典误区。Director上的VIP通过keepalived的virtual_ipaddress配置指定dev ens33所以它出现在物理网卡上没问题。但RS上的VIP绝对不能放在物理网卡上必须放lo:0。原因在于如果VIP放在RS的eth0上且掩码不是32位那么RS在向外发送数据时可能把VIP当作源地址做路由通告干扰网络内的ARP应答导致整个DR链路出现不可预测的行为。只有把VIP藏在lo:0这个本地回环接口上配合ARP抑制才能真正实现“我自己用我不告诉别人”的效果。7.3 调度算法选型什么时候抛弃rr实验环境用rr轮询足够但生产环境请按实际情况选择rr所有RS配置和能力完全一样时使用。wrr后端配置异构需要按权重分配。lc / wlc后端连接耗时差异明显或者请求保持时间较长希望在连接数少的一方优先分配时使用。LVS本身支持的算法很多但生产上用最多的就是rr、wrr和wlc别一上来就追求冷门算法。7.4 persistence_timeout的取舍我在实验里特意保持persistence_timeout 0是为了让rr轮询效果清晰可见。如果生产环境需要会话保持比如用户登录状态不能频繁跳动有几种做法在LVS层设置persistence_timeout让同一来源IP在超时时间内固定调度到同一RS。使用SH算法通过源IP哈希实现一致性分配。更推荐的做法在RS的应用层做会话共享比如Redis集中存储Session这样即使RS切换也不影响用户体验。7.5 线上巡检建议最后聊下平时怎么养监控习惯。我会在Master上挂一个定时脚本每隔一段时间执行watch -n 5 ipvsadm -L --stats -n重点关注ActiveConn和InActConn的平衡度如果某台RS的ActiveConn异常高就去检查是不是健康检查摘除过它导致连接重新分配。另外记得巡检Backup节点上不应该出现VIP一旦出现说明发生过脑裂或配置不一致。最后再分享一个我平时验证一台新交付负载均衡环境的“仪式感动作”先ping通VIP再抓包做一次主备切换然后看着免费ARP广播从新Master发出整个过程比看任何日志都直观。这套实验做下来你对DR模式和keepalived的理解会比看十篇文档都深后面再遇到线上问题排查思路也清晰得多。