Laravel 不支持主库恢复后自动回切,因其读写分离基于静态配置且无健康监听机制;需自定义连接工厂或服务发现实现按需健康检查与路由。

主库宕机后 Laravel 为什么没自动切回?
Laravel 本身不提供“主库恢复后自动切回”的能力,DB::connection() 的连接选择是请求级的、无状态的,它不会监听主库健康状态变化,更不会后台轮询或触发重连切换。所谓“自动回切”,必须自己实现健康检查 + 连接路由逻辑。
用 DB::reconnect() 强制重连主库行不行?
不行。这个方法只在当前连接已断开时尝试重建连接,但它不会改变连接池里已存在的从库连接,也不会影响后续请求的读写分离路由决策。Laravel 的读写分离靠的是 Connection 实例内部的 $readPdo / $writePdo 分离机制,不是靠运行时动态替换。
-
DB::reconnect()只对当前连接实例生效,且仅限于该实例下一次查询前重连 - 新请求仍会走默认的读写分离策略(比如读走从库、写走主库),主库是否可用由配置决定,不自动探测
- 如果主库刚恢复但连接池里还缓存着旧的失败连接,
reconnect()可能仍报PDOException: SQLSTATE[HY000] [2002] Connection refused
真正可行的回切方案:自定义连接工厂 + 健康检查兜底
核心思路是接管 Laravel 的连接创建过程,在每次获取主库连接前先做轻量健康检查;失败则降级到从库,成功则允许写操作继续走主库。这不是“全局切换”,而是按需、实时判断。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 在
App\Providers\AppServiceProvider::boot()中监听Illuminate\Database\Events\ConnectionEstablished,但该事件太晚,无法干预连接选择 - 推荐做法:重写
Illuminate\Database\Connectors\ConnectionFactory,或更简单——在config/database.php的mysql配置中,把host改成一个封装了健康检查的自定义 host 解析器(例如返回env('DB_PRIMARY_HOST', '127.0.0.1'),再配合外部哨兵脚本更新该 env) - 生产级建议:用 Consul 或 etcd 做服务发现,Laravel 启动时拉取当前主库地址,定期刷新;避免轮询 DB 端口(会增加 DB 负载)
- 临时应急:加一层中间件,在写操作前调用
DB::select('SELECT 1')测试主库连通性,失败则抛出DBWriteDownException并 fallback 到队列重试或降级提示
最容易被忽略的坑:事务 + 主从延迟 + 连接复用
即使你实现了“主库恢复即刻回切”,以下三点会让行为不可控:
- PHP-FPM 进程复用 DB 连接,
pdo对象可能长期持有已失效的主库句柄,直到超时或异常才释放——这不是 Laravel 控制的,是 PDO 底层行为 - 事务中执行了写操作,但主库刚好在 commit 前恢复,此时从库还没同步完,紧接着的读请求若走从库,会查不到刚写的记录(主从延迟)
- 使用
DB::transaction()时,Laravel 默认将整个事务绑定到主库连接;但如果事务中途主库宕机又恢复,PDO 不会自动重连,会直接报错而非静默切从库
所以“自动回切”从来不是单点修复,它必须和连接生命周期管理、事务语义、读写一致性要求一起设计。没有银弹,只有权衡。

















