CodeIgniter故障转移数组失效排查求助:主库宕机后无法切换备库
咱先从最容易踩坑的点入手——既然你已经确认备用库单独连接正常,那问题大概率出在故障转移的配置细节、框架触发逻辑或者环境变量加载上,给你梳理几个核心排查方向:
1. 先确认故障转移配置的完整性
你贴的配置代码没写完,要确保主库配置里正确定义了failover数组,而且关键参数不能错,比如官方文档的标准结构(以CI3为例):
/* MySQL Driver */ $db['mysql']['hostname'] = getenv('DB_HOST'); $db['mysql']['username'] = getenv('DB_USERNAME'); $db['mysql']['password'] = getenv('DB_PASSWORD'); $db['mysql']['database'] = getenv('DB_DATABASE'); $db['mysql']['dbdriver'] = 'mysqli'; // 建议用mysqli而非旧的mysql驱动 $db['mysql']['pconnect'] = FALSE; // 重点!持久连接必须关闭,否则不会触发重连/故障转移 $db['mysql']['db_debug'] = TRUE; // 开启调试,方便看错误日志 // ... 其他通用配置(char_set、dbcollat等) // 备用库故障转移配置 $db['mysql']['failover'] = array( array( 'hostname' => getenv('DB_BACKUP_HOST'), 'username' => getenv('DB_BACKUP_USERNAME'), 'password' => getenv('DB_BACKUP_PASSWORD'), 'database' => getenv('DB_BACKUP_DATABASE'), 'dbdriver' => 'mysqli', 'pconnect' => FALSE, 'db_debug' => TRUE, 'char_set' => 'utf8', 'dbcollat' => 'utf8_general_ci', // 其他和主库一致的通用配置 ) );
这里最容易忽略的是pconnect = FALSE:如果开了持久连接,框架会复用旧的连接句柄,主库宕机后不会主动尝试重新连接,自然不会触发故障转移。
2. 验证故障转移的触发条件
CodeIgniter的故障转移不是主库一宕机就立刻自动切换,而是要在执行数据库查询时遇到连接错误才会触发。你不能只停留在“关闭主库服务”,要实际执行一个数据库操作(比如$this->db->get('your_table');),同时开启db_debug看是否有连接错误日志,以及框架是否尝试切换到备用库。
如果只是主库宕机但没有执行查询,框架不会主动检测主库状态,这是正常逻辑。
3. 检查环境变量是否正确加载
有时候环境变量没被正确读取,导致备用库的配置是空值或者错误值。可以在配置文件末尾加一行调试代码:
var_dump($db['mysql']['failover']); exit;
访问你的应用,看备用库的hostname、username、password等参数是否和预期一致,有没有空值或者拼写错误(比如把DB_BACKUP_HOST写成DB_BACKUP_HOSTS)。
4. 确认框架版本与配置匹配
CodeIgniter 3.x和4.x的故障转移配置结构差异很大:
- CI3是在
application/config/database.php的主库数组里加failover子数组; - CI4是在
app/Config/Database.php的$default配置里,把failover设为备用库的配置数组。
你说配置取自官方文档,一定要确认文档对应的是你正在使用的CI版本,别把CI3的配置用到CI4上。
5. 模拟连接错误测试(比直接关主库更靠谱)
有时候直接关闭主库服务可能会有缓存或者连接残留,不如主动模拟主库连接失败:把主库的hostname改成一个无效的地址(比如127.0.0.999),然后执行查询,看框架是否会自动切换到备用库。这种方式能排除主库宕机后的连接残留问题,更精准地测试故障转移逻辑。
6. 检查数据库缓存与其他干扰项
如果开启了cache_on = TRUE,框架可能会使用缓存的查询结果,不会去尝试连接数据库,导致故障转移没触发。测试时先把缓存关闭,再验证故障转移是否生效。
另外,如果你用了第三方数据库扩展或者自定义的数据库操作类,也要确认它们没有覆盖框架原生的故障转移逻辑。
7. 查看框架驱动源码(终极排查)
如果以上都没问题,可以直接看CI的数据库驱动源码:
- CI3:
system/database/drivers/mysqli/mysqli_driver.php里的reconnect()和failover()方法; - CI4:
system/Database/BaseConnection.php里的failover()相关逻辑。
通过源码可以看到故障转移的触发条件(比如只针对特定的数据库错误码),甚至可以在源码里加日志输出,看是否进入了故障转移的逻辑分支。
内容的提问来源于stack exchange,提问作者user3691635

