说明:
stream {}模块属于四层 TCP 负载均衡,工作在传输层,不解析 HTTP;用来代理 MySQL、Redis、SSH 等 TCP 协议。需要编译 Nginx 时带上
--with-stream,否则不支持 stream 模块;stream{}和http{}同级,不能写在 http 里面!stream upstream 支持策略:轮询、加权轮询、least_conn、ip_hash;不支持 url_hash。
健康检查:原生被动健康检查;主动健康检查需要 Nginx Plus / 第三方
ngx_stream_upstream_check_module。
完整 nginx.conf 示例
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
# ========== stream 四层TCP负载均衡,和http{}同级 ==========
stream {
upstream mysql_cluster {
# 策略:least_conn 最少连接,MySQL推荐!
least_conn;
# MySQL后端节点,端口3306
server 10.0.1.10:3306 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.11:3306 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.12:3306 weight=2 max_fails=3 fail_timeout=30s;
# 备用节点,所有主节点不可用才启用
server 10.0.1.13:3306 backup;
}
# 全局stream日志,方便排查连接问题
log_format proxy_stream '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /var/log/nginx/stream-access.log proxy_stream;
# 监听3306端口,对外提供MySQL连接入口
server {
listen 3306;
proxy_pass mysql_cluster;
# TCP代理超时参数,MySQL调优重点
proxy_connect_timeout 10s; # 连接后端MySQL超时
proxy_timeout 600s; # 连接空闲超时,600s无数据自动断开
# TCP缓冲区
proxy_buffer_size 16k;
}
}
# ========== http模块(独立,放Web服务,和stream互不干扰) ==========
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
}
}
参数详解(stream upstream)
upstream mysql_cluster {
least_conn; # ✅ MySQL推荐:最少连接。慢查询会占用连接,轮询容易堆在同一个节点
# ip_hash; # 如需同一个客户端IP固定连同一个MySQL节点,打开这个,注释least_conn
server 10.0.1.10:3306 weight=5 max_fails=3 fail_timeout=30s;
}
max_fails=3:连续 3 次连接失败,标记节点不可用fail_timeout=30s:标记失败后,30 秒内不再尝试访问该节点;30s 后重试探测weight:权重,加权轮询模式生效backup:备用节点,主节点全部 down 才启用down:手动标记节点下线,用于维护:server 10.0.1.10:3306 down;
stream 支持的调度策略:
默认:轮询 RR
least_conn:最少连接(MySQL/Redis 首选)
ip_hash:源 IP 哈希,同一个客户端 IP 固定打到同一后端
重点调优参数(server 块内)
listen 3306;
proxy_pass mysql_cluster;
proxy_connect_timeout 10s; # 建立TCP连接超时,不要太长
proxy_timeout 600s; # TCP连接空闲超时,MySQL长连接一定要设置
proxy_buffer_size 16k; # TCP数据缓冲区,四层不需要大buffer
验证命令
# 检查配置语法
nginx -t
# 平滑重载
nginx -s reload
# 验证端口监听
ss -tlnp | grep 3306
生产重要注意事项
模块检查
nginx -V | grep stream
# 看是否有 --with-stream,没有就要重新编译Nginx
MySQL 集群场景区分
MySQL 读写分离:stream LB 一般做读节点负载均衡;写节点单点,不放入这个 upstream
MGR 主从集群:可以把多个 MGR 只读节点放入 upstream 做读流量分发
被动健康检查局限 Nginx 原生 stream 只能探测TCP 连接能不能建立;无法探测 MySQL 实例是否正常(比如 MySQL 进程活着,但实例卡死、只读、复制异常)。
解决办法:第三方
ngx_stream_upstream_check_module主动健康检查,可发 MySQL ping 探测,需要打补丁重新编译 Nginx。防火墙:Nginx 服务器需要放开
3306端口;Nginx 机器要能访问后端 MySQL 节点 3306 端口。连接池注意 应用侧连接池连接到 Nginx 的 3306,Nginx 再和后端 MySQL 建立独立 TCP 连接;两层连接池,要注意连接数上限,防止连接打满。
扩展:Redis TCP 负载均衡示例(stream 块内追加)
upstream redis_cluster {
least_conn;
server 10.0.1.20:6379 max_fails=3 fail_timeout=30s;
server 10.0.1.21:6379 max_fails=3 fail_timeout=30s;
}
server {
listen 6379;
proxy_pass redis_cluster;
proxy_connect_timeout 5s;
proxy_timeout 300s;
}本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问