Nginx和HAProxy如何配合使用?七层代理与四层转发架构解析

很多中小团队在做网站架构时,会把 Nginx 放在最前面,再用它反代到后端的 Tomcat、Node 或者 PHP-FPM。这套结构在几百并发以内工作得很好,但一旦业务增长、后端机器从一台变成一排,问题就出现了:Nginx 自己既要处理静态资源,又要做负载均衡,还要扛 SSL 握手,CPU 最先撑不住的往往不是业务,而是这台入口机。这时候很多人会听到"上 HAProxy 做四层"这句话,于是又有了一层新的组件,但到底谁放前面、谁放后面、为什么不是只用其中一个,就说不清楚了。

这篇文章要解决的问题就是:Nginx 和 HAProxy 到底各自擅长什么,为什么很多架构会把两者叠在一起用,四层转发和七层代理在行为和适用场景上有什么本质区别,以及在什么规模下才值得引入 HAProxy。读者读完应该能自己判断"我的业务现在需不需要两层代理""如果要加,HAProxy 该放在 Nginx 前面还是后面"。

文章会先讲清四层与七层的原理差异,再用一张表格对比两者能力边界,然后给出几种常见的组合架构,最后落到真实的配置片段和压测观察方式。涉及的数值都是经验值,用来建立量级概念,不代表任何具体硬件的承诺。

一、先分清"四层"和"七层"到底在说什么

网络分层里,四层指传输层(TCP/UDP),七层指应用层(HTTP/HTTPS 等)。代理工作在几层,决定了它"看不看得懂"流量内容。

四层代理只认 IP 和端口,收到 TCP 连接后原样把字节流转发出去,它不解析 HTTP 报文头,不知道你请求的是 /api/user 还是 /static/a.css,也不知道 Host 头是什么。它的优势是快、连接消耗低:因为没有解析和重组报文,一个连接可以从头转发到尾,CPU 开销小,单机能扛的连接数非常高。四层代理的典型代表就是 LVS(内核态)和 HAProxy 的 mode tcp。

七层代理要解析 HTTP,能读到 URL、Host、Header、Cookie,于是可以做基于路径的路由、基于域名的虚拟主机、改写请求头、压缩、缓存、限流等。代价是它需要维护更多状态、按请求而非按连接处理,CPU 和内存开销明显更大,能支撑的并发量相对更低。Nginx 的 proxy_pass、HAProxy 的 mode http 都属于七层。

一个直观的类比:四层代理像"电话总机",只管把线接到某个分机,不管你们聊什么;七层代理像"前台接待",会听你说是来找谁、办什么事,再决定把你领到哪个部门。总机接线快、成本低,前台会得多但更忙。

二、Nginx 与 HAProxy 的能力边界对比

虽然两者都能做负载均衡,但设计侧重点不同。HAProxy 是"专职负载均衡器",把代理做到极致;Nginx 是"Web 服务器兼代理",反代只是它众多功能之一。下表是常见能力的对照,帮助你判断该用哪个。

能力维度 HAProxy Nginx
定位 专职四层/七层负载均衡 Web 服务器 + 反向代理
四层转发性能 极高,单机数十万级并发连接(经验值) 高,但同类场景下通常略逊
七层功能丰富度 强,健康检查、统计页、ACL 很完善 强,但配置表达相对繁琐
静态文件服务 不擅长(本就不是它的活) 擅长,可带 sendfile/缓存
SSL 卸载 支持,性能不错 支持,配合 session 缓存也够用
健康检查 主动式丰富(HTTP 探活、脚本) 被动式为主(max_fails),主动探活需第三方模块
动态扩缩容 运行时 API 可增删后端,无需 reload 改配置需 reload
统计与可观测 内置 stats 页面,指标细 需 stub_status 或日志分析
配置热更新 平滑 reload,几乎不丢连接 reload 会有一瞬间的旧连接处理
复杂度 中等,配置项多 低,生态熟悉

一句话概括:比"纯粹转发"和"负载均衡策略",HAProxy 更强;比"Web 内容处理",Nginx 更强。 所以常见做法是让 HAProxy 在前端承担四层转发和大规模连接接入,Nginx 在后端承担七层路由和内容服务。

三、几种常见的组合架构

架构不是越复杂越好,选哪种取决于规模和需求。

架构 A:只有 Nginx(最常见)

客户端 → Nginx(七层反代 + 负载均衡)→ 多台后端应用

适合单机入口带宽和并发没到瓶颈的场景。中小站点、日活几千到几万,单台 Nginx 通常足够。优点是简单,缺点是入口 CPU 被 SSL 和静态资源吃掉,后端扩容到十几台后 Nginx 成为单点。

架构 B:HAProxy 在前,Nginx 在后(经典双层)

客户端 → HAProxy(mode tcp,四层)→ 多台 Nginx(七层)→ 多台后端应用

这是"大流量"站点很常见的形态,典型于很多互联网公司的入口。HAProxy 只做四层转发,把流量分给下面一组 Nginx;每台 Nginx 再做七层路由、静态资源、SSL 卸载。好处是:HAProxy 四层转发高效且能承载海量连接,Nginx 水平扩展,单台挂了不影响整体。坏处是多一跳,链路变长,排查问题要跨两层看。

架构 C:HAProxy 做四层 + 七层混合

HAProxy 也可以直接做七层,某些场景直接替代 Nginx 反代。但如果你已经有一堆 Nginx 配置和静态资源,保留 Nginx 做内容层通常成本更低。

架构 D:LVS + Nginx

再往上一层用 LVS(DR 模式,内核态转发)做 VIP 入口,Nginx 做七层。LVS 性能比 HAProxy 四层还高,但配置和运维复杂度也更高,一般到了"单入口扛不住"的体量才会考虑。

选型建议:并发在几千以内、单机可扛,用架构 A;并发上万、需要入口水平扩展和高可用,用架构 B;追求极致转发性能再考虑 LVS。 别为了"看起来专业"提前堆两层,链路越长,出问题时越难定位。

四、一套可用的双层配置示例

HAProxy 四层转发配置

配置文件通常在 /etc/haproxy/haproxy.cfg。下面是一个把 80 端口四层转发给两台 Nginx 的最小示例。

global
    log /dev/log local0
    maxconn 60000          # 全局最大连接数,经验值,按内存和文件句柄调整
    daemon

defaults
    mode tcp               # 四层转发,不解析 HTTP
    log global
    option tcplog
    timeout connect 5s
    timeout client  60s
    timeout server  60s

frontend fe_http
    bind *:80
    default_backend be_nginx

backend be_nginx
    balance roundrobin
    option tcp-check
    server nginx1 10.0.0.11:80 check
    server nginx2 10.0.0.12:80 check

关键点:mode tcp 表示四层;balance roundrobin 是轮询;check 开启健康检查。四层模式下 HAProxy 看不到真实 URL,只能靠 TCP 探活判断后端存活。

后端 Nginx 七层配置

每台 Nginx 上做真正的七层路由。

upstream app_backend {
    server 10.0.1.21:8080 max_fails=3 fail_timeout=10s;
    server 10.0.1.22:8080 max_fails=3 fail_timeout=10s;
    keepalive 32;
}

server {
    listen 80;
    server_name www.example.com;

    location /static/ {
        root /data/www;               # 静态资源直接由 Nginx 返回
        expires 7d;
    }

    location /api/ {
        proxy_pass http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_read_timeout 60s;
    }
}

四层转发时如何拿到客户端真实 IP

这是双层架构最容易踩的坑。HAProxy 做四层转发时,如果只做 TCP 转发,Nginx 看到的来源 IP 会是 HAProxy 的地址,用 X-Forwarded-For 也拿不到真实客户端。解决方案有两种:

一是开启 HAProxy 的 send-proxy 协议,Nginx 对应监听加 proxy_protocol。

server nginx1 10.0.0.11:80 check send-proxy
server {
    listen 80 proxy_protocol;
    set_real_ip_from 10.0.0.10;    # HAProxy 的地址
    real_ip_header proxy_protocol;
}

二是用 transparent 模式,但依赖内核参数和 TPROXY,配置复杂,一般不用。

五、部署与调优命令

安装

# RHEL/CentOS/Rocky
sudo dnf install -y haproxy nginx
sudo systemctl enable --now haproxy nginx

# Debian/Ubuntu
sudo apt update
sudo apt install -y haproxy nginx
sudo systemctl enable --now haproxy nginx

校验与平滑重载

# HAProxy 配置校验,出错会直接报行号
haproxy -c -f /etc/haproxy/haproxy.cfg

# 平滑重载,不中断现有连接
sudo systemctl reload haproxy

# Nginx 同理
nginx -t && nginx -s reload

风险提示:修改 bind 端口、监听地址前,先用 haproxy -c 或 nginx -t 校验;改端口要同步放行防火墙,否则改完立刻全站不通。回滚方式:保留上一份配置备份(如 haproxy.cfg.bak),异常时 cp 回备份再 reload。

# 放行端口示例(注意:改防火墙属危险操作,先确认放行不影响安全策略)
# firewalld(RHEL 系)
sudo firewall-cmd --add-port=80/tcp --permanent && sudo firewall-cmd --reload
# ufw(Ubuntu)
sudo ufw allow 80/tcp

观察与调优

# 看 HAProxy 连接和错误计数
echo 'show stat' | sudo socat stdio /var/run/haproxy/admin.sock | cut -d, -f1,2,5,8,18,19
# NUMCONN/SCUR/STOT 看连接/会话数,EREQ/ECON 看错误

# 看系统连接数和文件句柄
ss -s
ulimit -n
cat /proc/sys/net/core/somaxconn

HAProxy 的 maxconn 受制于系统文件句柄上限。单机几万并发连接时,要把 nofile 提到 65535 以上,并调大 net.core.somaxconn。这些是量级参考,具体值要结合内存实测。

六、什么时候不该引入 HAProxy

引入第二层代理不是零成本,它带来多一跳延迟、多一处故障点、多一套要监控的组件。以下情况建议先用 Nginx:

  • 单入口 Nginx 的 CPU 使用率长期低于 50%,瓶颈不在转发层。
  • 后端应用只有两三台,Nginx 的 upstream 已能覆盖。
  • 团队没人熟悉 HAProxy 配置,出故障时缺少排查能力。
  • 预算有限,不想额外增加运维复杂度和监控成本。

反过来,当出现"入口机 CPU 打满、SSL 握手成为瓶颈、需要入口高可用和频繁动态扩缩容、单机连接数逼近上限"这些信号时,再考虑上 HAProxy 更合理。

常见问题

Q:HAProxy 放前面还是 Nginx 放前面?
看目标。要的是高并发四层接入和负载均衡,HAProxy 放前面;要的是以内容处理为主、入口规模不大,Nginx 放前面就够了。双层时通常是 HAProxy 在最前,Nginx 在后。

Q:两层代理后,日志里拿不到真实客户端 IP 怎么办?
四层转发要用 send-proxy + Nginx 的 proxy_protocol;七层转发则靠 X-Forwarded-For。注意 X-Forwarded-For 可以被伪造,做风控时应以最靠近真实客户端且可信的那一跳为准。

Q:HAProxy 的 mode http 和 mode tcp 怎么选?
需要按 URL/Host 路由、改写头部、做 ACL 判断,用 mode http;只管把 TCP 流量分出去、追求性能和透传,用 mode tcp。四层转发不能识别 HTTP 内容,这是它"快"的代价。

Q:健康检查为什么四层模式下后端挂了还转发?
四层检查只探 TCP 端口是否可连。后端进程还在监听但逻辑已异常时,四层探活仍显示"健康"。这种场景需要七层健康检查或后端自带的 /health 探针配合。

Q:加了一层 HAProxy 后延迟会明显增加吗?
同机房内四层转发增加的延迟通常在亚毫秒级到 1 毫秒量级(经验值),对绝大多数业务无感。真正影响体验的往往是跨机房、跨地域的网络 RTT,而不是这一跳转发。

总结

四层代理认 IP 和端口,快但"看不懂内容";七层代理解析 HTTP,功能强但开销大。HAProxy 擅长四层转发和大规模负载均衡,Nginx 擅长七层路由和内容服务,两者的强项互补,这是双层架构的根本出发点。

典型组合是"HAProxy 四层入口 + 多台 Nginx 七层 + 多台后端",适合入口需要水平扩展和高可用的大流量场景;中小规模用单层 Nginx 即可,不必提前堆复杂度。

四层转发要拿真实客户端 IP,必须用 send-proxy + proxy_protocol,否则 Nginx 只会看到 HAProxy 的地址。

任何改端口、改防火墙、改监听地址的操作都要先校验配置、备份旧配置,并想好 reload 回滚的路径。

是否为业务引入 HAProxy,判断依据是当前入口是不是真瓶颈,而不是"别人都这么架构"。链路越短越好维护,够用就是最优。