现场是这样的。PHP 8.1 的站点把 PDO 的持久连接打开后,MySQL 的 Threads_connected 从两百涨到六百,max_connections 是五百,高峰期开始拒绝新连接。
中间走过弯路,把「中间件连接池与持久连接叠加,等于两套池」当成主因,改完现象没变。
真正麻烦的地方在于,几个原因的现象几乎一样。每个 php-fpm 子进程各自缓存一份持久连接;持久连接不随请求结束释放,进程活着就一直占;异常路径没清理,连接状态变成不可复用。
动手时先统计连接来源与进程数
mysql -e "select user,host,count(*) from information_schema.processlist group by user,host;"
再往下核对 php-fpm 的进程上限
grep -E '^pm.(max_children|start_servers)' /etc/php-fpm.d/www.conf
随后关闭持久连接改由中间件做池化
php -i | grep -i 'pdo_mysql' | head -5
复查连接数是否回落
mysql -e "show status like 'Threads_connected';"
别只看报错消失,验证要多做一步。关闭持久连接后 Threads_connected 回落到两百上下,高峰期不再出现 Too many connections,接口耗时无明显变化。
容易忽略的是,持久连接适合建连成本高的场景,但连接数等于进程数乘库数;扩进程前先算一遍总数,别把数据库顶穿。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
