ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

LVS、Keepalived、HAProxy生产实践:三者的分工与架构选型

LVS、Keepalived、HAProxy生产实践:三者的分工与架构选型 第一次在生产环境同时面对LVS、Keepalived、HAProxy这三兄弟时很多人第一反应是这仨不都是做负载均衡的吗为什么一台机器上要装两三个这个问题我当年也纠结了很久直到某个凌晨被线上告警炸醒——两台后端同时宕机Keepalived没把VIP切走流量全部打到一台半死的机器上我才真正明白它们根本不是竞争关系而是完全不同的三个角色。这篇文章就用我踩过的坑和实际在跑的生产配置把这几个组件的分工、选型和避坑一次性说透。不管你是刚入门要搭第一套高可用架构还是已经在维护线上环境想排查疑难问题这里面的内容都应该能帮到你。1. 先把三兄弟的分工一次说清楚1.1 用物流分拣中心理解三个角色先忘掉技术名词想象一个大型物流分拣中心。货车到了园区门口保安先看车牌和货物类型能放行的直接放行到对应月台这是四层转发只认网络层和传输层的信息速度快到几乎没有存在感——这就是LVS的角色。园区里边有个调度台值班人员不仅看货物类型还要看收件人地址、偏好甚至指定日期再决定送哪个仓库这是七层分发功能强、能感知应用层内容——这就是HAProxy的角色。而保安和调度台背后还有一套考勤和轮岗制度主值班员倒班时副值班员要无缝顶上这个保证“关键时刻有人管事”的机制——就是Keepalived。把这三个角色放到同一套架构里分工就很清楚了LVS负责在数据链路层/网络层把海量连接快速分散到多台机器HAProxy负责在七层做精细化流量调度Keepalived则负责监控并保证入口VIP不因为单点故障而失效。理解了这层关系你就不会纠结“能不能只用HAProxy不用LVS”这种问题了——当然能取决于你的规模和需求但你也得知道大流量场景下LVS那层“无状态转发”的动作HAProxy无论如何也替代不了。1.2 LVS四层转发的效率之王LVS的全称是Linux Virtual Server工作在四层支持TCP/UDP的负载均衡。它最核心的产品力是“快”。因为不需要解析HTTP头部不需要维护复杂的会话状态多数模式下LVS的转发吞吐量可以做到逼近网卡物理上限。生产中最常用的是DR模式Direct Routing它的原理是客户端请求到达LVS的VIP后LVS通过MAC地址把报文原封不动地发给选中的后端真实服务器后端处理完以后直接把响应回给客户端回程流量根本不再经过LVS。这种“请求经过、响应不走”的方式让LVS在巨大流量面前依然从容。DR模式虽然高效代价是配置有门槛。需要调整的不仅LVS本身还有后端两台真实服务器的内核参数和回程路由坏消息是这部分网上资料很多都含糊其辞。我在生产里见过最典型的翻车现场realserver没有抑制ARP导致VIP在局域网内被真实服务器“抢答”客户端访问VIP时请求走到了其中一台后端但LVS的转发规则也好、健康检查也好全部失效看起来就是集群时好时坏。所以提到LVS千万不要只把它当一条ipvsadm命令来记它背后是一套需要配合内核网络策略的完整链路。1.3 Keepalived不是为了负载均衡是为了不宕机Keepalived这个命名本身就点出了它的核心任务让服务“一直活着”。它基于VRRP协议实现高可用常见形态是一主一备两台机器绑定同一个VIP正常情况下VIP挂在主节点上主节点挂掉后备节点通过优先级竞选把VIP和对应服务接管过来。它本身不做负载均衡决策只做一件事故障时保证VIP不丢、服务不中断。理解Keepalived的关键在于“虚拟”二字。VIP不是物理网卡上的固定地址而是通过VRRP协议在两台机器之间“飘”的;客户端感知不到这个漂移过程只知道自己访问的IP一直有人在响应。Keepalived除了漂移VIP还承担对后端真实服务器的健康检查任务在LVS场景下它会把多个real_server配置到一起哪个挂了就把它从转发列表里摘掉恢复后自动加回。也就是说Keepalived其实干了两件事管VIP漂移同时管后端状态同步到转发规则。1.4 HAProxy七层世界的规则处理器HAProxy是目前最流行的开源七层负载均衡器支持HTTP和TCP协议配置灵活内置丰富的ACL规则、健康检查和会话保持能力。很多中小团队第一套高可用架构就是“Keepalived HAProxy”前面Keepalived保活后面HAProxy把请求按域名、URI、Header甚至Cookie规则分发到后端。和LVS相比HAProxy能感知应用层内容可以做更细粒度的灰度发布、路径路由、请求改写这是四层转发做不到的。HAProxy的快不仅体现在吞吐上还体现在它对连接的生命周期管理上。它把连接分成前端和后端来维护可以缓存空闲连接、限制慢客户端占用资源降低“慢请求拖垮正常服务”的概率。但也正因为工作在七层HAProxy需要做更多的报文解析内存占用和CPU开销都要高于LVS。生产上很多团队会在HAProxy前面再挡一层LVS就是为了让七层机器尽量只干“精细活”海量连接交给四层去扛。到这里三者的位置基本清楚了Keepalived负责“活着”LVS负责“快”HAProxy负责“懂规则”。接下来真正的核心问题是这三者怎么排列组合才合理2. 架构选型到底该用哪种组合2.1 双节点起步Keepalived HAProxy 的高可用入口如果你的业务量目标是每日百万级别以内后端服务是HTTP接口且需要细粒度路由那么最经典的组合就是两台HAProxy节点前面挂一个Keepalived漂移VIP后面接若干个应用服务器。这个架构的好处是简单、直观、好排查Keepalived配置只管VIP和健康检查HAProxy只管转发规则两层互不干扰。出了问题无非就是看“是VIP没飘成功”还是“转发规则有问题”一条日志追到底。但这套架构有一个容易被忽视的瓶颈——HAProxy本身的状态。即使Keepalived健康检查手段再丰富它也只能知道HAProxy进程还活着无法感知进程是否处于半死状态比如处理线程卡死、accept队列堆积、后端连接全满。遇到这种“进程没死但干活越来越慢”的情况Keepalived不会触发切换用户实际感受到的依然是故障。我以前就碰到过HAProxy的连接数被慢客户端吃光进程还在但新请求全部排队超时保活机制完全没有反应。所以用Keepalived做HAProxy的保活时健康检查必须设计成“业务探活”不能只做进程级检查。2.2 大流量入口双LVS在前HAProxy在后当流量再往上走单靠HAProxy扛不住需要引入LVS做入口卸载。典型架构是最前面两台LVS服务器跑Keepalived绑定VIP后面挂一组HAProxy集群也是两台或更多各自再接KeepalivedHAProxy再把流量分发给后端的应用服务器。客户端只认VIPLVS把流量转发到HAProxy节点HAProxy做完七层路由后再往后抛——两层负载均衡各司其职HAProxy不会再被海量并发连接压垮。很多朋友会问既然LVS都能扛住大量并发为什么HAProxy这层不干脆去掉答案在于“精细化”和“规模化”是两条线。LVS的DR模式转发效率极高但它只认IP和端口做不了“根据URI把流量切到不同版本的后端”这种需求。而HAProxy的ACL和调度策略非常成熟在七层灰度、多域名共存的环境下几乎不可替代。所以这个组合不是冗余而是让每层都只做自己擅长的事。如果你有跨机房容灾需求LVS在前也能更方便地和交换机策略联动比如宣告VIP路由调试起来比HAProxy要平滑。2.3 选型决策的四个核心考量点第一看规模。日请求量在千万级以内QPS峰值几千到几万单层HAProxy足够不必硬上LVS。第二看流量特征。如果业务是长连接数据库代理、WebSocket、TCP隧道四层负载更合适LVS或HAProxy的tcp模式都可以如果是HTTP短连接且要按域名和路径分流必须上七层。第三看团队运维水平。LVS的DR模式对网络参数、后端系统配置的要求更高排错时涉及tcpdump、ARP表、ipvs内核表新手团队贸然上LVS容易在细节上踩坑。第四看业务对故障恢复的要求。Keepalived能做到的切换时间通常2秒以内LVSKeepalivedHAProxy这套架构可以将切换做到秒级且几乎无感知但配置和测试成本也相应增加。2.4 演进路线从小规模到大规模的平滑升级我的建议是不要一上来就上最重的方案而是随着流量增长逐步演进出层次。初期使用单台HAProxy做反代过段时间加一台做Keepalived高可用业务快速增长、HAProxy成为瓶颈时在前面插入LVS卸载连接再往后如果有多活需求再在DNS或全局负载层引入多机房调度。每一次演进都应该单一变更可回滚不追求一步到位。我见过团队一开始就搭了三层负载均衡结果线上排故障时排查链路太长性能没成为问题人的认知先成了瓶颈——架构演进要跟着业务节奏走不是越复杂越好。3. 核心实操双LVS Keepalived HAProxy架构完整落地3.1 整体拓扑与角色分配为了讲清楚落地细节我给出一个对应章节2.2的参考拓扑生产完全可以照抄改IP。前面的两台LVS节点一台MASTER一台BACKUP跑VRRP绑定VIP后面两台HAProxy节点也组成一个VRRP组绑定后端VIP组再往后是两台Nginx应用服务器。LVS通过DR模式把VIP上的80端口流量转发给两台HAProxyHAProxy再按域名规则把请求分给Nginx。这样任意一台LVS或HAProxy宕机业务都不会中断——LVS层面由Keepalived切换HAProxy层面由它自己的Keepalived切换。具体IP规划如下VIP为192.168.1.100LVS主节点192.168.1.11LVS备节点192.168.1.12HAProxy节点分别192.168.1.21和192.168.1.22后端Nginx分别为192.168.1.31和192.168.1.32。所有机器在同一个二层网络这是DR模式能工作的前提。生产环境如果跨VLANDR模式的广播和ARP策略会变得很麻烦这也是为什么有些场景会改用NAT模式的原因。3.2 配置LVS节点上的Keepalived安装Keepalived的过程这里不赘述yum或apt直接装就行重点看keepalived.conf的写法。以下是我的生产实例vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass yourpassword } virtual_ipaddress { 192.168.1.100/24 dev eth0 label eth0:0 } } virtual_server 192.168.1.100 80 { delay_loop 5 lb_algo wrr lb_kind DR protocol TCP # LVS会转发流量到这组真实服务器也就是后面的HAProxy节点 real_server 192.168.1.21 80 { weight 1 HTTP_GET { url { path /healthz status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 2 } } real_server 192.168.1.22 80 { weight 1 HTTP_GET { url { path /healthz status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 2 } } }backup节点的配置只需要把state改成BACKUP、priority改成90其他保持一致。这里有两个关键点lb_kind一定要写DR否则LVS会走NAT模式转发逻辑完全不同real_server的健康检查建议用HTTP_GET而不要用TCP_CHECK因为TCP能连通不代表HAProxy真的能返回正常的业务响应尤其要确保HAProxy上有/healthz这个探活地址并且该接口不依赖后端的数据库或缓存否则容易出现“健康检查跟着后端一起抖动”的连锁问题。注意vrrp_instance中virtual_router_id必须两机一致keepalived才能互相认出彼此是同一个VRRP组的成员不一致会导致两边都认为自己该持有VIP直接造成脑裂。authentication_pass这个参数也是写错了日志里会出现不断的VRRP包校验失败。3.3 配置后端HAProxy节点的内核网络参数这一节是最容易翻车的也是LVS的DR模式之所以劝退很多新手的地方。DR模式下LVS转发给后端的数据包目标MAC地址是后端网卡但目标IP依然是VIP192.168.1.100。后端收到这个包后如果按照正常工作流程本机网卡发现目标IP不是自己的IP比如本机只有192.168.1.21会直接把包丢弃——所以必须在每台HAProxy节点上把VIP绑定到lo这块虚拟网卡上ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 up这里用了32位掩码而不是常见的24位。原因很微妙如果掩码是24位系统会认为整个192.168.1.0/24网段的流量都应该通过lo转发反而会干扰正常的东西向流量甚至路由决策用32位掩码则只宣告VIP本身属于本机精准且安全。光绑定地址还不够必须抑制ARP响应。如果不做后端节点会响应客户端发往VIP的ARP请求告诉“VIP在这台机器上”流量就被引流到了某一台后端LVS完全失去意义。需要在sysctl.conf中修改四个参数net.ipv4.conf.lo.arp_ignore 1 net.ipv4.conf.lo.arp_announce 2 net.ipv4.conf.all.arp_ignore 1 net.ipv4.conf.all.arp_announce 2执行sysctl -p后再用arping或ip neigh看一遍VIP对应的MAC地址确认它只在LVS主节点上。还有一个坑是回程路由。DR模式要求后端响应直接返回给客户端但后端本身并没有VIP它响应的源地址应该是VIP所以必须添加一个路由确保发送给VIP所在网段的包通过本机lo处理route add -host 192.168.1.100 dev lo这三个步骤做完后端节点才算真正能接住LVS丢过来的流量。我当年遗漏了route add这一步结果是LVS不断转发、后端不断丢包健康检查还显示正常因为健康检查走的是单独IP线上故障全靠用户来报告狼狈极了。3.4 配置HAProxy的关键性能参数HAProxy的核心配置分成global、defaults、frontend、backend几个块。为了保证在高并发下不拖后腿我习惯在生产里这样写global maxconn 100000 nbproc 2 nbthread 4 pidfile /var/run/haproxy.pid defaults mode http timeout connect 5s timeout client 30s timeout server 30s timeout http-keep-alive 2s option httplog option forwardfor frontend main bind *:80 # 简单按域名分流的例子 acl is_payment hdr_dom(host) -i pay.example.com use_backend payment_servers if is_payment default_backend web_servers backend payment_servers balance roundrobin option httpchk GET /healthz server web1 192.168.1.31:80 check inter 3s fall 3 rise 2 server web2 192.168.1.32:80 check inter 3s fall 3 rise 2 backend web_servers balance leastconn option httpchk GET /healthz server web1 192.168.1.31:80 check inter 3s fall 3 rise 2 server web2 192.168.1.32:80 check inter 3s fall 3 rise 2这里值得展开的是timeout与maxconn设置。前端和后端的timeout决不能照抄默认值必须结合业务特征设置。比如你的页面偶尔有慢查询超过30秒那server timeout设30s就太短会造成正常请求被断开、用户看到502但timeout设得过长又会导致大量慢连接占住进程资源。一个比较接地气的做法是先看后端P99响应时间再在这个基础上加一倍作为server timeout参考值。maxconn同理100000这个值如果你们机器只有2C4G很可能内存先爆掉实际应该压测后根据内存使用率来反推。option forwardfor这行很容易被忽略但没有它后端Nginx拿不到客户端真实IP日志里全是HAProxy节点的地址排查访问来源会非常痛苦。3.5 验证与切换演练架构搭完不是能通就收工一定要做几轮故障演练。第一步在LVS主节点上执行ip addr show确认VIP挂在eth0:0上在LVS备节点上执行ipvsadm -L -n确认内核转发规则已经从主节点同步过来。第二步模拟主节点宕机可以执行systemctl stop keepalived来验证VIP是否在3秒内漂移到备份节点。第三步做真实流量测试用ab或wrk打压力同时kill掉一台HAProxy观察业务中断时间。我建议把这套演练写成固定脚本每次架构变更后都自动跑一遍。不要过度相信Keepalived本身任何VIP漂移机制的可靠性都必须在实际演练中验证因为你不知道交换机上有没有开启STP、ARP缓存老化时间是多久等外部因素。生产中很多“Keepalived没起作用”的案例并不是Keepalived的问题而是二层环境的变化导致VRRP报文或VIP的ARP广播被交换机策略拦截了这些只有演练才能暴露。4. 生产环境避坑指南那些文档里不会写的坑4.1 最隐蔽的坑ARP表缓存和VIP位置漂移DR模式下客户端访问VIP时需要解析VIP的MAC地址。正常情况下VIP在LVS主节点上客户端ARP表里记录的就是LVS主节点网卡的MAC。主节点宕机后备节点广播VRRP报文并接管VIP备节点会发送免费的ARP广播来刷新客户端的ARP表。但有些交换机或云网络环境会把这种免费ARP包过滤掉客户端依然往老MAC发请求结果就是VIP明明已经漂移到备机线上还是大面积超时直到客户的ARP表老化。这个问题在物理机之间可以用ping一个广播地址来强制刷新但更稳妥的做法是在Keepalived的配置里加上vrrp_skip_check_adv_addr和vrrp_strict参数的理解同时确认交换机的组播和未知单播洪泛策略放行了VRRP报文。云环境则更复杂因为很多云厂商的虚拟网络不标准支持VRRP这也是我后来在云上更倾向用SLB而不是自建LVS的原因。4.2 Keepalived脑裂主备同时持有VIP脑裂是指主备两台机器同时认为自己是MASTER、同时持有VIP造成网络上出现两个相同IP的设备ARP混乱流量时好时坏非常隐蔽。诱发脑裂最常见的原因是VRRP组播报文被防火墙或安全组拦掉了主备之间收不到对方的hello包各自都认为对方挂了于是各自抢占VIP。解决思路有三个维度网络层面放行VRRP协议Keepalived内部增加对端检查脚本外部用仲裁机制兜底。我目前在生产里比较务实的方案是给Keepalived加一个自定义的smtp或script告警一旦检测到本机持有VIP但VIP无法正常提供服务比如调用本地健康检查脚本失败就主动降低本机优先级并释放VIP。这比指望防火墙规则永远正确要可靠得多。4.3 HAProxy后端的连接堆积与排队七层负载均衡还有一个独特的坑连接队列堆积。HAProxy的maxconn设得再大后端应用服务器也有自己的TCP连接上限。当后端响应变慢后端队列满了之后HAProxy会持续把新连接挂在自己的队列里等待用户感觉就像页面卡死。这种现象在监控图上表现为HAProxy的qcur值一直往上爬。排查时先看HAProxy的统计页通过stats socket或web界面找到qcur高、qmax大的实例和后台server。生产上的处理手段一般分三步第一步临时调低对应后端的maxconn或调高后端的timeout server给后端喘息空间第二步定位后端变慢的原因通常是数据库慢查询、缓存穿透第三步在HAProxy上启用排队策略比如限制单IP最大连接数给慢客户端单独的池子避免正常请求被拖死。4.4 常见问题速查表故障现象可能原因排查命令/思路VIP通的但业务时好时坏ARP表缓存冲突VIP被多台机器响应ip neigh、arping 检查VIP对应MAC是否始终在LVS主节点LVS转发但后端总丢弃请求realserver未绑定VIP或未加回程路由ifconfig lo:0、route -n 确认VIP绑定和路由Keepalived主备同时持有VIP组播被防火墙隔离vrid不一致tcpdump抓VRRP报文(224.0.0.18)检查防火墙规则HAProxy健康检查正常但转发502后端超时或队列满看stats页面的qcur/scur排查后端日志交换机断网后VIP漂移失败交换机STP收敛太慢或ARP缓存过大调整交换机端口fastport、恒定性ARP配置连接数增长但CPU不高负载不平衡未配置leastconn检查backend的balance策略改为leastconn试试上面这个表是我自己实际排障记录改写的基本覆盖了新手到中级运维最常遇到的问题。排查思路有个共同点先确认VIP在哪再确认转发规则有没有生效最后再往后端追不要一开始就在应用日志里翻来翻去。这种分层排查的习惯比任何脚本都能更快帮你定位问题。5. 性能评估与架构演进建议5.1 压测思路与指标预期整套架构落地后必须压测拿到真实数据否则你根本不知道它在什么时候会崩。压测我建议分三层做。第一层只压LVS用tcpreplay或pktgen生成纯TCP包观察LVS节点的CPU和丢包率这一层的重点不是QPS而是吞吐bps和ppsLVS在纯转发时瓶颈通常是物理网卡和内核协议栈而不是软件本身。第二层压LVSHAProxy用wrk或ab打HTTP请求观察HAProxy节点的CPU、内存、连接队列重点指标是QPS、延迟和错误率。第三层全链路压到后端Nginx拉上数据库或缓存一起压看整个架构的瓶颈到底在哪一层。压测过程中我发现一个很有意思的现象很多时候瓶颈不在LVS也不在HAProxy而是后端Nginx的keepalive连接数和单个进程的fd上限没调好。用wrk测试时并发一上去后端日志马上出现too many open files联合创始人一晚上都在改ulimit——类似的坑现在如果你提前知道完全可以避免。5.2 流量再大之后从单集群到多活当单集群的容量逼近极限或者有跨机房容灾需求时架构还得继续进化。LVSKeepalived虽然能在单个集群内做到秒级切换但跨机房就无能为力了。这时你会需要上层DNS、GSLB、云负载均衡或自建边界集群来分流多个IDC。到了这个阶段LVS和HAProxy仍然在单个机房内部起到重要作用但全局调度已经不属于它们的职责范围。我在规模增长过程中还发现LVS的VIP在单一集群里虽然好使但多机房场景下IP就变成了稀缺资源而且不同运维团队对LVS的理解不一致也容易造成配置漂移。后期如果条件允许我会优先考虑让负载均衡团队统一维护一套IaC模板用terraform或ansible把LVS、Keepalived、HAProxy的配置全部代码化减少人为修改带来的不可控风险。这一点越早做越好别等到三十台以上的机器再回头改。5.3 架构演进中值得保留的细节演进归演进有三个基础细节是我无论架构怎么变都一直保留的一是所有健康检查都必须走“业务探活”绝不能只看进程在不在二是所有VIP相关的ARP和路由变更都必须在变更前先宿主机演练不能被生产环境打脸三是压测指标和监控报警要一直保留原始版本的对比数据方便快速判断流量模式是否发生了变化。这些习惯看似琐碎但在故障面前它们比任何想象中的“架构先进”都更能救你命。6. 写在最后的一点个人体会负载均衡这套东西资料虽然多但真正能在生产里跑得稳的组合往往是团队对每一层职责边界理解最透彻的组合。我自己踩过不少坑有的坑是因为配置参数少写了一行有的坑是因为架构顺序没想清楚有的坑则是被网上各种千篇一律的教程误导照着抄却没验证。如果你读完这篇能记住三句话我会很满足LVS解决并发吞吐问题HAProxy解决业务分发问题Keepalived解决故障高可用问题。搞清楚每一层解决什么问题选型就不会偏排障也不会手忙脚乱。最后再分享一个小技巧每次做架构变更前先在本地用虚拟机关闭所有防火墙把LVS的转发链路、Keepalived的VIP漂移、HAProxy的健康检查全部实测一遍再复现一次故障切换确认无误后再上生产——这套流程看上去麻烦但相比线上出一次故障的成本划算太多了。
返回列表