yupanzi

使用 Nginx Stream 代理数据库连接

· 4 分钟阅读

使用 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_addrIP 哈希(会话保持)
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
  • 定期清理日志文件,避免磁盘占满

参考资料

相关文章