Nginx四层负载均衡必须使用stream模块,配置需置于根层级、独立于http块,且须提前加载ngx_stream_module.so;不支持HTTP健康检查,仅依赖TCP连接结果判断后端状态。

nginx 的四层负载均衡必须用 stream 模块,不是 http 块里那套配置。如果你在 http 块里写 upstream + proxy_pass 去转发 MySQL 或 Redis 流量,它根本不会生效——那是七层逻辑,只认 HTTP/HTTPS。
确认 nginx 已加载 stream 模块
运行 nginx -V 2>&1 | grep -o with-stream,如果没输出,说明模块未编译启用。
Ubuntu/Debian 默认安装的 nginx-full 或 nginx-extras 包含该模块;CentOS/RHEL 需装 nginx-mod-stream(RPM 包),或源码编译时加 --with-stream 参数。
若缺失,重装或补加载:load_module modules/ngx_stream_module.so; 必须放在 nginx.conf 最顶部(在 events 块之前),否则启动会报错 unknown directive "stream"。
stream 块配置不能放在 http 块里
stream 是和 http、events 同级的顶层块,必须直接写在 nginx.conf 根层级,常见错误是把它塞进 http { ... } 里——这样 nginx 会直接拒绝启动,报错 directive is not allowed here。
正确结构示例:
load_module modules/ngx_stream_module.so;
events {
worker_connections 1024;
}
stream {
upstream db_cluster {
server 192.168.1.10:3306 weight=3;
server 192.168.1.11:3306 max_fails=2 fail_timeout=10s;
server 192.168.1.12:3306 backup;
}
server {
listen 3306;
proxy_pass db_cluster;
proxy_timeout 5s;
proxy_connect_timeout 1s;
}
}
注意:upstream 名称(如 db_cluster)不能和 http 块里的同名冲突;proxy_timeout 控制空闲连接超时,不是后端响应超时(四层无“响应”概念,只有连接生命周期)。
四层健康检查靠 TCP 连通性,不支持 HTTP 探针
stream 模块没有 health_check 指令,max_fails 和 fail_timeout 仅在客户端发起连接时触发:当 nginx 尝试向某后端建连失败(如拒绝连接、超时),才计一次失败;它不会主动发心跳包。
这意味着:
- 后端进程僵死但端口仍监听(如 MySQL crash 后 mysqld 退出但端口被其他进程占着),
max_fails不会触发剔除 - 后端防火墙静默丢包(SYN 不回 ACK),连接超时后才会标记失败
- 没有类似七层的
http_404或http_503状态码判断逻辑
真实生产环境建议配合外部工具(如 keepalived + check_mysql 脚本)做主动探活,或让应用层实现连接池自动熔断。
日志格式和调试要单独配,不继承 http 日志
stream 模块的日志完全独立,log_format 必须在 stream 块内定义,且变量名不同:$remote_addr 可用,但 $status 是连接结果(1xx 表示成功建立,5xx 表示代理失败),$upstream_addr 记录实际转发目标,$session_time 是本次连接持续秒数。
漏配日志会导致排障困难——比如流量没转发过去,你只能靠 tcpdump 抓包,而没法从日志快速定位是 DNS 解析失败、连接超时还是上游全挂了。
load_module 就启动失败,没 stream { log_format ... } 就等于盲跑。别指望复用 http 的经验,TCP 层的“连接”和 HTTP 层的“请求”是两套生命模型。


















