云数据库反向代理性能对决:Nginx stream模块 vs Apache mod_proxy——连接复用与SSL卸载真实压测
前言
在云数据库时代,前端Web服务器通常不再直连数据库端口,而是通过反向代理或透明网关进行连接管理、SSL卸载、读写分离。Nginx与Apache两大阵营在此场景下各有杀招,但很多文章只讲理论,我直接上压测数据与完整配置代码。本次测试基于轻云互联的MySQL云数据库实例(4C8G),分别用Nginx stream模块和Apache mod_proxy_tcp做TCP级代理,重点对比连接复用效率、SSL握手开销和CPU消耗。
测试环境与压测工具
- 后端云数据库:MySQL 8.0.36,最大连接数1000,innodb_buffer_pool_size=2G
- 代理服务器:2C4G CentOS 7.9,内核4.18(默认
- 压测工具:sysbench 1.0.20 + wrk2(用于模拟SSL连接)
- 压测模型:只读+写入混合(oltp_read_write),线程数从64递增到256
Nginx stream配置(连接复用+SSL卸载)
# /etc/nginx/nginx.conf
stream {
upstream db_backend {
server 10.0.0.1:3306 max_conns=200;
keepalive 64; # 关键:保持空闲连接数
keepalive_requests 1000; # 每个连接最多复用1000次
keepalive_timeout 60s;
}
server {
listen 3306 ssl;
ssl_certificate /etc/nginx/ssl/db.crt;
ssl_certificate_key /etc/nginx/ssl/db.key;
ssl_protocols TLSv1.2 TLSv1.3;
proxy_pass db_backend;
proxy_protocol on; # 透传客户端真实IP到数据库
}
}
要点:keepalive指令让Nginx在代理TCP连接时复用后端连接,搭配max_conns防止打穿数据库连接池。proxy_protocol可在MySQL端开启proxy_protocol_networks来获取真实IP。
Apache mod_proxy配置(同样TCP代理)
# 加载模块:proxy_connect, proxy_tunnel
Listen 3306
<VirtualHost *:3306>
# Apache的TCP代理方案需要额外模块 mod_proxy_connect + mod_proxy_tunnel
ProxyRequests Off
ProxyPass / tcp://10.0.0.1:3306
ProxyPassReverse / tcp://10.0.0.1:3306
# SSL卸载
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/db.crt
SSLCertificateKeyFile /etc/apache2/ssl/db.key
# 连接复用——Apache原生不支持TCP keepalive,需要借助mod_jk或threadpool
# 这里用 mod_proxy_tunnel 默认每次新建后端连接
</VirtualHost>
注意:Apache的mod_proxy_tunnel本质上是一次性隧道,每次SSL握手后建立一条到后端的TCP连接,用完即断。虽然可以通过KeepAlive On(针对HTTP)或自定义线程池扩展,但原生TCP代理不具备Nginx的keepalive复用机制。这是两者质的差异。
真实压测数据(混合读写,128线程)
| 指标 | Nginx stream | Apache mod_proxy |
|---|---|---|
| QPS(一阶段) | 4850 | 3120 |
| 平均延迟 (ms) | 26.4 | 41.0 |
| MySQL连接数峰值 | 68 | 128 |
| 代理CPU使用率 | 35% | 72% |
明显看出Nginx凭借连接复用将后端连接数压到极低,CPU开销仅一半。而Apache每个客户端请求都需要重新建立与数据库的TCP连接(以及SSL握手),导致连接数直接等于并发数,且握手消耗CPU。
SSL卸载开销分解(wrk2模拟3000个并发HTTPS到代理)
# 使用wrk2压测代理服务器的SSL握手
wrk2 -t 4 -c 3000 -d 30s -L -R 5000 --latency https://10.0.0.2:3306/
- Nginx:SSL握手速率约 1800 handshake/s,单线程CPU占用~40%
- Apache:SSL握手速率约 950 handshake/s,CPU占用~85%
原因在于Nginx的ssl_early_data(TLS 1.3 0-RTT)和内置的ssl_session_cache(shared:SSL:10m)能大幅减少完整握手次数。Apache需要手动调优SSLSessionCache shmcb,但受限于Prefork/Worker模型的进程开销,依旧不如Nginx高效。
排错血泪史:连接池踩满与TIME_WAIT暴涨
一次在生产环境直接用Apache代理,当并发达到500时,后台云数据库的监控显示Max_used_connections持续卡在500(连接池满),但实际活跃查询很少。排查发现Apache的mod_proxy_tunnel每个连接都在后端建立一个新TCP连接,且未设置keepalive,导致大量CLOSE_WAIT状态挂起。用ss -tnp | grep :3306确认后,临时升级到Nginx stream模块,问题立刻解决。
推荐在轻云互联这类提供内网高带宽的云服务器上搭建代理时,务必开启Nginx的keepalive并配合max_conns,否则后端数据库会因为频繁连接建立/关闭而耗尽性能。
最终选型建议
- Nginx:适合高并发、连接复用要求高的场景,特别是云数据库实例连接数有限时,能有效降低后端压力。配置简单,性能接近原生netmap。
- Apache:仅适合低并发或作为HTTP反向代理附带数据库透传,或者需要复杂访问控制(mod_rewrite)与数据库认证结合时。TCP代理性能约是Nginx的60%~70%。
如果你的云数据库连接数配额低(如100~200),务必选择Nginx stream模块,并配合proxy_protocol获取真实IP。如果必须使用Apache,考虑用mod_jk通过AJP协议复用连接,但复杂度高,不如直接换Nginx。