如何排查PHP MySQL中导致连接数超限的未关闭连接文件?
定位未关闭MySQL连接的PHP文件的实用方法
给PDO连接添加创建溯源标记
在创建PDO连接的代码处,加入调用栈记录,把连接的创建位置(文件、行号、调用链)写入日志或者存在连接实例的自定义属性中。比如:$pdo = new PDO($dsn, $user, $pass); // 记录连接创建的调用栈 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $creationInfo = sprintf("Connection created in %s line %s", $trace[0]['file'], $trace[0]['line']); // 写入错误日志 error_log($creationInfo);当连接数接近上限时,查看错误日志就能知道哪些文件频繁创建连接却没释放。
封装PDO子类追踪生命周期
自己封装一个PDO子类,在构造函数记录创建信息,析构函数记录销毁信息。如果某个连接的销毁日志没出现,说明它没被正确关闭,就能定位到创建它的文件:class TrackedPDO extends PDO { private $creationTrace; public function __construct($dsn, $username = null, $password = null, $options = null) { $this->creationTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); parent::__construct($dsn, $username, $password, $options); $info = sprintf("Created connection: %s line %s", $this->creationTrace[0]['file'], $this->creationTrace[0]['line']); error_log($info); } public function __destruct() { $info = sprintf("Closed connection from: %s line %s", $this->creationTrace[0]['file'], $this->creationTrace[0]['line']); error_log($info); } }把项目中所有
new PDO()替换成new TrackedPDO(),运行一段时间后对比创建和销毁日志,缺失销毁记录的就是问题文件。临时开启MySQL通用日志定位连接来源
临时开启MySQL的general log,记录所有连接请求的详细信息,包括发起连接的PHP进程ID。然后结合PHP的FPM日志,找到对应进程处理的请求文件:-- 开启通用日志 SET GLOBAL general_log = 'ON'; SET GLOBAL general_log_file = '/tmp/mysql_general.log';日志里会显示类似
Connect user@host on dbname的记录,以及对应的Thread ID,再通过show processlist找到该Thread ID对应的PHP请求,进而定位到处理的文件。用完记得关闭通用日志,避免磁盘占用过高。使用PHP性能分析工具追踪实例
用Xdebug或Tideways这类工具,开启函数调用追踪,记录每个PDO实例的创建和销毁点。通过分析调用栈,能直观看到哪些请求中PDO实例没有被正确销毁,从而定位到对应的文件。
内容的提问来源于stack exchange,提问作者tonsaa
相关产品推荐
相关产品推荐

