根本原因不是多服务器配置本身,而是每个服务器连接在PHP进程内维持独立mysqli/PDO实例且默认未主动释放;频繁切换服务器、多标签页或冗余配置会导致连接累积驻留,引发内存增长、GC压力增大及CPU占用升高。
根本原因不是“多服务器配置本身”,而是每个服务器连接在 php 进程内维持了独立的 mysqli 或 pdo 实例,且默认未主动释放;当用户频繁切换服务器、打开多个标签页、或配置中启用了冗余连接逻辑时,这些连接会累积并长期驻留,导致 php-fpm 进程内存持续增长、gc 压力增大,最终表现为 cpu 占用升高(尤其在 __destruct 或连接关闭阶段触发大量资源清理)。
多服务器配置中哪些写法会隐式创建多余连接
phpMyAdmin 的 $cfg['servers'] 数组每项都会在登录后尝试建立连接(即使未选中),尤其在以下场景:
- 配置了 5 个服务器,但只用第 1 个 —— 其余 4 个仍会在初始化阶段调用
new mysqli(),若mysqli.reconnect=Off(默认)且连接失败,错误处理可能卡住连接对象 - 在
config.inc.php中使用foreach动态生成服务器配置,但未对$i索引做严格递增校验,导致部分配置被跳过或重复加载,引发多次mysqli::__construct调用 - 启用了
$cfg['ServerDefault'] = 0(即“无默认服务器”),但未配合$cfg['AllowArbitraryServer'] = false,phpMyAdmin 会在每次请求时尝试探测所有服务器连通性
为什么连接不释放会导致 CPU 持续偏高
PHP-FPM 进程退出前会逐个析构所有活跃的 MySQL 连接对象。若连接数多、网络延迟高或 MySQL 服务响应慢,mysqli::close() 可能阻塞数秒 —— 这期间进程无法复用,新请求只能 fork 新进程,形成雪崩式进程膨胀。更隐蔽的是:
- MySQL 连接对象内部持有大量 ZVAL 引用,GC 在销毁时需遍历整个引用图,连接越多,GC 耗时越长(尤其 PHP 8.0+ 的 GC 策略更激进)
- phpMyAdmin 的
src/Plugins/Auth/AuthenticationCookie.php在验证多服务器登录态时,若$cfg['CheckConfigurationPermissions'] = true(默认),会反复 stat 配置文件并触发 realpath 缓存刷新,加剧 CPU 消耗 - 某些 MariaDB 版本在空闲连接关闭时存在握手延迟,导致
mysqli::close()实际执行时间远超预期
如何验证当前是否是连接管理引发的高 CPU
别只看 top,重点抓进程级行为:
- 运行
strace -p $(pgrep -f 'php-fpm.*www') -e trace=connect,close,write -s 128 2>&1 | grep -E '(connect|close|mysql)',观察是否密集出现重复connect或长时间阻塞在close - 在 phpMyAdmin 页面底部点“服务器信息” → “PHP 设置”,确认
mysqli.max_links是否为-1(无限)—— 若是,且你有 10 个服务器配置,单个 PHP-FPM 进程最多可建 10 个持久连接,极易耗尽系统 fd 限额 - 检查
/proc/$(pgrep -n php-fpm)/fd/下的文件描述符数量:若稳定 > 500,且多数是 socket 类型,基本可判定连接泄漏
真正有效的缓解方式不是删服务器,而是控制连接生命周期
多服务器本身无害,问题出在“连接即建、建即常驻”。必须从三个层面切断链路:
立即学习“PHP免费学习笔记(深入)”;
- 在
config.inc.php中显式禁用非必要连接:$cfg['Servers'][$i]['extension'] = 'mysqli'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; $cfg['Servers'][$i]['compress'] = false;—— 关闭压缩和 Unix socket 自动降级,避免连接协商开销 - 设置连接超时:在每个服务器配置块里加
$cfg['Servers'][$i]['login_timeout'] = 3;和$cfg['Servers'][$i]['ssl'] = false;(除非真需要 SSL) - 强制按需连接:在
config.inc.php底部追加if (! isset($_GET['server']) && ! isset($_POST['server'])) { foreach ($cfg['Servers'] as $i => $server) { unset($cfg['Servers'][$i]); } }—— 让未指定服务器的请求不初始化任何连接
最易被忽略的一点:phpMyAdmin 的“服务器选择下拉框”本身就会触发全部服务器的元数据查询(如 SHOW DATABASES),哪怕你只是路过登录页。如果其中某个服务器响应极慢,整个页面渲染会被拖住 —— 这种阻塞不是内存问题,而是同步 I/O 导致的 CPU 空转等待,必须用 login_timeout 和前端 JS 控制加载时机来破局。



















