PHP7.4使用PDO连接数据库偶尔出现连接耗时过高异常问题问询
可能的根因分析
- MySQL服务端反向DNS解析超时
MySQL默认会对所有入站连接的客户端IP做反向域名解析,用于权限校验时匹配域名规则。即便客户端连接时填写的是数据库IP,该服务端逻辑也会执行。如果数据库服务器配置的DNS服务不稳定、客户端IP没有对应的PTR记录,就会出现解析超时,默认超时时间多为1秒,与日志中1秒级的耗时峰值完全匹配,0.2秒左右的异常耗时对应解析重试的中间状态。 - TCP连接队列溢出
每小时3亿查询对应的QPS超过8万,短连接场景下每秒新建TCP连接的量级非常高。如果数据库端的TCP半连接队列(syn_backlog)、全连接队列(somaxconn/back_log)配置过小,高并发下队列溢出后内核会丢弃SYN包,TCP协议栈会等待超时后重传SYN,Linux系统默认首次SYN重传超时为200ms、第二次为1秒,正好对应日志中0.2秒和1秒两档异常耗时。 - 短连接风暴导致连接资源争抢
当前代码仅实现了单次请求内的连接单例,PHP-FPM模式下每个进程独立持有连接,请求结束后如果没有开启持久化连接,连接会被主动释放,后续请求需要重新建立连接。高并发下频繁新建/释放连接会耗尽数据库端的可用连接槽位,新连接需要等待旧连接释放才能建立,导致耗时上涨。
排查与验证方法
- 登录数据库执行
show global variables like 'skip_name_resolve',查看是否已经关闭反向DNS解析。 - 执行
show global status like 'Threads_created',对比前后两次查询的数值差,如果差值和每秒请求数接近,说明短连接占比极高。 - 查看数据库服务器内核日志
dmesg,如果存在TCP: time wait bucket table overflow、SYN cookies相关的记录,即可确认存在TCP连接队列溢出问题。
解决方案
- 优先在MySQL配置文件
my.cnf中添加skip-name-resolve参数,重启MySQL生效,直接排除反向DNS解析问题。 - 调整内核参数:将
net.core.somaxconn、net.ipv4.tcp_max_syn_backlog调整为1024以上,同时开启net.ipv4.tcp_syncookies = 1,应对高并发连接场景。 - 开启PDO持久化连接:在
$cred['options']中添加PDO::ATTR_PERSISTENT => true,实现FPM进程级别的连接复用,大幅降低新建连接的频率。 - 调高MySQL的
back_log、max_connections参数,匹配业务并发连接量级。
内容的提问来源于stack exchange,提问作者Tyralcori
相关产品推荐
相关产品推荐

