PHP mysqli如何重连已更新的DigitalOcean托管数据库实例
问题核心原因
你遇到的是PHP-FPM常驻进程场景下的两个核心问题:
- 你的数据库连接逻辑只判断静态连接对象是否存在,不校验连接有效性,连接失效后不会主动重建
- 常驻的PHP-FPM进程、mysqli实例、系统DNS缓存会留存旧的数据库节点IP,故障切换后不会自动更新
解决方案
1. 修复数据库连接逻辑(核心调整)
你当前的代码存在两个明显缺陷:一是只要静态属性\SqlClass::$connObj被初始化过,不管连接是否失效都会直接判定为已连接;二是重试时复用同一个mysqli实例,该实例会缓存首次解析的旧IP,重试也不会重新解析域名。
调整后的参考代码如下:
public static function connectToDatabase(string $dbHostName, string $dbUserName, string $dbPassword, string $databaseName): void { $maxRetries = 3; $retryDelays = [1, 2, 10]; // 每次重试的等待秒数 // 先校验现有连接是否有效 if (\SqlClass::$connObj) { // 尝试ping检测连接存活,失败则重置连接对象 if (!@\SqlClass::$connObj->ping()) { \SqlClass::$connObj->close(); \SqlClass::$connObj = null; } } $hasConnected = false; for ($i = 0; $i < $maxRetries; $i++) { if (!\SqlClass::$connObj) { // 每次重连都新建mysqli实例,避免旧实例缓存DNS解析结果 \SqlClass::$connObj = mysqli_init(); \SqlClass::$connObj->options(MYSQLI_OPT_CONNECT_TIMEOUT, $i === 0 ? 1 : 10); // 禁用MySQL客户端的DNS缓存(如支持) if (defined('MYSQLI_OPT_DNS_CACHE_TIMEOUT')) { \SqlClass::$connObj->options(MYSQLI_OPT_DNS_CACHE_TIMEOUT, 0); } } $hasConnected = @\SqlClass::$connObj->real_connect($dbHostName, $dbUserName, $dbPassword, $databaseName, 128); if ($hasConnected && !\SqlClass::$connObj->connect_errno) { break; } // 连接失败重置对象,等待后重试 \SqlClass::$connObj->close(); \SqlClass::$connObj = null; if ($i < $maxRetries -1) { sleep($retryDelays[$i]); } } if (!$hasConnected || \SqlClass::$connObj->connect_errno) { // 执行错误处理逻辑 exit; } \SqlClass::$connObj->select_db($databaseName); \SqlClass::$connObj->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true); \SqlClass::$connObj->set_charset('utf8mb4'); }
2. 调整PHP配置
编辑php.ini文件,调整以下参数,缩短PHP层面的DNS缓存时间:
; 降低PHP DNS缓存时长为10秒,默认通常为120秒 dns_cache_timeout = 10
重启PHP-FPM生效。
3. 调整PHP-FPM配置
编辑你站点对应的PHP-FPM池配置文件(通常在/etc/php/8.0/fpm/pool.d/目录下),添加以下参数:
; 每个worker进程处理500次请求后自动重启,避免常驻进程长期缓存旧DNS/旧连接 pm.max_requests = 500
如果你使用了mysqli持久连接(主机名前缀为p:),建议额外添加:
; 持久连接复用前强制校验有效性 mysqli.allow_persistent = On mysqli.check_peristent = On
重启PHP-FPM生效。
4. 系统DNS缓存调整
如果你的服务器开启了nscd、systemd-resolved等DNS缓存服务,将A记录的缓存时长调整为10秒以内,避免系统层面长期留存旧的数据库IP。
完成以上调整后,数据库故障切换时最长30秒内即可自动恢复连接,不需要手动重启PHP-FPM。
内容的提问来源于stack exchange,提问作者Redzarf
相关产品推荐
相关产品推荐

