本文目录导读:

- 使用 Laravel (框架层面)
- 使用 ThinkPHP 6.0+ (框架层面)
- 使用 PHP 原生 + PDO (自研封装)
- 使用数据库中间件 (最推荐)
- 主从延迟与权重的关系(重要)
- 推荐配置层级
- 注意事项
在 PHP 中配置读写分离权重,通常需要结合数据库中间件、ORM 框架或自研封装来实现,下面列出几种常见的配置方式,从框架层面到中间件层面。
使用 Laravel (框架层面)
Laravel 原生支持读写分离,但不支持权重,要实现权重负载,需要结合第三方包或自定义逻辑。
① 原生配置(无权重,随机/轮询)
// config/database.php
'mysql' => [
'read' => [
'host' => [
'192.168.1.1',
'192.168.1.2',
'192.168.1.3',
],
],
'write' => [
'host' => [
'192.168.1.100',
],
],
'sticky' => true,
'driver' => 'mysql',
'database' => 'schema',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
],
② 使用第三方包(支持权重)
推荐包:laravel-doctrine 或自定义连接器。
// 自定义服务提供者中绑定连接器
use Illuminate\Database\Connection;
use Illuminate\Database\Connectors\MySqlConnector;
$this->app->bind('db.connector.mysql', function ($app, $config) {
// 重写 createConnection 方法,在内部实现权重随机算法
});
使用 ThinkPHP 6.0+ (框架层面)
ThinkPHP 6 支持读写分离,并且支持权重配置。
核心配置:
// config/database.php
return [
'connections' => [
'mysql' => [
'type' => 'mysql',
'host' => '192.168.1.100', // 主库(写)
'username' => 'root',
'password' => '',
'database' => 'demo',
// 读写分离配置
'rw_separate' => true,
'read' => [
'host' => [
// 格式:'权重' => '主机'
'weight' => [
'192.168.1.1' => 3, // 权重3
'192.168.1.2' => 2, // 权重2
'192.168.1.3' => 1, // 权重1
],
],
'username' => 'root',
'password' => '',
],
],
],
];
备注:ThinkPHP 内置了 parseWeight 方法,会按照权重比例随机选取从库。
使用 PHP 原生 + PDO (自研封装)
自己写一个数据库连接管理器,实现权重随机。
class DatabaseManager
{
private $readHosts = [
['host' => '192.168.1.1', 'weight' => 3],
['host' => '192.168.1.2', 'weight' => 2],
['host' => '192.168.1.3', 'weight' => 1],
];
private $writeHost = ['host' => '192.168.1.100'];
/**
* 根据权重随机选择从库
*/
private function selectReadHost()
{
$totalWeight = array_sum(array_column($this->readHosts, 'weight'));
$rand = mt_rand(1, $totalWeight);
foreach ($this->readHosts as $host) {
$rand -= $host['weight'];
if ($rand <= 0) {
return $host['host'];
}
}
return $this->readHosts[0]['host'];
}
/**
* 获取 PDO 连接
*/
public function getConnection($isWrite = false)
{
$host = $isWrite ? $this->writeHost['host'] : $this->selectReadHost();
$dsn = "mysql:host={$host};dbname=your_db;charset=utf8mb4";
return new PDO($dsn, 'username', 'password');
}
/**
* 判断 SQL 是读还是写
*/
public function query($sql)
{
$trimmed = trim($sql);
$isWrite = !preg_match('/^(SELECT|SHOW|DESCRIBE|EXPLAIN)/i', $trimmed);
$conn = $this->getConnection($isWrite);
return $conn->query($sql);
}
}
使用数据库中间件 (最推荐)
在实际生产环境中,不推荐在业务代码中配置权重,因为会耦合数据库拓扑,推荐使用中间件:
| 中间件 | 权重配置示例 |
|---|---|
| MySQL Proxy | read_weight = 3:2:1 |
| MyCat | <dataHost balance="1" writeType="0" dbType="mysql"><readHost host="..." weight="3"/></dataHost> |
| ProxySQL | INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (2, 'slave1', 3306, 3); |
| MaxScale | servers = ( slave1, slave2, slave3 ) + weights = 3,2,1 |
| Vitess | 通过 VSchema 配置 weight |
ProxySQL 配置示例:
-- 添加主机并设置权重 INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (2, '192.168.1.1', 3306, 300), (2, '192.168.1.2', 3306, 200), (2, '192.168.1.3', 3306, 100); LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;
PHP 代码只需要连接 ProxySQL 一个入口,完全不需要关心权重逻辑。
主从延迟与权重的关系(重要)
权重配置需要结合主从延迟考虑:
- 延迟高的从库应降低权重(
weight设置小)。 - 建议采用动态权重,例如根据
SHOW SLAVE STATUS的Seconds_Behind_Master实时调整。 - 若业务数据一致性要求高,建议
sticky(会话保持)开启,确保写后立即读到新数据。
推荐配置层级
- 小型项目(单机 PHP):使用 ThinkPHP 8 内置权重配置(最简单)。
- 中型项目(多实例):使用 ProxySQL 中间件统一管理权重。
- 大型分布式架构:使用云数据库(如阿里云 PolarDB、腾讯云 TDSQL),它们自带读写分离和权重策略,PHP 只需连接一个入口。
注意事项
- 权重比例是随机概率,并不是严格轮询。
- 如果从库宕机,需要健康检查剔除节点,否则会导致部分请求失败。
- 建议在业务代码层面加上降级策略:当从库全部不可用时,自动切换主库兜底。