资讯动态

Keepalived热备、LVS与HAproxy高可用架构选型与实战

发布时间:2026/10/13 5:49:24 来源:尧图企业网站定制
1. 从单点故障说起为什么高可用架构不是可选项很多团队在项目初期都经历过这样的阶段一台服务器扛下所有流量跑得好好的直到某天凌晨磁盘满了、进程崩了、机房网络抖了一下业务直接归零。这种“单点故障”带来的痛只有真正被电话叫醒过的人才能体会。高可用High Availability简称HA要解决的核心问题只有一个当某个节点不可用时服务能自动切换到备用节点让用户几乎无感知。围绕这个目标业界沉淀出了几条主流技术路线。标题里提到的三个关键词——Keepalived热备、KeepalivedLVS、HAproxy服务器——其实代表了三种不同层次、不同侧重点的高可用方案。它们不是互相替代的关系而是经常组合使用分别解决“谁来做主”“流量怎么分发”“请求怎么转发”这三个问题。Keepalived热备解决的是节点级冗余两台机器一主一备主挂了备顶上靠的是VRRP协议和虚拟IP漂移。KeepalivedLVS解决的是四层负载均衡下的高可用LVS负责把流量分给后端真实服务器Keepalived负责让LVS调度器本身不成为单点。HAproxy则工作在七层能基于HTTP头部、URL、Cookie做更精细的转发和健康检查同样可以用Keepalived做高可用。这篇文章适合谁看如果你正在搭建一套需要7×24小时稳定运行的服务或者你已经在用Nginx做反向代理但发现它扛不住某些场景又或者你只是想把“高可用”这三个字从概念变成能落地的配置那接下来的内容会一步步把原理、选型、配置和踩坑经验讲清楚。我会尽量用生活化的类比解释协议细节同时给出可以直接抄的配置片段和排查命令。2. Keepalived热备VRRP协议与虚拟IP漂移的底层逻辑2.1 VRRP到底在干什么一个“虚拟路由器”的选举游戏Keepalived的核心是VRRPVirtual Router Redundancy Protocol虚拟路由器冗余协议。你可以把它想象成一个小区里只有一部对外公开的“总机号码”但背后其实有两部电话机。平时由主电话机接听主电话机坏了备用电话机立刻接管这个号码外面打电话的人根本不知道换了机器。这个“总机号码”就是虚拟IPVIP。VRRP把一组服务器组成一个虚拟路由器这个虚拟路由器有一个VIP和一个虚拟MAC地址。组内的服务器通过优先级priority选举出MasterMaster持有VIP并响应ARP请求Backup则处于监听状态。Master定期发送VRRP通告报文默认1秒一次Backup如果在3倍通告间隔内没收到通告就认为Master挂了触发新一轮选举。这里有几个关键参数必须理解透virtual_router_id同一个VRRP组内必须一致不同组必须不同范围1-255。如果两台不相关的Keepalived配了相同的router_id且在同一网段会互相抢VIP这是新手最容易踩的坑之一。priority优先级数值越大越优先范围1-254。Master通常配100以上Backup配100以下。注意255是保留给IP地址拥有者的。advert_int通告间隔默认1秒。调小能加快故障检测但会增加网络开销调大则相反。state初始状态MASTER或BACKUP。但实际角色由优先级和选举决定state只是启动时的初始声明。authentication认证方式推荐用PASS同一组内密码必须一致。2.2 抢占模式与非抢占模式什么时候该让Master“抢回来”Keepalived默认是抢占模式preempt当原来的Master恢复后如果它的优先级仍然最高它会重新抢回VIP。这在某些场景下是好事比如主节点性能更强但在另一些场景下是灾难比如主节点刚重启服务还没完全就绪就抢回流量导致请求失败。非抢占模式通过nopreempt参数开启但有个硬性条件初始state必须设为BACKUP且优先级可以比另一台高。这样即使高优先级节点恢复也不会主动抢回VIP直到当前Master主动释放。我个人的经验是数据库主库、有状态服务、启动慢的应用一律用非抢占无状态的前端服务可以用抢占让性能好的机器多扛流量。2.3 一个能直接用的Keepalived热备配置假设有两台服务器IP分别是192.168.1.10和192.168.1.11VIP是192.168.1.100。主节点配置# /etc/keepalived/keepalived.conf global_defs { router_id node_master enable_script_security script_user root } vrrp_script chk_nginx { script /usr/bin/killall -0 nginx interval 2 weight -20 fall 2 rise 2 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass MyPass123 } virtual_ipaddress { 192.168.1.100/24 dev eth0 label eth0:1 } track_script { chk_nginx } notify_master /etc/keepalived/notify.sh master notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }备节点只需改三处router_id改成 node_backupstate改成 BACKUPpriority改成 90。virtual_router_id、auth_pass、virtual_ipaddress必须完全一致。vrrp_script这段是精髓它每2秒检查一次nginx进程是否存在如果连续2次检查失败fall 2就把优先级减20weight -20。主节点优先级从100降到80低于备节点的90于是触发切换。这比单纯靠VRRP心跳检测更可靠因为有时候机器没宕机但服务已经挂了。注意killall -0 nginx只是检查进程是否存在不检查服务是否真正可用。更严谨的做法是用curl -sf http://127.0.0.1/health检查健康接口。2.4 脑裂最危险也最容易被忽视的问题脑裂split-brain是指两台节点都认为自己是Master同时持有VIP。结果就是VIP在两个MAC地址之间来回漂移或者ARP表混乱流量时通时断。造成脑裂的常见原因有三个心跳线断了但服务器还活着、防火墙拦截了VRRP组播、virtual_router_id冲突。排查脑裂的第一步是看日志journalctl -u keepalived -f或/var/log/messages。如果看到两台都在发“Entering MASTER STATE”基本可以确认。解决方案包括用独立的心跳线不要和业务网卡混用、在交换机上放行VRRP协议协议号112、配置unicast_peer指定单播心跳而不是依赖组播。我踩过最坑的一次是云环境里安全组默认拦截了组播Keepalived根本收不到对方通告两台都成了Master。后来改成单播模式才解决unicast_src_ip 192.168.1.10 unicast_peer { 192.168.1.11 }3. KeepalivedLVS四层负载均衡的高可用组合拳3.1 LVS的三种转发模式NAT、DR、TUN怎么选LVSLinux Virtual Server是内核级的四层负载均衡器性能极高因为它在内核空间处理数据包不需要把请求交给用户态进程。它有三种工作模式模式原理优点缺点适用场景NAT调度器改写目标IP请求和响应都经过调度器配置简单后端可跨网段调度器成为带宽瓶颈小规模、后端数量少DR直接路由调度器只改MAC地址响应由后端直接回给客户端性能最高调度器只处理入站后端必须和调度器同网段需配置VIP在lo上大多数生产环境首选TUN隧道用IP隧道封装请求转发给后端后端可跨机房需要支持隧道协议配置复杂跨地域分发生产环境里DR模式用得最多。它的巧妙之处在于调度器收到请求后只把目标MAC改成某台真实服务器的MACIP层完全不动。真实服务器收到包后发现目标IP是自己的VIP配置在lo接口上就处理请求然后直接把响应发给客户端不再经过调度器。这样调度器只承担入站流量出站流量由后端自己扛吞吐量大幅提升。3.2 为什么LVS需要Keepalived调度器本身不能是单点LVS再强如果只有一台调度器它挂了整个集群就没了。所以标准做法是两台LVS调度器 Keepalived做高可用。两台调度器组成VRRP组同时持有VIP只有Master对外服务。后端真实服务器通过ipvsadm配置在调度器上。这里有个细节后端服务器的VIP配置。在DR模式下每台真实服务器都需要在lo接口上配置VIP但必须关闭ARP响应否则它们会响应客户端对VIP的ARP请求导致流量绕过调度器直接打到后端。配置方法# 在每台真实服务器上执行 echo 1 /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 /proc/sys/net/ipv4/conf/lo/arp_announce echo 1 /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 /proc/sys/net/ipv4/conf/all/arp_announce ip addr add 192.168.1.100/32 dev lo label lo:0arp_ignore1表示只回答目标IP是本机物理接口IP的ARP请求arp_announce2表示总是使用最佳本地地址发送ARP。这两个参数配合确保后端不会“抢答”VIP的ARP。3.3 调度算法轮询、加权、最少连接的实际效果差异LVS支持十几种调度算法常用的有rr轮询请求依次分给每台后端适合后端性能一致的场景。wrr加权轮询按权重分配性能强的机器权重高。权重需要根据CPU、内存、实际压测结果来定不能拍脑袋。lc最少连接把请求发给当前连接数最少的后端适合请求处理时间差异大的场景。wlc加权最少连接默认算法综合了权重和连接数大多数场景下表现最稳。sh源地址哈希同一客户端IP总是打到同一后端适合需要会话保持的场景但后端故障时会话会丢失。我的一般建议是无状态服务用wlc有状态但能容忍会话丢失的用wlc必须会话保持的用sh并配合后端会话共享。不要盲目用rr因为实际后端性能往往不一致rr会导致慢的机器堆积请求。3.4 完整配置KeepalivedLVS DR模式实战主调度器Keepalived配置virtual_server 192.168.1.100 80 { delay_loop 6 lb_algo wlc lb_kind DR persistence_timeout 50 protocol TCP real_server 192.168.1.20 80 { weight 100 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 connect_port 80 } } real_server 192.168.1.21 80 { weight 100 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 connect_port 80 } } }persistence_timeout 50表示同一客户端50秒内的请求都打到同一后端这是一种简单的会话保持。TCP_CHECK会定期探测后端80端口连续失败3次就把该后端从池子里摘掉。查看LVS转发状态用ipvsadm -Ln输出里会显示每个后端的活跃连接数和权重。如果发现某个后端一直是0连接要么是健康检查没通过要么是权重配错了。实操心得DR模式下后端服务器的默认网关不需要指向调度器因为响应是直接回给客户端的。但如果你发现响应回不去检查后端服务器的路由表确保回包路径正确。4. HAproxy七层代理的健康检查与高可用实践4.1 HAproxy和LVS的本质区别四层与七层的分界线LVS工作在四层传输层它只看IP和端口不关心内容是HTTP还是MySQL。HAproxy工作在七层应用层它能解析HTTP协议根据URL、Host头、Cookie做转发决策还能做SSL终止、压缩、重写。打个比方LVS像一个邮局分拣员只看信封上的地址把信分到不同区域HAproxy像一个前台接待能拆开信封看内容根据信里写的事情类型转给不同的部门。所以HAproxy更灵活但性能略低LVS更高性能但功能单一。实际架构中经常是LVS做第一层四层负载均衡后面挂多个HAproxy做七层转发HAproxy后面才是真正的应用服务器。4.2 健康检查的三种级别从端口探测到业务级检测HAproxy的健康检查比LVS精细得多分三个层次TCP检查只检查端口是否能建立连接。配置option tcp-check。HTTP检查发送HTTP请求检查返回状态码。配置option httpchk GET /health。业务级检查检查返回内容里是否包含特定字符串。配置http-check expect string OK。我强烈建议至少用HTTP检查因为端口开着不代表服务正常。曾经遇到过Tomcat进程还在但线程池满了端口能连上但请求全部超时TCP检查完全发现不了。加上http-check expect status 200后这种假死状态就能被及时摘除。4.3 HAproxy配置文件的结构与关键参数HAproxy配置分四段global、defaults、frontend、backend。下面是一个生产可用的模板global log /dev/log local0 maxconn 50000 user haproxy group haproxy daemon stats socket /var/run/haproxy.sock mode 600 level admin defaults log global mode http option httplog option dontlognull option redispatch retries 3 timeout connect 5s timeout client 30s timeout server 30s timeout check 3s frontend web_front bind *:80 bind *:443 ssl crt /etc/haproxy/certs/site.pem default_backend web_servers backend web_servers balance roundrobin option httpchk GET /health http-check expect status 200 server web1 192.168.1.20:8080 check inter 2s fall 3 rise 2 server web2 192.168.1.21:8080 check inter 2s fall 3 rise 2 backup几个关键参数解释option redispatch表示如果某台后端挂了重试时把请求发给其他健康后端retries 3是重试次数inter 2s fall 3 rise 2表示每2秒检查一次连续3次失败标记为down连续2次成功标记为upbackup标记该服务器为备用只有主服务器全挂才启用。4.4 用Keepalived给HAproxy做高可用HAproxy本身不做高可用需要Keepalived配合。配置和第二节的Keepalived热备几乎一样只是健康检查脚本改成检查HAproxy进程vrrp_script chk_haproxy { script killall -0 haproxy interval 2 weight -30 fall 3 rise 2 }两台HAproxy都配置相同的backendVIP在Master上。客户端访问VIPMaster上的HAproxy处理请求。Master挂了VIP漂到BackupBackup上的HAproxy接管。由于两台HAproxy配置完全一致切换后行为不变。注意HAproxy的stats socket可以用来做运行时管理比如动态调整后端权重、下线某台服务器。配合socat工具可以脚本化操作这在紧急故障时非常有用。5. 三种方案的选型对比与组合架构5.1 一张表看清三种方案的适用边界维度Keepalived热备KeepalivedLVSHAproxy工作层次节点级四层七层核心功能VIP漂移、节点冗余四层负载均衡高可用七层转发健康检查性能不涉及转发无损耗内核级极高用户态较高灵活性低低高配置复杂度低中中典型场景数据库主备、单服务双机大流量四层分发HTTP路由、SSL终止、灰度发布会话保持不涉及源地址哈希Cookie插入/源地址哈希选型的核心判断逻辑是先问需不需要七层功能再问流量规模有多大。如果只需要把请求分给几台后端且不需要看HTTP内容LVSKeepalived是性能和稳定性的最优解。如果需要根据URL路由、做SSL终止、或者后端是HTTP服务且需要精细健康检查HAproxy更合适。如果只是两台机器做主备比如MySQL主从Keepalived热备就够了。5.2 大规模场景下的组合架构LVSHAproxyKeepalived在日活百万级以上的场景里常见架构是三层最外层两台LVS调度器 Keepalived持有VIP用DR模式把流量分给下层HAproxy集群。中间层多台HAproxy每台都用Keepalived做双机热备或者用ECMP等价路由做集群负责七层转发和健康检查。最内层应用服务器集群注册在HAproxy的backend里。这样LVS扛住了四层的高并发HAproxy提供了七层的灵活性Keepalived保证了每一层都没有单点。每一层的健康检查独立工作LVS检查HAproxy的端口HAproxy检查应用的健康接口任何一层出问题都能自动隔离。这个架构的复杂度在于故障排查链路变长。请求不通时要逐层确认VIP在不在、LVS转发规则对不对、HAproxy后端状态是否健康、应用本身是否正常。我的习惯是每层都配好日志和监控LVS用ipvsadm -Ln --stats看转发计数HAproxy用stats页面看后端状态应用层看自己的健康接口。5.3 云环境下的特殊考量在云平台上VIP漂移需要平台支持。有些云厂商允许在控制台申请虚拟IP并绑定到实例有些则限制ARP响应导致Keepalived默认的组播模式无法工作。这时候要么改用单播模式要么使用云厂商提供的负载均衡服务。另外云环境的网络延迟和丢包率与物理机房不同VRRP的advert_int可能需要调大避免网络抖动导致误切换。我一般会在云环境把advert_int设为2秒fall设为3次这样需要6秒才判定故障虽然切换慢一点但避免了频繁误切。6. 实战排查那些配置正确但就是不工作的时刻6.1 VIP漂移了但服务不通ARP缓存惹的祸有一次切换后VIP确实漂到了备节点ip addr能看到VIP但客户端访问就是不通。排查了半天发现是客户端和交换机的ARP缓存还指向旧Master的MAC。VRRP切换时会发送免费ARPgratuitous ARP通知大家更新缓存但如果网络设备忽略了免费ARP缓存就不会更新。解决办法有两个一是在Keepalived配置里加garp_master_delay和garp_master_repeat参数多发送几次免费ARP二是在切换脚本里手动发送ARP更新arping -I eth0 -c 3 -A 192.168.1.100-A表示发送ARP应答而不是请求-c 3表示发3次。这个命令放在notify_master脚本里能大幅提高切换后立即恢复的概率。6.2 HAproxy后端全部显示DOWN但服务明明正常这种情况通常是健康检查配置和后端实际行为不匹配。比如后端返回的是302重定向但健康检查期望200或者后端要求Host头但健康检查没带。排查步骤在HAproxy服务器上手动执行健康检查请求curl -v http://后端IP:端口/health看返回什么。检查HAproxy日志tail -f /var/log/haproxy.log看健康检查的具体失败原因。用stats socket查看后端详情echo show stat | socat stdio /var/run/haproxy.sock。常见修复方式加http-check expect status 200 302允许多个状态码或者在option httpchk里指定完整的请求头和Host。6.3 LVS转发正常但后端收不到请求DR模式下如果后端收不到请求先检查后端lo接口上的VIP是否配置正确以及ARP参数是否生效。用ip addr show lo确认VIP在用sysctl net.ipv4.conf.all.arp_ignore确认值是1。还有一个容易忽略的点后端服务器的防火墙可能拦截了目标IP为VIP的包。因为包的目标IP是VIP而VIP配置在lo上某些防火墙规则会把它当作非法流量丢弃。检查iptables -L -n或firewall-cmd --list-all确保没有拦截。6.4 Keepalived日志里反复出现“VRRP_IS_INITIALIZED”错误这个错误通常表示VRRP实例初始化失败最常见的原因是virtual_router_id冲突或者网卡名称写错。用ip link show确认网卡名用tcpdump -i eth0 vrrp抓包看是否有其他VRRP通告。如果同一网段有多个Keepalived组确保每组的router_id不同。7. 监控与日常维护让高可用真正“可用”7.1 必须监控的五个指标高可用架构搭好只是开始没有监控的高可用等于没有高可用。以下五个指标必须纳入监控VIP归属当前VIP在哪个节点上是否与预期一致。可以用脚本定期检查ip addr | grep VIP并上报。VRRP状态Keepalived实例是MASTER还是BACKUP状态切换次数。后端健康状态HAproxy或LVS里有多少后端处于down状态。切换事件每次VIP漂移都要记录并告警因为非预期的切换意味着有故障发生。连接数LVS的活跃连接数、HAproxy的当前会话数突增或突降都可能是异常信号。7.2 定期演练不要等真出事才发现切换不了我见过太多团队配了Keepalived但从来没测试过切换真到主节点挂了才发现备节点配置有误、VIP漂不过去。建议每季度至少做一次切换演练手动停掉主节点的Keepalived观察VIP是否在预期时间内漂到备节点业务是否自动恢复切换期间有多少请求失败。演练时要注意选择业务低峰期提前通知相关方准备好回滚方案。切换后检查所有后端服务的会话是否丢失、数据库连接是否正常。演练结束后分析切换耗时如果超过预期检查advert_int、fall等参数是否合理。7.3 配置版本管理别让两台机器的配置不一致Keepalived和HAproxy的配置文件必须纳入版本管理如Git每次修改都提交并记录原因。两台机器的配置差异应该只有state、priority、router_id这几项其他必须完全一致。我习惯用Ansible或类似的配置管理工具批量下发避免手动修改导致不一致。实操心得在notify_master、notify_backup脚本里加上配置校验逻辑比如检查关键进程是否在运行、关键端口是否监听。如果校验失败脚本返回非零值Keepalived会认为切换失败并记录日志避免切到一个不健康的节点上。8. 我在这套架构上踩过的三个真实坑第一个坑是优先级设置反了。主节点priority配了90备节点配了100结果备节点一直抢着当Master主节点反而成了Backup。当时没仔细看日志排查了半天才发现是数字大小搞反了。记住priority越大越优先。第二个坑是健康检查脚本权限问题。Keepalived默认以keepalived用户运行脚本但脚本里执行的命令需要root权限导致检查一直失败。后来在global_defs里加了script_user root和enable_script_security才解决。但要注意用root跑脚本有安全风险脚本内容必须严格可控。第三个坑是HAproxy的timeout设置过短。后端某个接口处理时间较长比如导出报表要10秒但timeout server设了5秒导致请求被HAproxy主动断开用户看到502。后来把超时调到30秒并对长耗时接口单独配置了更长的超时。这个问题的教训是超时时间要根据业务实际响应时间来定不能拍脑袋。这套高可用架构从单机到双机、从四层到七层每一步都是在解决具体问题的过程中逐步演进的。没有银弹只有适合当前场景的组合。Keepalived负责“谁活着”LVS负责“分得快”HAproxy负责“分得准”三者各司其职配合好了才能让服务真正稳定运行。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑