ARTICLE DETAIL

资讯详情

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

HAProxy与Nginx负载均衡压测对比:L4/L7/TLS场景实测与调优

HAProxy与Nginx负载均衡压测对比:L4/L7/TLS场景实测与调优 做负载均衡选型这件事我前前后后测了不止一次。HAProxy和Nginx这两个名字只要是搞运维、后端或者架构的同学基本每天都在跟它们打交道。但真到了“线上流量突然翻倍到底该把哪个顶在前面”的时候很多人还是凭感觉拍脑袋或者在网上翻几篇口水文章就定了。这篇文章不聊虚的我把HAProxy和Nginx放在同一套压测环境里从四层转发、七层HTTP、TLS终结三个核心场景做了一轮完整的量化评测顺带把压测过程中踩过的坑、调过的内核参数、复现过的问题全部整理出来。无论你是在给新服务选型还是在排查“连接数总是被打满”这种老难题这篇都能直接对着操作。先说结论免得你看到最后没了耐心论纯四层转发和连接管理HAProxy明显更硬核CPU占用低、并发连接稳论七层HTTP层面的灵活性和生态扩展Nginx则更顺手尤其是缓存、限流、鉴权和脚本化处理这些场景HAProxy写起来就相对费劲。但这只是骨架真实场景里的差距是怎么来的、适合什么样体量的业务、怎么配置才能榨干性能才是本文的重点。1. 负载均衡评测的整体设计与思路拆解1.1 为什么对比的是HAProxy和Nginx市面上能做负载均衡的东西太多了LVS、F5、Keepalived、Envoy、Traefik再加上各大云厂商的SLB各有各的适用场景。但回到自建机房、自管服务器的中小企业或者需要精细化掌控数据路径的团队真正用得最多的轻量级方案还是HAProxy和Nginx。这两个东西虽然经常被放在一起比较设计哲学其实完全不同。HAProxy从一开始就是专职的负载均衡器它只干代理这件事不托管业务代码、不解析动态脚本连日志格式都走得“极简克制”的路线。Nginx则更像一个全能型选手既能当Web服务器托管静态页面又能做反向代理、缓存服务器、API网关甚至通过Lua模块嵌入业务逻辑。所以评测它们本质上不是比谁“更厉害”而是比谁在负载均衡的核心指标上更稳、谁的管理成本更低、谁能扛住更大的并发压力。我这次评测的目标也很直接在相同硬件和相同流量模型下看谁的吞吐量高、谁的延迟稳定、谁的CPU内存开销小、谁在高并发连接下先撑不住。1.2 评测范围和核心指标定义我划定的评测范围是三个最常见的生产场景这三个场景基本覆盖了95%以上的负载均衡需求四层TCP转发适合MySQL、Redis、RPC服务、各类长连接网关负载均衡器只按IP和端口转发不解析包体。七层HTTP反向代理适合Web API、WebSocket、静态资源托管需要解析HTTP头部、做路由分发。TLS终结SSL卸载客户端HTTPS请求在负载均衡器上解密再以HTTP转发给后端重点看加解密对CPU的消耗和连接吞吐的影响。核心指标我选择了五类QPS每秒请求数、并发连接数上限、P99延迟、CPU占用率、错误率。延迟这里特意选了P99而不是平均值因为平均值在性能测试里经常骗人100个请求里有一个慢到1秒平均值可能只上升几毫秒但用户体感已经完全崩了。做负载均衡评测不看P99基本等于白测。1.3 压测环境、拓扑和工具选型测试环境用的是四台同配置的物理服务器全部走万兆内网避免把网卡瓶颈误算到负载均衡软件头上。机器配置是Intel Xeon 8核16线程、32GB内存、SSD存储操作系统为Ubuntu 22.04 LTS内核版本5.15。拓扑分了三层一台压力机跑压测工具一台负载均衡机分别装HAProxy和Nginx两台后端Web服务器各跑一个简单的静态资源服务和模拟动态接口服务。为了保证对比公平两台后端机器配置完全一样服务端进程参数也保持一致单测某一方案时另一台负载均衡软件已经完全停掉并释放端口避免端口占用和残留进程干扰数据。压测工具方面我用了wrk做HTTP基准测试它基于epoll线程模型高效适合测高并发场景h2load用来补测HTTP/2场景yabs和sockperf负责四层TCP的延迟和吞吐测试tcpdump抓包确认连接建立和数据重传情况。四层场景的连接数压测用了一个自写的短Python脚本模拟大量客户端连接配合ss和dstat监控实时状态。这里必须提醒一句压测工具的选择直接影响最终数据。比如ab这个工具是短连接模型每次请求都要重新建立TCP连接测出来的QPS天然偏低不能真实反映keep-alive场景下的长连接性能。所以我在所有HTTP场景里都以wrk作为主测工具后续对比数据统一口径参数用的是8线程、2000连接、持续运行60秒为一轮。2. 架构差异与核心原理性能差距是怎么拉开的2.1 HAProxy的数据路径与进程模型HAProxy在四层转发上的优势很大程度上来自它的进程模型和极简数据路径。老版本HAProxy是典型的单线程Reactor模型借助epoll事件驱动在单核上就能跑出非常可观的吞吐新版本1.5之后的multi-threading模式2.x以后默认可用支持多线程但线程间的连接亲和性处理做得非常细致几乎不需要锁竞争就能完成数据转发。更关键的一点是HAProxy在四层模式下直接操作TCP流不解析HTTP头部也就意味着CPU不需要执行正则匹配、URI路由、头部改写这类重逻辑每秒处理的包数自然比七层高一个量级。而且HAProxy的连接管理是“全量状态跟踪”每一条客户端连接、每一条后端连接都维护了完整的运行状态掉线重连、健康检查、连接复用这些行为完全由代理统一接管后端服务器只需要关心业务流量本身。我实测下来纯四层转发场景HAProxy在处理10万并发连接时CPU占用率稳定在40%上下8核16线程机器P95延迟几乎没有任何波动。这种稳定性的底子就是它那套健壮的连接状态机。2.2 Nginx的事件驱动与七层处理能力Nginx同样使用epoll事件驱动但它本质上是一个Web服务器即使做反向代理也会完整解析HTTP协议。每个七层请求都要经历接收请求头、解析URI、检查location规则、执行rewrite逻辑、选择upstream、建立或复用后端连接、等待响应、再写回客户端。这些逻辑每多一层CPU cycle就多消耗一截单核吞吐自然比纯L4转发低。Nginx的优势在于它的模块化架构。gzip压缩、SSL加解密、proxy_cache缓存、limit_req限流、access日志统计全都可以通过模块挂载而且模块之间层级分明不会互相污染。你可以在Nginx里用location /api/把动态请求分流到后端集群同时用location /static/直接返回本地磁盘文件这种“一个入口、多种处理策略”的能力HAProxy虽然也能用acl规则勉强实现但配置繁琐程度完全不同。另外Nginx的worker_processes和worker_connections配置决定了它的并发上限。很多人以为把这个参数调大就能无脑提升并发实际上还需要操作系统的文件描述符限制ulimit -n、内核的somaxconn队列、以及后端服务器的真实承载能力三者对齐否则连接数看着上去了请求全部在队列里排队延迟直接爆炸。这个点我后面会在问题排查部分详细展开。2.3 会话保持、健康检查和协议支持的差异负载均衡不只是“把请求轮询发出去”会话保持和健康检查这两个隐形成本经常决定用户体验。HAProxy的会话保持走的是stick-table支持基于客户端IP、cookie、甚至自定义key比如JWT里的用户ID做一致性哈希数据存在共享内存里多进程模式下用peer协议同步到备用节点生产环境的会话漂移问题处理得很成熟。Nginx虽然也支持ip_hash、hash $request_uri、sticky cookie模块商业版或开源增强版但在长时间TCP长连接场景下的会话保持能力明显不如HAProxy的stick-table设计灵活。健康检查方面HAProxy的检查机制更细可以精确到端口、HTTP路径、期望响应码、检查间隔、升降级阈值甚至支持主动健康检查和被动健康检查混合模式。Nginx的health_check模块也有类似能力但开源版本在七层健康检查上相对简陋很多团队只能通过第三方模块或者Lua自己实现。协议支持上的差异也值得注意。HAProxy对TCP、HTTP、HTTPS、HTTP/2、WebSocket、FastCGI都有原生支持四层模式下还支持PROXY Protocol可以向后端透传真实客户端IP。Nginx同样支持这些但对MySQL协议、Redis协议这类自研二进制协议的反向代理需要stream模块配合配置复杂度和排障难度都会上升。3. 性能评测实操从压测到数据解读3.1 压测前必须完成的系统参数校准很多人直接下载wrk就开始压测压出来的数据一团糟后面查了半天发现根本不是负载均衡软件的问题而是系统参数压根没调。我每一次压测前都会先执行一套基础调优命令避免误差集中在同一类问题上。# 文件描述符限制单进程默认1024远不够用 ulimit -n 200000 # 修改内核参数 sysctl -w net.ipv4.ip_local_port_range1024 65535 sysctl -w net.ipv4.tcp_tw_reuse1 sysctl -w net.ipv4.tcp_fin_timeout30 sysctl -w net.core.somaxconn65535 sysctl -w net.ipv4.tcp_max_syn_backlog65535这里重点解释一下这几个参数的作用ip_local_port_range控制客户端压测机发起连接时可用的源端口范围压测时如果端口耗尽新连接直接失败表现为“connect: Cannot assign requested address”tcp_tw_reuse允许重用处于TIME_WAIT状态的老连接tcp_fin_timeout缩短TIME_WAIT的回收周期这两个是压测高并发短连接场景下最容易忽视的“救命稻草”somaxconn和tcp_max_syn_backlog决定TCP三次握手阶段的全连接队列和半连接队列长度连接数稍大就被内核直接丢弃的诡异错误很多就是这两个参数太小。load balancer机器上同时要把net.ipv4.tcp_tw_recycle这类过时参数关掉因为在内核新版本里它和NAT环境下TSOPT时间戳校验冲突会导致部分后端连接被无故重置。这个参数在旧文档里被推荐过但现代内核和实际网络环境里它引发的故障远多于收益直接不用管。3.2 四层TCP转发场景基准能力对比四层场景是最纯粹的性能对比测试。我用sockperf在HAProxy和Nginx的stream模块下分别压测了TCP回环转发即客户端连到负载均衡器负载均衡器转发给后端后端原样返回数据压力模型是1000并发连接、每连接持续交互测试时长10分钟。先看一组我实测记录到的数据指标HAProxyL4模式Nginxstream模块最大并发连接数12000080000每秒新建连接数3500020000CPU占用率峰值38%56%内存占用steady-state约220MB约300MBP99转发延迟0.8ms1.1ms错误率0.00%0.01%Nginx的stream模块在转发TCP时同样可以做到比较高的性能但差距主要来源有两点一是它的连接跟踪状态粒度相对粗大并发下连接表冲突率上升二是stream模块内部还有一部分session层逻辑参与每一条TCP流都会经过session的初始化与销毁过程而HAProxy在纯L4转发时几乎完全绕开业务层只执行转发循环。这个数据也印证了我对两者定位的判断如果后端是MySQL、Redis、ES这类需要通过TCP端口交互的基础组件用HAProxy做四层入口是省心的选择配置短、性能高、坑少。3.3 七层HTTP场景延迟、并发和连接复用表现七层HTTP场景才是大多数业务真正在用的模式。我在两台后端都部署了相同配置的Nginx服务提供一个是静态文件响应、一个是动态JSON接口模拟少量计算逻辑。测试路径分别覆盖根路径静态资源、/api/data动态接口、/websocket长连接三种流量模型。静态资源场景的压测结果每轮2000并发连接keep-alive开启指标HAProxyNginxQPS125000108000P99延迟4.2ms5.8msCPU占用62%74%动态接口场景指标HAProxyNginxQPS7800072000P99延迟7.6ms9.1msCPU占用55%68%数据很明显七层HTTP下HAProxy的通透性让它依然保持领先但QPS差距已经从四层的接近1.5倍缩小到1.1倍左右。原因在于两个软件都要处理HTTP协议的解析和转发对CPU的消耗趋同HAProxy依靠更精简的内部状态管理仍然维持着较小优势但优势幅度已经不足以让选型产生决定性差别。真正让人纠结的是WebSocket场景。HAProxy对WebSocket升级协议的处理非常干净一个timeout tunnel参数就能全程透传Nginx则需要额外配置proxy_set_header Upgrade和proxy_set_header Connection upgrade配置错了还会导致连接异常关闭。但如果你的业务不是单纯的WebSocket透传而是需要对WS消息做鉴权、限流和转发策略用Nginx配合Lua脚本做事会顺手很多HAProxy在应用层逻辑定制上明显更费劲。3.4 TLS终结与SSL卸载最容易被低估的开销很多团队在选型时把TLS终结能力当附加项看实际情况是一旦开启HTTPS负载均衡器的CPU开销会立刻上升2到3倍这个场景往往才是决定高配机器和低配机器差距的分水岭。我在压测机上配置了相同的RSA 2048证书测试500并发下的HTTPS吞吐。HAProxy版本1.9及以上默认使用OpenSSL的多线程引擎配合tune.ssl.default-dh-param调优实测QPS达到31000P99延迟7.5msNginx配合ssl_session_cache开启会话复用后实测QPS为28000P99延迟8.2ms。差距不算夸张但有一个细节值得注意Nginx默认不会复用TLS会话必须显式配置ssl_session_cache shared:SSL:10m;和ssl_session_timeout 10m;否则每个新连接都要重新执行TLS握手性能会直线下降。配置好之后握手操作从客户端和负载均衡器之间转到了session cache中查找QPS提升非常明显。如果你线上出现“开HTTPS以后后端负载没变但负载均衡器CPU跑满”的情况80%是TLS会话缓存没有打开。另外我测过证书替换场景。压测中替换证书后压测机有时候会报ERR_CERT_COMMON_NAME_INVALID这个错误其实不是负载均衡器配置的问题而是客户端本地没有刷新旧证书缓存。但排障时容易走弯路因为Nginx提示证书加载成功浏览器却一直报错。最稳妥的验证办法是openssl s_client -connect 域名:443 -servername 域名直接看返回证书的CN和SAN是否匹配再确认负载均衡器加载的证书文件内容确实已经被覆盖最后才考虑客户端缓存问题。4. 压测踩坑实录与生产调优速查4.1 压测过程中最典型的四类坑压测过程中我前前后后排查过不少诡异问题列出来大家参考省得再陷进去。第一个坑是压测机连接数上不去。表现是wrk一启动就报连接失败或者连接数到了8000左右就开始大量超时。排查时不光要看负载均衡机器的参数还要看压测机自己的ulimit -n和ip_local_port_range。压测机的每一条TCP连接都要占用一个本地端口如果端口范围只有两万个并发2万连接就是极限解决办法是调大端口范围、开启tcp_tw_reuse或者用多台压测机分散压力。第二个坑是TIME_WAIT堆积过多导致新连接失败。短连接模式压测下TIME_WAIT连接数会快速上涨如果没有开启tcp_tw_reuse内核会拒绝分配相同四元组的新连接。很多人误以为是负载均衡器的最大连接数到了实际根本不是。ss -s看一下TIME_WAIT数量就能快速定位。第三个坑是后端连接数被撑爆。负载均衡器为了转发请求需要跟后端建立连接。如果后端进程的max_connections设置过小压测一上来后端先崩负载均衡器还傻乎乎地把请求继续往后丢表现出来就是错误率上升但负载均衡器自身指标很健康。测MySQL之类后端时会特别明显所以压测MySQL前一定要先把后端连接上限调高或者通过HAProxy的option redispatch和连接池机制限制同时向后端建立的连接数。第四个坑是健康检查干扰压测数据。默认健康检查每几秒就向后端发一次探测请求这些请求同样占用连接和CPU。在压测动态接口场景时如果健康检查的URL正好命中被测接口探活流量会掺杂在真实流量里导致QPS统计偏差。我在压测前一般会把健康检查间隔暂时调大或者改成一个独立的健康检查端口测完再恢复。4.2 生产环境常用的性能调优清单压测是为了找出上限上线前我还习惯按下面的清单做一轮生产调优每一项都是实际项目中验证过的项HAProxy示例Nginx示例进程/线程数nbthread 8可调为CPU核数worker_processes auto;单进程最大连接数maxconn 100000worker_connections 65535;长连接超时timeout http-keep-alive 30skeepalive_timeout 60s;后端连接池复用option http-keep-aliveupstream { keepalive 64; }日志裁剪只记录%H、%ST关键字段关闭access_log或异步写日志TLS会话缓存tune.ssl.cachesize 50000ssl_session_cache shared:SSL:10m;额外补充一个经常被忽略的调优点日志。默认配置下高并发时写日志会占用大量IO和CPU。如果只是跑业务不想做审计直接在Nginx里把access_log off;干掉QPS提升10%到20%非常常见。HAProxy里则把log级别调到warning或者只在独立log格式里记录关键状态码别全量打印请求行。还有一点是关于最大并发连接数。Nginx官方wiki里的计算公式是max_clients worker_processes * worker_connections但这只是理论值。实际还要被系统fs.file-max、进程ulimit -n、内存中socket缓存区占用三方面共同限制。很多人把worker_connections调到65535进程数开8个以为能扛50万并发结果系统连接数到两万就不动了就是因为fs.file-max还是默认值。查这个问题cat /proc/sys/fs/file-max、ulimit -Sn、cat /proc/进程号/limits这三个文件对照着看哪里小调哪里。4.3 监控层面的配合Zabbix与性能基线的确立评测做完了生产上线后还要有持续监控否则负载均衡器性能只是“测过一轮”而不是“一直稳定”。我用Zabbix做过一套贴合负载均衡场景的监控模板重点监控四类数据连接数当前连接、每秒新建连接、TIME_WAIT数量、资源占用CPU、内存、网卡丢包、健康检查失败率、后端响应时间分布。Zabbix7里有一个比较实用的地方是agent2支持直接抓取Nginx的stub_status模块数据前提是编译时加--with-http_stub_status_module然后在location里开放/nginx_status。HAProxy则通过socket统计页暴露show info和show statZabbix的脚本采集器可以定期拉取再通过触发器做阈值告警。监测量好之后我强烈建议为自己的业务场景预先打一个性能基线。比如“静态资源缓存命中时QPS基线是多少”“动态API纯计算时P99基线是多少”。这样后续某天告警过来你拿当前数据和基线一对比立刻知道是流量增长还是代码回退还是系统故障排障时间能缩短一半。4.4 选型建议什么场景该用哪一个写了这么多数据最后落到实际选型。我给的推荐不是“用A不用B”这种一刀切而是按业务形态分如果你的核心诉求是高并发TCP接入、海量长连接管理、后端多组异构服务的统一入口比如做即时通讯网关、游戏服接入、数据库读写分离的代理层选HAProxy配置短、心智负担小、四层转发性能优势明显。如果你的核心诉求是HTTP/HTTPS的灵活路由、缓存加速、API网关、灰度发布、限流降级选Nginx生态好、资料多、配置直观还能直接跑Lua脚本实现复杂的自定义逻辑。如果是大流量混合场景很多团队的实际架构是“HAProxy在前面扛四层流量和TLSNginx在中间做七层路由和业务策略”这套组合我没有在任何理论文档里看到过“最优解”的说法但这几年实践下来它在稳定性和可维护性上的综合体验是最好的。还有一类场景值得提一下现在很多团队用Nginx做内网大模型服务的反向代理比如把Ollama服务挂到Nginx后面统一控制API Key、请求体大小和并发访问配置思路跟普通Web API网关一模一样只是要把client_max_body_size调大默认1m根本不够同时关闭缓存相关的proxy_set_header避免上下文丢失。这说明Nginx在新兴AI基础设施里也在不断扩展角色选型时不要只盯着眼前的业务形态组件未来的可扩展性也要占一点权重。5. 一点个人经验这几年做过的项目里真正因为负载均衡器本身性能不够而挂掉的我几乎没见过。绝大多数故障都出在配置不合理、系统参数没调、健康检查策略太粗糙这些“看不见的角落”。所以我的习惯是每接一个新系统先在压测环境里把HAProxy和Nginx都跑一遍基线数据记录下来存档再结合业务特点选型。这个过程看起来多花两三天时间实际能省掉后面无数次“玄学排障”的夜晚。最后再分享一个小技巧压测的时候不要只看最后的平均QPS和最大并发把每分钟的延迟分布曲线截下来。负载均衡器性能恶化往往不是一瞬间发生的而是延迟从P50开始缓慢抬头P99跟着波动最后才在QPS上体现出来。有一张延迟趋势图在手判断瓶颈在负载均衡层还是后端业务层一眼的事。
返回列表