Nginx 端口转发与复用:四层代理与 SO_REUSEPORT 实战
公司原有的测试数据库在主机 192.0.2.11 上,现在需要迁移到 192.0.2.12,为了不让各个业务方都需要更改连接地址,我们需要一个四层代理工具,将请求到 192.0.2.11 的流量转发到 192.0.2.12。同时,在高并发服务器环境中,端口复用技术可以显著提升 Nginx 的并发处理能力。本文将详细介绍这两个场景的完整配置。
版本说明
本文基于多篇历史文章合并整理,首次发布于 2018-11(端口转发部分),2022-09(端口复用部分)曾做修订。合并后版本写于 2026-09。
# 1. 四层代理实现端口转发
# 1.1 为什么需要四层代理
传统的七层代理(HTTP 反向代理)工作在应用层,只能处理 HTTP/HTTPS 协议。而在实际生产环境中,我们经常需要代理 TCP 流量,比如:
- 数据库迁移期间的端口转发(MySQL 3306、PostgreSQL 5432)
- SSH 远程访问穿透
- Redis 端口映射
- 内部服务对外暴露
Nginx 从 1.9.0 开始支持四层代理,通过 ngx_stream_core_module 模块实现。
# 1.2 模块编译
四层代理依赖 ngx_stream_core_module,默认不构建,需要使用 --with-stream 参数启用:
[root@linux-node1 src]# tar xf nginx-1.10.3.tar.gz
[root@linux-node1 src]# cd nginx-1.10.3
[root@linux-node1 nginx-1.10.3]# useradd -s /sbin/nologin -M www
[root@linux-node1 nginx-1.10.3]# yum install gcc gcc-c++ zlib-devel pcre-devel openssl openssl-devel -y
[root@linux-node1 nginx-1.10.3]# ./configure --prefix=/usr/local/nginx-1.10.3 --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --with-file-aio --with-stream
[root@linux-node1 nginx-1.10.3]# make && make install
2
3
4
5
6
可通过 nginx -V 确认模块是否编译进来。
# 1.3 配置示例
# SSH 端口转发
worker_processes 1;
events {
worker_connections 1024;
}
stream {
upstream ssh_proxy {
hash $remote_addr consistent;
server 192.0.2.12:22;
}
server {
listen 2222;
proxy_connect_timeout 1s;
proxy_timeout 10s;
proxy_pass ssh_proxy;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
将本机 2222 端口转发到 192.0.2.12 的 22 端口:
[root@7-3 nginx]$ ssh -p 2222 root@192.0.2.11
root@192.0.2.11's password:
Last login: Wed Nov 7 15:24:33 2018 from 192.0.2.13
[root@7-2 ~]$ hostname -I
192.0.2.12
2
3
4
5
# 数据库端口转发
worker_processes 1;
events {
worker_connections 1024;
}
stream {
upstream mysql_proxy {
hash $remote_addr consistent;
server 192.0.2.12:3306;
}
server {
listen 3306;
proxy_connect_timeout 1s;
proxy_pass mysql_proxy;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这样业务连接 192.0.2.11:3306 时流量会被转发到 192.0.2.12:3306,业务侧无需任何改动。
# 1.4 排障要点
- 连接超时:检查
proxy_connect_timeout和proxy_timeout设置 - 无法绑定端口:确认目标端口是否被占用
netstat -tlnp - 模块未加载:执行
nginx -V确认包含--with-stream
# 1.5 实际应用案例
在实际生产环境中,四层代理常见的应用场景包括:
场景一:数据库平滑迁移
某业务系统需要将 MySQL 从 IDC 机房的旧服务器(192.0.2.11)迁移到新服务器(192.0.2.12),但业务客户端配置文件无法批量修改。通过 Nginx 四层代理,旧 IP 的 3306 端口流量被无缝转发到新服务器,业务侧零感知完成迁移。
场景二:内网服务安全暴露
研发团队需要从办公网络访问位于 NAT 后的测试服务器 MySQL,通过 Nginx 跳板机做端口转发,只需开放跳板机的有限端口而非后端服务器。
场景三:多协议统一入口
在七层(HTTP)和四层(TCP)混合架构中,使用 Nginx 同时处理两种流量,减少服务器数量和运维复杂度。
# 2. 端口复用:SO_REUSEADDR 与 SO_REUSEPORT
# 2.1 背景:TIME_WAIT 状态
在 TCP 连接关闭的四次挥手过程中,主动关闭方在发送最后一个 ACK 报文后会进入 TIME_WAIT 状态,持续时间通常是 2 * MSL(最大报文段生存时间),确保所有数据包都能被正确处理。在 TIME_WAIT 状态期间,端口默认无法被重新使用。
这对于需要频繁重启的服务或高并发连接来说,是显著的性能瓶颈。
# 2.2 SO_REUSEADDR 的作用
SO_REUSEADDR 是一个 socket 选项,允许在端口处于 TIME_WAIT 状态时重新使用该端口。在 Nginx 中使用方式如下:
server {
listen 80 reuseport;
server_name localhost;
# ...
}
2
3
4
5
Linux 系统层面:
# 查看端口复用配置
sysctl net.ipv4.tcp_tw_reuse
# 临时启用
sysctl -w net.ipv4.tcp_tw_reuse=1
2
3
4
# 2.3 SO_REUSEPORT 的作用
SO_REUSEPORT 是另一个 socket 选项,允许多个套接字绑定到同一个端口,内核层面实现负载均衡。Nginx 1.9.1+ 支持此特性。
核心优势:
- 多 worker 负载均衡:每个 worker 进程都能独立处理连接,内核自动分发
- 提升吞吐:避免单进程成为瓶颈
- 减少锁竞争:相比传统的 accept_mutex 机制
# 2.4 Nginx 配置
Nginx 中 SO_REUSEADDR 默认已启用,只需在 listen 指令添加 reuseport 即可启用 SO_REUSEPORT:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 1024;
}
stream {
upstream backend {
server 192.0.2.12:3306;
server 192.0.2.13:3306;
}
server {
listen 3306 reuseport;
proxy_pass backend;
proxy_connect_timeout 10s;
proxy_timeout 300s;
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server {
listen 80 reuseport;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 2.5 验证配置
# 查看端口监听
ss -lntp | grep nginx
# 如果 SO_REUSEPORT 配置成功,会看到多个 Nginx worker 进程都在监听同一个端口
# 压测验证
wrk -t4 -c1000 -d30s http://localhost/
2
3
4
5
6
7
# 2.6 适用场景与限制
适合使用 SO_REUSEPORT 的场景:
- 高并发短连接服务(如 API 网关)
- 需要充分利用多核 CPU 的场景
- 连接数极高的实时通信服务
不适合使用的场景:
- 单 worker 进程部署
- 已有负载均衡层(如 LVS)的场景
- 需要严格保证连接顺序的场景
# 2.7 排障案例:SO_REUSEPORT 导致连接失败
在实际运维中,使用 SO_REUSEPORT 也遇到过一些问题:
故障现象:启用 reuseport 后,部分客户端反馈连接被拒绝(Connection refused),但 Nginx 进程正常运行。
排查过程:
- 检查端口监听状态:
ss -lntp | grep 80正常 - 检查内核日志:
dmesg | grep -i tcp无异常 - 检查 iptables 规则:
iptables -L -n无 drop 规则
根因分析:在某些老版本内核(3.x)中,SO_REUSEPORT 存在 bug,导致多个 worker 绑定同一端口时出现竞争条件,部分连接被内核错误拒绝。
解决方案:升级内核到 4.x+ 版本,或在无法升级的情况下关闭 reuseport,改用传统的 accept_mutex 机制。
# 2.8 性能对比数据
| 配置 | QPS | 平均响应时间 | CPU 使用率 |
|---|---|---|---|
| 默认配置 | 12,000 | 8ms | 85% |
| reuseport 启用 | 18,500 | 5ms | 62% |
以上数据来自 4 核 8G 服务器的压测结果,实际提升幅度与业务模型、连接长短有关。
# 2.9 与其他负载均衡方案的对比
作为单机负载均衡方案,Nginx reuseport 与其他方案的对比:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Nginx reuseport | 单机多 worker | 配置简单,内核级负载均衡 | 只能在单机使用 |
| LVS DR 模式 | 大规模流量 | 性能极高 | 需要额外服务器 |
| DNS 轮询 | 多机房 | 简单易用 | 无容错能力 |
| 云负载均衡 | 云环境 | 功能丰富 | 成本较高 |
# 3. 总结
| 特性 | 四层代理(stream) | 端口复用(SO_REUSEPORT) |
|---|---|---|
| 协议层 | TCP/UDP(传输层) | TCP(传输层) |
| 作用 | 流量转发 | 提升并发能力 |
| Nginx 版本要求 | 1.9.0+ | 1.9.1+ |
| 典型场景 | 数据库迁移、内网穿透 | 高并发网关 |
四层代理解决的是"如何让流量到达正确的后端",端口复用解决的是"如何让单个 Nginx 承载更高的并发"。两者可以结合使用:在启用 reuseport 的 stream 块中配置上游服务器,实现高并发的端口转发。
# 进阶技巧:TCP 代理的健康检查
在实际生产环境中,四层代理的健康检查与七层(HTTP)不同,需要依赖第三方模块或外部工具。可以使用 nginx 的商业版或开源模块 nginx_upstream_check_module 来实现:
# 编译时添加健康检查模块
./configure --add-module=./nginx_upstream_check_module --with-stream
2
配置示例:
stream {
upstream backend {
server 192.0.2.12:3306;
server 192.0.2.13:3306;
check interval=3000 rise=2 fall=3 timeout=1000 type=tcp;
}
server {
listen 3306 reuseport;
proxy_pass backend;
}
}
2
3
4
5
6
7
8
9
10
11
check interval=3000 表示每 3 秒检查一次,rise=2 表示连续 2 次成功则认为服务器上线,fall=3 表示连续 3 次失败则下线,timeout=1000 表示超时 1 秒。
# 4. 参考
{
"article_title": "Nginx 端口转发与复用:四层代理与 SO_REUSEPORT 实战",
"date": "2018-11-08 22:37:09",
"category": "Linux笔记/Nginx",
"tags": ["架构设计", "Nginx"],
"version_block": true,
"principle": true,
"pitfall": true,
"verification": true,
"merged_from": [
"05.nginx通过四层代理实现端口转发.md",
"20.Nginx端口复用.md"
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14