使用 Nginx Stream 代理数据库连接
使用 Nginx Stream 模块代理 TCP 连接,实现数据库端口转发和负载均衡。
应用场景
- 端口映射:本地 33078 → 远程 MySQL 3306
- 负载均衡:多个数据库实例分流
- 连接日志:记录所有数据库连接信息
- 安全加固:隐藏真实数据库地址
Nginx Stream 配置
完整配置示例
/etc/nginx/nginx.conf:
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 配置(Web 服务)
http {
# ... HTTP 配置保留 ...
include /etc/nginx/sites-enabled/*;
}
# Stream 配置(TCP/UDP 代理)
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;
# MySQL 代理
server {
listen 33078;
proxy_pass mysql.example.com:3306;
proxy_timeout 300m;
proxy_connect_timeout 10s;
}
# PostgreSQL 代理
server {
listen 54320;
proxy_pass postgres.example.com:5432;
proxy_timeout 300m;
}
# Redis 代理
server {
listen 63790;
proxy_pass redis.example.com:6379;
proxy_timeout 600s;
}
# MongoDB 代理
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 | 连接时间 |
超时设置
proxy_timeout 300m; # 会话超时(5 小时)
proxy_connect_timeout 10s; # 连接超时(10 秒)
负载均衡配置
多个 MySQL 实例
stream {
# 定义后端服务器组
upstream mysql_backend {
# 负载均衡策略:least_conn(最少连接)
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(会话保持)
upstream mysql_backend {
hash $remote_addr consistent;
server mysql1.example.com:3306;
server mysql2.example.com:3306;
}
SSL/TLS 加密
添加 SSL 层
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 白名单
stream {
# 定义允许的 IP
geo $allowed_ip {
default 0;
192.168.1.0/24 1;
10.0.0.0/8 1;
}
server {
listen 33078;
# 检查 IP
if ($allowed_ip = 0) {
return 403;
}
proxy_pass mysql.example.com:3306;
}
}
使用示例
连接 MySQL
# 直接连接(原始)
mysql -h mysql.example.com -P 3306 -u user -p
# 通过代理连接
mysql -h proxy.example.com -P 33078 -u user -p
连接 PostgreSQL
psql -h proxy.example.com -p 54320 -U user -d database
连接 Redis
redis-cli -h proxy.example.com -p 63790
查看连接日志
# 实时查看
tail -f /var/log/nginx/tcp-access.log
# 示例输出:
# 192.168.1.100 [29/Sep/2024:15:34:32 +0800] TCP 200 1024 2048 300.123 "mysql.example.com:3306" "512" "1536" "0.003"
性能优化
连接池配置
worker_rlimit_nofile 65535; # 增加文件描述符
events {
worker_connections 10240; # 增加连接数
use epoll; # Linux 使用 epoll
}
缓冲区调优
stream {
server {
listen 33078;
proxy_pass mysql.example.com:3306;
proxy_buffer_size 16k;
proxy_upload_rate 0;
proxy_download_rate 0;
}
}
健康检查
需要 Nginx Plus 或第三方模块:
upstream mysql_backend {
server mysql1.example.com:3306;
# Nginx Plus 健康检查
health_check interval=5s fails=3 passes=2;
}
开源版替代方案:使用外部脚本定期检测。
注意事项
- Stream 模块默认编译,无需额外安装
- 与 HTTP 配置在同一个
nginx.conf文件中 - 日志文件单独配置,避免与 HTTP 日志混淆
- 超时时间根据实际业务调整(长连接可设置更大值)
- 生产环境建议启用 SSL/TLS
- 定期清理日志文件,避免磁盘占满