云数据库DDoS防护深度对决:MySQL连接限速 vs Thread Pool硬核抗压实测
前言
云数据库的抗D博弈,不在CDN,不在硬防,而在内核。
当4层SYN Flood被云厂商清洗后,7层慢连接、HTTP POST洪水、甚至MySQL协议层认证风暴,才是打穿数据库的最后一颗子弹。
这次我们不用任何外部高防IP,只对比数据库内核自身的两套护城河方案:MySQL连接限速 和 Thread Pool。
场景模拟
部署环境:4C8G云数据库实例(CentOS 7.9 + MySQL 8.0.34)。
攻击手段:2000个并发TCP连接发起MySQL认证请求,伪造合法用户名但不发后续query,模拟最耗资源的“连接建立型”攻击。
方案一:传统连接限速(Connection Rate Limit)
实现逻辑
# 利用iptables对宿主机端口的SYN包做hashlimit限速
iptables -A INPUT -p tcp --dport 3306 --syn \
-m hashlimit --hashlimit-name mysql_ratelimit \
--hashlimit-mode srcip \
--hashlimit-upto 5/second \
--hashlimit-burst 10 \
-j ACCEPT
iptables -A INPUT -p tcp --dport 3306 --syn -j DROP
效果评估:
- 命中场景:纯TCP连接建立式攻击,能显著降低MySQL进程的CPU开销。攻击端只有少量请求能通过,其余被iptables在内核态丢弃。
- 致命缺陷:一锤子买卖。限速粒度只到源IP,无法区分正常业务尖峰(如秒杀)与攻击。一旦业务全用NAT出口,一个源IP限死,业务全挂。
- 运维代价:排查难度低,调参数后iptables-save / iptables-restore即可。但MySQL内部完全无感知。
进阶:MySQL内部Per User限速
# 开启MySQL的max_user_connections + login attempts
SET GLOBAL max_connections = 200;
CREATE USER 'serv_user'@'%' IDENTIFIED BY 'x'
WITH MAX_USER_CONNECTIONS 50
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 3;
血泪教训:这个方案对“认证爆破”有效,但攻击者只需要持续用不同用户名创建连接,内存中的connection对象会瞬间膨胀,触发OOM killer。
方案二:Thread Pool(线程池)
实现说明
MySQL的企业版Thread Pool、Percona的线程池或MariaDB的thread pool,本质相同:限制活跃线程数,把请求先扔到任务队列。
# Percona MySQL配置示例
[mysqld]
thread_handling=pool-of-threads
thread_pool_size=16 # 与CPU核心数成正比
thread_pool_idle_timeout=60
thread_pool_oversubscribe=10
压力测试结果:
- 攻击开始后,mysql连接数瞬间涨到2000,但
SHOW PROCESSLIST显示的active thread count稳定在16。实际CPU占用率仅从12%升至25%,未触发OOM。 - 正常查询仍然可以进入队列并执行(延迟从2ms升到300ms,业务尚可接受)。而连接限速方案下,正常业务的P99延迟直接炸到5秒以上。
极端场景:Thread Pool+Giant lock?
Thread Pool并非银弹。在高并发写入场景下,如果后台有行锁竞争,线程池会因为任务被阻塞在锁等待上而饿死其他查询。
典型反例:一个慢update拿着行锁不提交,线程池把所有线程卡住,连KILL命令都无法响应。
解法:设置thread_pool_stall_limit=5(超时5秒强行中断当前线程),并配合innodb_lock_wait_timeout=3。
两款方案深度对比
| 指标 | 连接限速(iptables) | Thread Pool(内核级) |
|---|---|---|
| 攻击存活(连接数2000) | 服务可用,正常用户被误伤 | 保持稳定,正常请求可处理 |
| 资源消耗 | CPU低,内存无保护 | CPU略高,内存可控 |
| 部署难度 | 1分钟改iptables规则 | 需编译percona或MariaDB,或买企业版 |
| 业务适应性 | 低(无状态区分) | 高(支持事务级隔离) |
| 排错复杂度 | 简单,看dump包 | 需看mysql performance_schema.threads |
结论:如果预算足够(或使用云厂商自研内核),Thread Pool是攻防的第一道防线。iptables限速只能作为快速止血的临时方案。
生产环境调优最佳实践
我只说下面三板斧,不再啰嗦:
- 前置连接回收:在数据库层之上,使用
ProxySQL或HAProxy做连接池复用。将活动连接数压到100以内,让攻击者无法轻易创建海量连接。 - 内核参数收口:调高
net.ipv4.tcp_max_syn_backlog和net.core.somaxconn,并开启tcp_syncookies,让TCP三次握手阶段就拦住部分洪水。 - 应用层熔断:在业务代码中实现
circuit breaker。当MySQL错误码超过阈值时,直接返回降级结果(如“服务繁忙”),而不是继续阻塞数据库池。
实战数据
# 混合方案压测记录(流量模拟器drill生成2000并发)
# Thread Pool + ProxySQL前置连接池
服务端:max_connections=500
客户端:2000并发请求
结果:ProxySQL保持活跃连接80个,Thread Pool活动线程数20
延迟:P50=15ms,P99=400ms,无连接超时。
对比无防护组:P99直接爆到40s,mysql进程内存占用飙至3.8GB(被OOM杀掉)
一点题外话
很多厂商爱吹“高防云数据库”,但到了真实攻击场景,你会发现底层内核调优比什么都重要。
我测试的这台机器来自轻云互联,它的基础云数据库产品默认开启了Thread Pool(基于Percona版),省去了额外编译的时间。不过,即使没有自带,按本文的方式手动接入也很容易。
总结
对于云数据库DDoS防护:
- 连接限速是墙,能挡低级枪炮,但挡不住精确的穿透弹。
- Thread Pool是防弹衣,能保护核心引擎,但仍然有锁竞争的阿喀琉斯之踵。
- 最终要做立体防御:内核参数 + 连接池 + 应用熔断。
代码已给出,踩过的坑也标注了,剩下的留给你自己的生产环境去验证。