Nginx从1.9.13版本开始正式支持四层代理功能,这意味着它不再局限于HTTP/HTTPS七层代理,而是可以直接处理原始TCP和UDP流量。这个特性让Nginx从单纯的Web服务器蜕变为全能的流量代理网关。在实际生产环境中,我经常用它来处理数据库连接池、游戏服务器转发、IoT设备通信等场景。
与传统的HAProxy或LVS相比,Nginx的stream模块有几个独特优势:
重要提示:使用stream模块需要确保编译时添加了
--with-stream参数。通过nginx -V命令可以检查当前版本是否支持该功能。
Nginx处理TCP/UDP流量的核心在于stream上下文块,它与我们熟悉的http块是平级关系。一个典型的架构包含三个关键部分:
nginx复制worker_processes auto;
events {
worker_connections 1024;
}
# 与http块同级的stream块
stream {
upstream db_cluster {
server 10.0.0.1:3306;
server 10.0.0.2:3306 backup;
}
server {
listen 3306;
proxy_pass db_cluster;
}
}
http {
# 常规HTTP配置...
}
TCP代理的精细化控制需要理解以下几个关键参数:
连接超时控制:
nginx复制proxy_connect_timeout 2s; # 建立连接的超时时间
proxy_timeout 1h; # 连接保持的最长时间
缓冲与性能优化:
nginx复制proxy_buffer_size 16k; # 单连接缓冲区大小
proxy_download_rate 100k; # 下载速率限制
proxy_upload_rate 50k; # 上传速率限制
高可用配置:
nginx复制upstream redis_servers {
server 192.168.1.10:6379 weight=5;
server 192.168.1.11:6379 max_fails=3 fail_timeout=30s;
server 192.168.1.12:6379 backup;
}
UDP代理与TCP有几个显著差异点需要注意:
典型配置示例:
nginx复制stream {
upstream syslog_servers {
server 10.0.1.100:514;
server 10.0.1.101:514;
}
server {
listen 1514 udp reuseport;
proxy_pass syslog_servers;
proxy_timeout 1s;
proxy_responses 0;
}
}
经验之谈:UDP代理务必加上
reuseport参数,可以显著提升多核处理性能。实测在8核机器上,添加该参数后QPS从12k提升到85k。
Nginx可以解密传入的SSL流量后转发明文到后端:
nginx复制stream {
server {
listen 443 ssl;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
proxy_pass backend_servers;
}
}
通过Lua脚本可以实现协议转换,比如将MQTT转为WebSocket:
nginx复制server {
listen 1883;
preread_buffer_size 1k;
preread_by_lua_block {
local sock = ngx.req.socket()
local data = sock:receive(1)
if data == "\x10" then -- MQTT CONNECT包
ngx.var.target = "mqtt_backend"
else
ngx.var.target = "ws_backend"
end
}
proxy_pass $target;
}
将生产流量复制到测试环境进行分析:
nginx复制upstream primary {
server 10.0.0.5:5432;
}
upstream mirror {
server 10.0.1.5:5432;
}
server {
listen 5432;
proxy_pass primary;
mirror /mirror;
mirror_request_body on;
}
在/etc/sysctl.conf中添加:
bash复制net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65536 16777216
nginx复制worker_processes auto;
worker_rlimit_nofile 100000;
events {
worker_connections 50000;
multi_accept on;
use epoll;
}
stream {
proxy_buffering on;
proxy_buffer_size 16k;
proxy_busy_buffers_size 24k;
}
对于数据库类长连接应用:
nginx复制upstream mysql_pool {
server 10.0.0.10:3306;
keepalive 20; # 保持20个空闲连接
}
server {
listen 3306;
proxy_pass mysql_pool;
proxy_connect_timeout 3s;
proxy_socket_keepalive on;
}
检查步骤:
tail -f /var/log/nginx/error.logtelnet backend_ip backend_portiptables -L -n -vss -tulnp | grep port使用系统工具进行分析:
bash复制# 查看CPU使用情况
mpstat -P ALL 1
# 查看网络吞吐
sar -n DEV 1
# 查看连接状态
ss -s
问题1:bind() to 0.0.0.0:80 failed (98: Address already in use)
问题2:upstream timed out (110: Connection timed out)
proxy_connect_timeout值问题3:too many open files
nginx复制server {
listen 3389;
allow 192.168.1.0/24;
deny all;
proxy_pass rdp_servers;
}
nginx复制server {
listen 11211;
proxy_pass memcached_servers;
proxy_download_rate 100k;
proxy_upload_rate 50k;
}
nginx复制stream {
server {
listen 5432 ssl;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_certificate /etc/ssl/certs/pg.crt;
ssl_certificate_key /etc/ssl/private/pg.key;
proxy_pass postgres_servers;
}
}
在实际部署中,我发现TCP代理对MySQL长连接的支持需要特别注意keepalive参数的设置。曾经遇到过一个生产环境问题:当并发连接数超过500时,Nginx会出现大量TIME_WAIT状态的连接。最终通过调整内核参数net.ipv4.tcp_tw_reuse和Nginx的proxy_socket_keepalive参数解决了这个问题。