ARTICLE DETAIL

资讯详情

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

HAProxy超时配置与负载均衡算法实战指南

HAProxy超时配置与负载均衡算法实战指南 1. 超时配置先搞懂haproxy到底在管什么做后端服务的同学几乎都会在某个深夜被线上问题搞得头疼上游接口明明没挂客户端却反馈转圈半天才报错数据库连接池明明够用服务却时不时出现连接被重置。排查了一圈最后定位到中间那一层haproxy发现是超时参数没配对。这个场景我太熟了所以想单独把haproxy里的超时配置和负载均衡这两块拿出来聊透。先说个很多人容易忽略的点haproxy的超时配置本质上是在帮你定义“一个连接到底算不算已经死掉”。网络请求从客户端到haproxy再到后端服务器中间任何一环卡住如果没有超时限制haproxy就会一直傻等连接越积越多最终把自身的文件描述符和内存耗尽。配置合理的超时相当于给每个连接上了一道保险丝让异常连接能及时被清理掉而不是拖垮整个集群。这套配置适合谁我觉得只要你的服务架构里用了haproxy做入口或四层转发都值得花时间把超时参数从头到尾捋一遍。尤其是做微服务网关层、数据库读写分离代理、WebSocket长连接接入的同学超时配不好线上故障基本是迟早的事。下面我按实际使用频率和重要性把关键参数一个个拆开讲。1.1 五分钟看懂haproxy的连接生命周期要理解超时先得理解haproxy处理一次请求的完整链路。客户端连上haproxyhaproxy往后端服务器发起新连接然后两端之间转发数据。这个过程中一共有几个独立的时间段客户端与haproxy建立连接、haproxy与后端建立连接、请求数据从客户端传给haproxy、haproxy等待后端返回响应、后端返回数据传回客户端。每个时间段都可能卡住所以haproxy为每一段都设计了独立的超时配置。我举个生活化的例子你打电话给客服拨号等待接通算一段接通后你报问题算一段客服查询系统算一段客服给你读答案算一段。任何一段超时没人说话电话就可以挂断了。haproxy的超时配置就是这个“挂断”的判断标准只不过它更精细每一段都能单独设置。1.2 最常用的五个超时参数先记住这些配置haproxy时我建议先记住下面五个参数它们覆盖了90%以上的场景timeout connecthaproxy向后端服务器发起TCP连接的超时时间。后端服务器IP不通、端口没监听、防火墙丢包都会导致这个阶段卡住。默认值一般是5秒如果后端网络质量差或者服务器负载高需要适当调大。timeout client客户端与haproxy之间两次数据交互的最大间隔时间。这个不是总时长而是空闲超时。客户端建立了连接但一直不发送数据超过这个时间就被haproxy断开。timeout serverhaproxy与后端服务器之间两次数据交互的最大间隔时间。后端处理慢、接口长时间不返回都会卡在这一段。timeout check健康检查的超时时间。haproxy定期探测后端服务器是否存活这个参数控制探测请求发出后等待响应的时间。timeout http-request对于HTTP模式从客户端发出请求到haproxy收到完整请求头的时间。可以防止慢速攻击。这五个参数里timeout client和timeout server是最容易踩坑的。很多人只配了connect和check没配client和server结果接口一慢就504连接一空闲就被断开问题都出在这。2. 超时参数怎么定给每个场景算笔账配置超时最忌讳的就是照搬模板。不同业务对超时的容忍度完全不同必须按场景一项项去算。我平时给团队定超时参数基本都是按“正常耗时的3到5倍”这个原则来。为什么是3到5倍而不是2倍因为要考虑网络抖动、GC停顿、数据库慢查询等突发情况。如果只是正常耗时的2倍稍微抖一下就会误杀正常请求。2.1 timeout connect和timeout server的取值推算先说timeout connect。后端是同一个机房的内网IP一般1到3秒足够。跨机房或者走公网建议5到10秒。这个值不宜过大因为connect阶段卡住往往意味着后端网络出了问题等太久只会拖慢整体感知。我踩过一次坑后端某台机器网卡故障连接请求全部丢包当时connect配了30秒结果客户端请求全部排队整个入口层被拖死。后来改成3秒故障机器很快就被摘除其他正常机器完全不受影响。再说timeout server。这个参数要看后端接口的P99耗时。假设你的接口P99是800毫秒那server超时配3到5秒是合理的。如果后端有批量导出、报表生成这类长时间任务就得单独拉长甚至配到60秒以上。很多团队在同一个haproxy前端混跑多种业务后端接口有快有慢这时候用不同的backend分组来区分超时而不是全局统一一个值。2.2 timeout client和长连接场景的特殊处理timeout client针对的是客户端到haproxy之间的空闲时间。普通网页请求几秒钟就够了。但如果客户端是App、小程序这类移动端网络切换频繁空闲时间可能比较长建议至少配30到60秒。这里有个特别容易踩的坑WebSocket长连接。WebSocket建立连接后客户端和服务器之间可能会长时间没有数据交互但这个连接是正常的。如果你把timeout client配成30秒WebSocket连接一空闲就会被haproxy干掉。处理方式有两种一是对WebSocket路径单独配置一个backend把超时拉长到300秒以上二是用timeout tunnel参数专门处理升级为隧道模式的连接。2.3 timeout tunnel容易忽略但关键时刻救命timeout tunnel是我特别想强调的一个参数。它适用于连接升级为隧道模式的场景典型的就是WebSocket、SSL加密传输、CONNECT请求。连接一旦进入隧道模式timeout client和timeout server就不再生效取而代之的是timeout tunnel。默认情况下如果你没配timeout tunnelhaproxy会使用timeout client的值。对WebSocket业务来说这个默认值往往太小。我见过一个线上事故在线客服系统用的WebSockethaproxy的timeout client配的60秒结果用户挂着客服页面超过60秒没说话连接就被断了消息收发全部失败。后来把所有WebSocket路径的timeout tunnel配到3600秒问题彻底解决。3. 超时参数速查表与常见配置误区整理了一个我自己经常参考的参数速查表方便大家快速对照参数作用阶段推荐初始值适用场景timeout connecthaproxy连接后端服务器3-5秒同机房内网建议3秒跨机房5-10秒timeout client客户端到haproxy空闲超时30-60秒普通HTTP请求移动端建议60秒timeout serverhaproxy到后端服务器空闲超时根据接口P99×3-5倍核心接口建议单独设置timeout check健康检查探测超时2-3秒配合interval使用不宜过大timeout http-request等待完整HTTP请求头5-10秒防慢速攻击一般不用太大timeout tunnel隧道模式空闲超时3600秒WebSocket、SSL透传场景3.1 全局配置还是frontend/backend单独配置很多初学者会问超时参数到底写在哪一层答案是都可以但作用范围不同。写在defaults段里是全局默认值所有frontend和backend都会继承。写在frontend段里只对入口生效写在backend段里只对后端生效。我个人的习惯是defaults里放一套保守的通用值保证所有服务都能跑起来然后对特殊的backend单独覆盖。比如默认server超时配10秒但批量导出接口的backend单独覆盖成120秒。这样既保证了通用性又避免了“一刀切”误伤特殊业务。3.2 超时配太小和太大分别会有什么后果超时配太小直接后果就是正常的慢请求被误杀。数据库在凌晨做批处理时CPU飙高接口响应慢了几秒结果连接直接被haproxy断开客户端收到504。这种问题通常不是每天出现但一旦出现就影响一批用户排查起来还特别费劲因为日志里只能看到“connection timed out”无法直接定位是haproxy断的还是后端断的。超时配太大问题更隐蔽。连接长时间占用haproxy的并发连接数一直降不下来内存持续增长。最危险的是后端服务器假死——进程还在但已经无法处理新请求haproxy还在傻等旧连接超时释放。这种情况如果配合了健康检查还能通过检查机制摘除故障节点如果健康检查也没配好整条链路就悬了。4. 负载均衡算法选型别只会用roundrobin聊完超时进入第二个核心负载均衡。haproxy默认的负载均衡算法是roundrobin也就是轮询。轮询的优点是简单公平每个后端请求数基本一致。但轮询有一个天生的问题它不考虑后端服务器的当前负载和处理能力。如果两台机器配置不一样一台8核一台4核轮询会让两台机器接收同样多的请求4核那台就会先扛不住。那什么时候用哪种算法我按自己实战经验总结如下。4.1 等开销负载均衡leastconn解析leastconn这个算法直译是“最少连接”我习惯叫它“等开销”策略因为它的核心思想是谁当前的活跃连接少就把新请求发给谁。这个算法特别适合处理长连接和请求处理时间差异大的场景。举个具体的例子你的后端是两台数据库代理一条SQL可能执行1毫秒也可能执行3秒。如果用轮询两台代理理论上收到的请求数一样但A机器可能一直分到慢SQL连接一直被占着B机器却闲得没事干。改用leastconn之后haproxy会实时检查两台机器的连接数把新请求分给连接少的那台整体资源利用率明显提升。4.2 source、uri、hdr会话保持类算法什么时候用source算法按客户端IP做哈希同一个IP的请求永远打到同一台后端适合需要会话保持的场景比如传统的Session登录态。但副作用也很明显如果某个IP后面是公司出口网关大量员工共用同一个IP流量会全部堆到同一台机器。所以现在微服务架构下source算法用得越来越少了。uri算法则是对请求的URI做哈希适合做缓存服务的前置负载。比如后端是多台Redis缓存或者多台Nginx缓存节点同一个资源的请求始终打到同一台能提高缓存命中率。hdr算法可以对指定的请求头做哈希比如按用户ID做哈希实现按用户维度的会话保持。4.3 haproxy和nginx负载均衡的差异与取舍说到负载均衡很多人会问haproxy和nginx到底怎么选我的理解是两者并不是替代关系而是分工不同。haproxy更擅长四层TCP/UDP负载均衡性能极高单机可以支撑几十万并发连接配置模型也更贴近网络层。nginx更擅长七层HTTP负载均衡内置了缓存、gzip、反爬、限流、SSL终止等Web层功能。如果你的场景是给数据库、Redis、MQ做代理或者要做海量TCP长连接接入haproxy是第一选择如果是对HTTP API做路由分发、需要丰富的HTTP处理能力nginx更顺手。很多大厂的真实架构是两层配合haproxy在最前面做四层流量入口把流量转发给后端的nginx集群nginx再按域名或路径分发给具体的业务服务。这种架构充分利用了haproxy的高并发优势和nginx的HTTP处理能力各司其职。4.4 balance参数配置实例haproxy里配置负载均衡算法非常简单在backend段里用balance关键字指定即可backend web_servers balance leastconn server web1 192.168.1.10:8080 check inter 3s fall 3 rise 2 server web2 192.168.1.11:8080 check inter 3s fall 3 rise 2这里balance leastconn表示使用最少连接算法。如果注释掉这行haproxy默认就是roundrobin。对多数HTTP短连接场景roundrobin其实够用但如果后端是长连接、慢接口居多强烈建议换成leastconn效果立竿见影。5. 一个完整的多场景haproxy配置实例空谈理论没有用我直接给出一份我实际在用的多场景配置模板包含了超时参数、健康检查、负载均衡算法和状态页。这个模板可以直接跑改改IP和端口就能用。5.1 配置逐段解读global maxconn 50000 log 127.0.0.1 local0 info nbproc 4 pidfile /var/run/haproxy.pid defaults mode http timeout connect 5s timeout client 60s timeout server 30s timeout http-request 10s timeout check 3s option httplog option dontlognull option redispatch retries 2 frontend http_front bind *:80 stats uri /haproxy-status stats auth admin:password123 acl is_ws hdr(Upgrade) -i websocket use_backend ws_back if is_ws default_backend web_servers backend web_servers balance leastconn server web1 192.168.1.10:8080 check inter 3s fall 3 rise 2 server web2 192.168.1.11:8080 check inter 3s fall 3 rise 2 backend ws_back timeout tunnel 3600s timeout server 3600s timeout client 3600s balance leastconn server ws1 192.168.1.20:8080 check inter 5s fall 3 rise 2 server ws2 192.168.1.21:8080 check inter 5s fall 3 rise 2这份配置里有几个细节值得注意。defaults里我故意把timeout server配成了30秒因为web_servers里绝大部分接口都在1秒内返回30秒足够宽松又不会把异常接口拖太久。ws_back这个backend单独把tunnel、server、client三个超时都拉到了3600秒就是为了让WebSocket长连接不被误杀。5.2 健康检查参数inter、fall、rise的含义好多人看配置时对check inter 3s fall 3 rise 2感到困惑。拆开理解inter是健康检查的间隔时间每3秒检查一次fall是连续失败多少次标记后端为不可用这里3次也就是9秒内连续失败才摘除rise是连续成功多少次标记后端为恢复可用这里2次也就是6秒内恢复正常就重新上线。这几个值的搭配要注意inter太小健康检查本身会占资源fall太小网络一抖动后端就被摘除流量突然全部打到其他机器容易引发雪崩。我的经验是对普通的HTTP服务inter 3秒、fall 3次、rise 2次是比较稳妥的组合。对数据库这类重量级后端建议inter 5秒、fall 4次、rise 3次更保守一些。5.3 状态页如何辅助排查负载均衡是否生效配置里我开了stats uri /haproxy-status访问http://你的haproxy地址/haproxy-status输入配置的账号密码就能看到实时状态页。这个页面非常直观可以看到每个后端的当前连接数、会话总数、健康状态、流量统计等。我排查线上问题时第一件事就是打开状态页看后端的qcur和scur两个指标。qcur是当前排队请求数如果一直是0说明后端处理能力充足如果持续上涨说明后端已经忙不过来了需要扩容。scur是当前会话数配合leastconn算法这个数字在每台后端上应该大致均衡如果发现某台机器scur明显偏高说明流量分配出了问题。6. 超时与负载均衡的常见问题排查实录这部分我整理了实际工作中最常遇到的几类故障每条都是踩过坑总结出来的经验。我见过太多人遇到504先怀疑后端代码其实问题出在haproxy超时配置上既浪费时间又消耗精力。6.1 504 Gateway Timeout优先排查server超时现象是客户端调用接口经常报504但后端日志显示请求实际执行成功了。这种情况十有八九是timeout server配小了。后端接口的真实耗时超过了server超时haproxy等不及先断开了连接但后端还在继续执行最终数据库被重复执行了多次。解决方法是先看后端接口的耗时分布如果P99是2秒server超时至少配到6到10秒。另外如果是偶发的慢查询除了调大超时更合理的做法是优化SQL或者增加缓存不能一味靠调大超时掩盖问题。6.2 连接频繁断开检查keepalive和tunnel超时普通HTTP场景下如果客户端频繁出现“Connection reset by peer”检查两个地方haproxy的timeout http-keep-alive是否设置合理以及客户端是否有复用连接的习惯。HTTP keep-alive的超时时间决定了空闲连接在haproxy上保留多久如果设得太短连接频繁被关闭客户端每次都要重新建立TCP连接握手开销剧增。WebSocket场景下连接频繁断开基本就是timeout tunnel没配置或者配得太小。我排查过一个案例在线聊天室连接每60秒准时断一次原因就是timeout tunnel继承了defaults里的timeout client 60s。把ws_back的timeout tunnel改成3600s之后问题消失。6.3 健康检查误报调大fall和inter即可解决后端服务本身稳定运行但haproxy状态页上显示后端被标记为DOWN流量被切走。这种误报的根本原因是健康检查过于敏感inter间隔太短或者fall次数太少。比如某台机器发生了一次GC停顿耗时超过了check的响应时间连续两三次检查失败节点就被摘除了。我的建议是对健康检查的宽容度要高一些。毕竟haproxy摘除节点是为了保护整体可用性而不是为了精确反映单机的瞬时状态。inter 5秒、fall 4次以上能过滤掉大部分偶发抖动。如果后端启动时间较长还可以配一个slowstart参数让恢复的节点慢慢接入流量防止瞬间涌入的请求把刚启动的服务打爆。6.4 单机流量不均负载均衡算法选错了状态页上能看到某台后端连接数特别高其他几台几乎空闲。这种情况先确认balance算法是什么。如果是roundrobin请求数应该是均衡的如果请求耗时差异大连接数就会明显不均这时换成leastconn能看到立竿见影的效果。还有一种情况是源站开启了会话保持导致同一个用户的请求一直打到同一台机器。这种不均匀是业务需求导致的不能用算法去调整只能从业务层面改造比如把会话状态迁移到分布式缓存里。6.5 大流量下服务雪崩为每个后端加上慢启动最后讲一个比较少人注意但很关键的点后端节点恢复上线时的流量陡增问题。某台后端因为故障被摘除恢复后重新加入集群haproxy会立刻把流量分配给它。如果这台机器刚启动还没完成缓存预热大量请求突然涌入很容易再次被打挂形成“恢复-挂掉-恢复-挂掉”的循环。解决办法是在server配置里加slowstart参数server web1 192.168.1.10:8080 check inter 3s fall 3 rise 2 slowstart 60s这样节点恢复后haproxy会在60秒内逐步增加分配给它的连接数给它充分的预热时间。这个参数在生产环境的价值非常大强烈建议加上。7. 超时配置和负载均衡的联动思考超时配置和负载均衡算法表面上是两件事实际是深度联动的。最典型的就是leastconn算法它依赖连接数来判断后端负载。如果超时配得过大慢请求会长时间占用连接连接数虚高leastconn会把新请求都分给其他机器造成新的不均衡。反过来如果超时配得太小慢请求被频繁断开客户端就会反复重试放大了对后端的压力。我见过一个非常典型的案例某服务用leastconn做负载均衡后端某台机器出现慢查询连接数一路飙升。haproxy发现这台机器连接数高就把新请求全部转发给其他机器结果其他机器也被慢查询拖垮。最后所有机器连接数都爆了整个集群雪崩。这个案例的根因是超时没有兜底慢查询一直占着连接不释放。如果当时timeout server配得合理一些连接会在到达上限前被强制断开至少能保住部分机器的可用性。所以我的结论很简单配超时和选算法必须放在一起通盘考虑。每次调整负载均衡算法都应该同步审视超时配置是否匹配。维护一个生产级的haproxy入口需要把这些参数当成一个整体来治理而不是孤立地调某一个值。8. 在线调优技巧无需重启即可生效最后分享一个提升幸福感的小技巧。haproxy支持热加载配置修改完配置不需要重启服务用下面的命令就能平滑加载haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)这个命令会启动一个新的haproxy进程加载新配置再把旧进程优雅关停。整个过程对客户端完全透明不会有连接中断。我调超时参数的时候全靠这个命令改完立即生效方便极了。但要注意一点热加载之前最好用haproxy -c -f /etc/haproxy/haproxy.cfg先校验一下配置文件的语法避免加载了错误的配置导致全线故障。这是非常低成本的护身符我每次改配置都会先跑一遍。在实际操作中我还会配合状态页观察热加载后的变化确认新的参数是否产生了预期效果。有一次我把timeout server从30秒改成10秒热加载后明显看到连接数下降说明很多慢请求不再被haproxy长时间占用整体吞吐反而上去了。这种调优的反馈几乎是即时的让人很有成就感。
返回列表