使用 Nginx Stream 模块代理 TCP 连接,实现数据库端口转发和负载均衡。
应用场景
- 端口映射:本地 33078 → 远程 MySQL 3306
- 负载均衡:多个数据库实例分流
- 连接日志:记录所有数据库连接信息
- 安全加固:隐藏真实数据库地址
Nginx Stream 配置
完整配置示例
/etc/nginx/nginx.conf:
1 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf;
worker_rlimit_nofile 65535;
events { worker_connections 10240; }
http { include /etc/nginx/sites-enabled/*; }
stream { log_format proxy '$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/tcp-access.log proxy; error_log /var/log/nginx/tcp-error.log; open_log_file_cache off;
server { listen 33078; proxy_pass mysql.example.com:3306; proxy_timeout 300m; proxy_connect_timeout 10s; }
server { listen 54320; proxy_pass postgres.example.com:5432; proxy_timeout 300m; }
server { listen 63790; proxy_pass redis.example.com:6379; proxy_timeout 600s; }
server { listen 27018; proxy_pass mongodb.example.com:27017; proxy_timeout 300m; } }
|
配置说明
日志字段
| 字段 |
说明 |
$remote_addr |
客户端 IP |
$time_local |
本地时间 |
$protocol |
协议(TCP/UDP) |
$status |
连接状态 |
$bytes_sent |
发送字节数 |
$bytes_received |
接收字节数 |
$session_time |
会话时长 |
$upstream_addr |
后端服务器地址 |
$upstream_connect_time |
连接时间 |
超时设置
1 2
| proxy_timeout 300m; proxy_connect_timeout 10s;
|
负载均衡配置
多个 MySQL 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| stream { upstream mysql_backend { least_conn;
server mysql1.example.com:3306 weight=2 max_fails=3 fail_timeout=30s; server mysql2.example.com:3306 weight=1 max_fails=3 fail_timeout=30s; server mysql3.example.com:3306 backup; }
server { listen 33078; proxy_pass mysql_backend; proxy_timeout 300m; } }
|
负载均衡策略
| 策略 |
说明 |
round-robin |
轮询(默认) |
least_conn |
最少连接数 |
hash $remote_addr |
IP 哈希(会话保持) |
random |
随机 |
IP Hash(会话保持)
1 2 3 4 5
| upstream mysql_backend { hash $remote_addr consistent; server mysql1.example.com:3306; server mysql2.example.com:3306; }
|
SSL/TLS 加密
添加 SSL 层
1 2 3 4 5 6 7 8 9 10 11
| stream { server { listen 33078 ssl; proxy_pass mysql.example.com:3306;
ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; } }
|
访问控制
IP 白名单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| stream { geo $allowed_ip { default 0; 192.168.1.0/24 1; 10.0.0.0/8 1; }
server { listen 33078;
if ($allowed_ip = 0) { return 403; }
proxy_pass mysql.example.com:3306; } }
|
使用示例
连接 MySQL
1 2 3 4 5
| mysql -h mysql.example.com -P 3306 -u user -p
mysql -h proxy.example.com -P 33078 -u user -p
|
连接 PostgreSQL
1
| psql -h proxy.example.com -p 54320 -U user -d database
|
连接 Redis
1
| redis-cli -h proxy.example.com -p 63790
|
查看连接日志
1 2 3 4 5
| tail -f /var/log/nginx/tcp-access.log
|
性能优化
连接池配置
1 2 3 4 5 6
| worker_rlimit_nofile 65535;
events { worker_connections 10240; use epoll; }
|
缓冲区调优
1 2 3 4 5 6 7 8 9 10
| stream { server { listen 33078; proxy_pass mysql.example.com:3306;
proxy_buffer_size 16k; proxy_upload_rate 0; proxy_download_rate 0; } }
|
健康检查
需要 Nginx Plus 或第三方模块:
1 2 3 4 5 6
| upstream mysql_backend { server mysql1.example.com:3306;
health_check interval=5s fails=3 passes=2; }
|
开源版替代方案:使用外部脚本定期检测。
注意事项
- Stream 模块默认编译,无需额外安装
- 与 HTTP 配置在同一个
nginx.conf 文件中
- 日志文件单独配置,避免与 HTTP 日志混淆
- 超时时间根据实际业务调整(长连接可设置更大值)
- 生产环境建议启用 SSL/TLS
- 定期清理日志文件,避免磁盘占满
参考资料