这个坑值得记一笔。PHP 7.4 的项目里每个请求都 new PDO 连 MySQL,接口平均耗时八十毫秒,用 mysql 的 general log 一对时间,六十毫秒花在建立连接和认证上,并发一上来 QPS 就上不去。
刚开始盯着「连接用完就断,服务端频繁创建销毁线程,Threads_created 一直涨」,折腾了半个多小时,排掉了。
原因不止一个,得分开看。每个请求新建一条 TCP 连接,握手加认证的往返全算在业务耗时里;MySQL 默认开启反向域名解析,每次连接都要做一次 PTR 查询;连接上没有设置字符集和时区,每次连上还要额外发几条初始化语句。
第一件事是对比连接数与新建线程数
mysql -e 'show global status like "Connections"; show global status like "Threads_created";'
随后确认反向解析是不是开着
mysql -e 'show variables like "skip_name_resolve";'
然后关掉反向解析并重启数据库
sed -i '/^\[mysqld\]/a skip-name-resolve' /etc/my.cnf && systemctl restart mysqld
剩下的就是在应用侧确认有没有用长连接
grep -rn 'new PDO' /www/api/app | head -5
怎么算真的好了,看的是同一批现象。接口耗时降到三十毫秒以内,Threads_created 的增长速度明显放缓,连接数与 QPS 的比例稳定在个位数。
提醒一点。长连接要配合 wait_timeout 一起来,池子里的连接被服务端先断掉同样会报错,两边超时顺序要对齐。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
