1. Nginx代理功能概述
Nginx作为高性能的反向代理服务器,大多数场景下我们主要使用其HTTP代理能力。但很多人不知道的是,从1.9.0版本开始,Nginx就原生支持了TCP/UDP协议的代理功能。这个特性使得Nginx可以成为数据库、游戏服务器、DNS服务等非HTTP协议应用的代理网关。
我在实际生产环境中使用Nginx作为MySQL读写分离的代理层,单台Nginx服务器轻松承载了每秒2万+的数据库查询请求。相比专业的数据库中间件,Nginx的TCP代理配置更加轻量灵活,特别适合中小规模的应用场景。
2. TCP代理配置详解
2.1 基础模块加载
首先需要在编译Nginx时加入--with-stream参数来启用流模块。如果是已安装的Nginx,可以通过nginx -V查看是否包含此模块。如果没有则需要重新编译:
bash复制./configure --with-stream
make && make install
提示:生产环境建议使用
--with-stream_ssl_module同时启用SSL支持,这样后续可以配置加密的TCP代理。
2.2 核心配置结构
TCP代理的配置需要放在stream上下文中,与常规的http上下文同级:
nginx复制# 主配置文件nginx.conf
events {
worker_connections 1024;
}
stream {
server {
listen 3306;
proxy_pass db_backend;
}
upstream db_backend {
server 192.168.1.101:3306 weight=5;
server 192.168.1.102:3306;
}
}
http {
# 常规HTTP配置...
}
这个配置实现了:
- 监听本机3306端口
- 将TCP连接代理到后端两个MySQL服务器
- 第一个后端服务器权重更高
2.3 高级参数调优
对于高并发场景,建议调整以下参数:
nginx复制stream {
proxy_connect_timeout 5s; # 连接超时
proxy_timeout 1h; # 长连接保持时间
proxy_buffer_size 16k; # 每个连接缓冲区大小
server {
listen 3306 so_keepalive=on; # 启用TCP keepalive
proxy_pass db_backend;
proxy_next_upstream on; # 故障转移
}
}
实测发现,调整proxy_buffer_size对数据库类小包高并发场景性能影响最大。我们通过压测找到16k是最佳值,既不会浪费内存,又能减少系统调用次数。
3. UDP代理配置实践
3.1 DNS代理示例
Nginx的UDP代理常用于DNS查询转发。以下是配置示例:
nginx复制stream {
server {
listen 53 udp reuseport;
proxy_pass 8.8.8.8:53;
proxy_responses 1; # 预期接收的响应数
}
}
关键点:
udp参数指定UDP协议reuseport实现内核级负载均衡proxy_responses需要根据协议特性设置
3.2 游戏服务器代理
对于游戏类应用,需要特别关注超时设置:
nginx复制stream {
server {
listen 27015 udp;
proxy_timeout 20s;
proxy_pass game_servers;
}
upstream game_servers {
server 10.0.1.10:27015;
server 10.0.1.11:27015;
}
}
注意:UDP代理不支持
proxy_next_upstream,因为Nginx无法判断UDP请求是否失败
4. 性能优化技巧
4.1 内核参数调优
在高并发场景下,需要调整系统参数:
bash复制# 增加本地端口范围
echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl.conf
# 增大连接跟踪表大小
echo "net.netfilter.nf_conntrack_max = 1048576" >> /etc/sysctl.conf
sysctl -p
4.2 Worker进程绑定
在多核服务器上,将worker进程绑定到特定CPU核心:
nginx复制worker_processes auto;
worker_cpu_affinity auto;
4.3 连接池管理
对于数据库代理场景,启用连接池减少握手开销:
nginx复制stream {
server {
listen 3306;
proxy_pass db_backend;
proxy_socket_keepalive on;
}
upstream db_backend {
server 10.0.0.1:3306 max_conns=100;
}
}
5. 常见问题排查
5.1 连接超时问题
错误现象:频繁出现proxy_connect_timeout错误
排查步骤:
- 检查后端服务端口是否开放:
telnet backend_ip port - 检查防火墙规则:
iptables -L -n - 检查Nginx错误日志:
tail -f /var/log/nginx/error.log
5.2 UDP丢包问题
解决方案:
- 增加
reuseport参数 - 调整
worker_processes数量 - 检查网络设备MTU设置
5.3 性能瓶颈定位
使用系统工具分析:
bash复制# 查看连接状态
ss -s
# 监控CPU使用
top -H -p `pgrep nginx`
# 网络吞吐量
nload -u M
6. 安全加固措施
6.1 访问控制
nginx复制stream {
server {
listen 3306;
allow 192.168.1.0/24;
deny all;
proxy_pass db_backend;
}
}
6.2 SSL加密传输
对于敏感数据,建议启用SSL加密:
nginx复制stream {
server {
listen 3306 ssl;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
proxy_pass db_backend;
}
}
6.3 日志审计
配置详细的访问日志:
nginx复制stream {
log_format tcp_proxy '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';
server {
listen 3306;
access_log /var/log/nginx/tcp-access.log tcp_proxy;
proxy_pass db_backend;
}
}
7. 实际应用场景
7.1 数据库读写分离
nginx复制stream {
upstream mysql_master {
server db1.example.com:3306;
}
upstream mysql_slave {
server db2.example.com:3306;
server db3.example.com:3306;
}
server {
listen 3306;
proxy_pass mysql_master;
}
server {
listen 3307;
proxy_pass mysql_slave;
}
}
应用层通过连接不同端口实现读写分离。
7.2 多协议网关
nginx复制stream {
# DNS
server {
listen 53 udp;
proxy_pass dns_servers;
}
# MySQL
server {
listen 3306;
proxy_pass mysql_servers;
}
# Redis
server {
listen 6379;
proxy_pass redis_servers;
}
}
这种架构特别适合微服务环境,通过Nginx统一暴露各种后端服务的访问入口。
7.3 协议转换
结合stream_ssl_module可以实现SSL卸载:
nginx复制stream {
server {
listen 3306 ssl;
ssl_certificate /path/to/cert.pem;
proxy_pass backend:3306;
}
}
这样客户端使用SSL连接,而后端服务使用普通TCP连接,减轻后端服务器的加密计算负担。