如何在ThinkPHP中配置数据库主从分离_分布式数据库连接方案

1次阅读

thinkphp 6 主从配置需满足:default 必须存在且 type=‘mysql’,slave 为含完整数据库参数的数组;读写分离默认生效,select 轮询从库,INSERT/UPDATE/delete 走主库;强一致性读需显式调用 ->master(true)。

如何在ThinkPHP中配置数据库主从分离_分布式数据库连接方案

ThinkPHP 6 的 database.php 怎么配主从?

主从配置不是加个“slave”键就完事,TP6 要求显式声明 typemysql,且主库必须叫 default,从库必须放在 slave 数组里——漏掉任一条件都会降级成单库连接。

常见错误现象:Db::table('user')->select() 始终走主库,slave 配置完全不生效。

  • default 必须存在,且不能是空数组;它只负责写操作和未指定读写意图的查询
  • slave 是数组,每个元素是一个完整数据库配置(含 hostnameusername 等),不是只填 IP
  • 所有从库配置里不要设 deployrw_separate,TP6 已废弃这些旧键
  • 如果用了 pdo 连接池或长连接,记得在从库配置中加 'params' => [PDO::ATTR_PERSISTENT => true],否则每次查从库都重建连接

示例关键片段:

'default' => [     'type'            => 'mysql',     'hostname'        => 'master.example.com',     'database'        => 'app_db',     'username'        => 'root',     'password'        => 'xxx', ], 'slave' => [     [         'type'     => 'mysql',         'hostname' => 'slave1.example.com',         'database' => 'app_db',         'username' => 'ro_user',         'password' => 'yyy',     ],     [         'type'     => 'mysql',         'hostname' => 'slave2.example.com',         'database' => 'app_db',         'username' => 'ro_user',         'password' => 'zzz',     ], ],

读写分离怎么触发?Db::connect()->master() 有什么区别?

TP6 默认只在 INSERT/UPDATE/DELETE 时自动走主库,SELECT 默认轮询从库——但前提是没手动干预连接对象。一旦你调用 Db::connect('slave'),就等于绕过内置路由,后续所有操作都固定走那个从库,不再负载均衡

立即学习PHP免费学习笔记(深入)”;

容易踩的坑:在事务中混用读写,比如先 Db::transaction(function () { ... Db::table('log')->select(); ... });,此时 select() 仍可能被发到从库,导致事务一致性断裂(MySQL 从库默认不支持事务内读写混合)。

  • 强制走主库查数据:用 Db::name('user')->master(true)->select()
  • 强制走某从库:不推荐,但可 Db::connect(['hostname' => 'slave1.example.com', ...])->table('user')->select()
  • 想让某个 SELECT 也走主库(比如刚写完立刻读),必须显式加 ->master(true),别指望“刚写完会自动同步”
  • 关联查询(with())默认主库 + 从库混合走,但如果关联表跨库或主从延迟高,结果可能不一致

从库延迟导致数据查不到,怎么兜底?

TP6 没内置延迟检测或自动切回主库机制。所谓“强一致性读”,得自己控制:对时效性敏感的读操作(如用户刚提交订单后查订单状态),一律加 ->master(true)

更现实的做法是分层处理:普通列表页走从库,详情页 ID 查询加缓存+主库兜底。别幻想靠配置项解决延迟问题。

  • 不要依赖 slave_balance(TP6 不支持该配置),轮询策略是硬编码在 thinkdbconnectorMysql 里的,无法插件化替换
  • 监控从库延迟:需单独执行 SHOW SLAVE STATUS,TP6 不提供钩子自动采集
  • 如果业务允许几秒延迟,可在从库查询前加 sleep(0.1) 等待同步(仅测试环境,生产禁用)
  • 真正可靠的方案是应用层加缓存,比如用 redis 存刚写入的记录,查缓存命中则不查 DB

多从库下连接数爆了怎么办?

TP6 每个从库配置会独立维护连接池,默认最大连接数由 params' => [PDO::MYSQL_ATTR_MAX_BUFFER_SIZE] 之类控制不了,实际取决于 PHP-FPM 的 pm.max_children 和 MySQL 侧的 max_connections

现象:上线后 MySQL 报 Too many connections,但 show processlist 显示大量 Sleep 状态连接来自不同从库地址。

  • 给每个从库配置加 'break_reconnect' => true,断连时主动释放资源,而不是等超时
  • 限制从库数量,TP6 对超过 3 个从库的轮询性能无优化,反而增加连接管理开销
  • 确认是否误开了 'debug' => true,开启调试后每条 SQL 都会额外建连接做日志记录
  • Db::close() 主动关闭不用的从库连接,尤其在长生命周期的 CLI 命令中

主从分离不是银弹,配置只是第一步。真正卡住人的,永远是主从延迟、连接泄漏、事务边界和缓存一致性——这些没法靠改几个数组键解决。

text=ZqhQzanResources