悠悠楠杉
PHP如何实现数据库读写分离:配置方法详解
在实际Web开发中,数据库往往成为性能瓶颈。当单台MySQL服务器QPS超过2000时,读写分离就成了必选项。下面通过具体案例演示PHP环境下的完整实现流程。
一、主从数据库基础配置
首先需要在MySQL服务器层完成主从同步(Replication)配置:
```sql
-- 主库my.cnf
[mysqld]
server-id=1
log-bin=mysql-bin
binlog-format=ROW
-- 从库my.cnf
[mysqld]
server-id=2
relay-log=mysql-relay-bin
read-only=1
```
完成配置后,通过CHANGE MASTER TO
命令建立主从关系,使用SHOW SLAVE STATUS
验证同步状态。
二、PHP原生实现方案
通过PDO扩展手动管理连接:
```php
class DBConnection {
private static $writeconn;
private static $readconns = [];
public static function getWriteConnection() {
if(!self::$write_conn){
self::$write_conn = new PDO(
'mysql:host=master.db;dbname=app',
'user',
'password',
[PDO::ATTR_PERSISTENT => true]
);
}
return self::$write_conn;
}
public static function getReadConnection() {
if(empty(self::$read_conns)){
$slaves = [
['host'=>'slave1.db', 'weight'=>3],
['host'=>'slave2.db', 'weight'=>2]
];
// 按权重随机选择
$selected = self::weightedRandom($slaves);
self::$read_conns[] = new PDO(
"mysql:host={$selected['host']};dbname=app",
'user',
'password'
);
}
return self::$read_conns[array_rand(self::$read_conns)];
}
}
```
使用时分场景调用不同连接:
```php
// 写入操作
$pdo = DBConnection::getWriteConnection();
$pdo->prepare("INSERT INTO orders...")->execute();
// 读取操作
$pdo = DBConnection::getReadConnection();
$stmt = $pdo->query("SELECT * FROM products...");
```
三、框架集成方案
以Laravel为例,修改database.php配置:
php
'mysql' => [
'write' => [
'host' => env('DB_WRITE_HOST', 'master.db'),
],
'read' => [
'host' => [
'database' => env('DB_READ_HOST', 'slave1.db'),
'database' => env('DB_READ_HOST', 'slave2.db')
],
],
'sticky' => true // 写入后短暂时间内仍读主库
],
Yii2可通过配置行为实现:
php
'db' => [
'class' => 'yii\db\Connection',
'slaveConfig' => [
'username' => 'user',
'password' => 'pass',
'attributes' => [
PDO::ATTR_TIMEOUT => 10,
],
],
'slaves' => [
['dsn' => 'mysql:host=slave1.db;dbname=app'],
['dsn' => 'mysql:host=slave2.db;dbname=app'],
],
],
四、中间件代理方案
对于大型应用,推荐使用专业中间件:
1. MySQL Router:官方轻量级路由
2. ProxySQL:支持查询规则缓存
3. MaxScale:MariaDB企业级方案
配置示例(ProxSQL):
```sql
INSERT INTO mysqlservers(hostgroupid,hostname) VALUES
(10,'master.db'), (20,'slave1.db'), (20,'slave2.db');
INSERT INTO mysqlqueryrules (ruleid,active,matchpattern,destination_hostgroup) VALUES
(1,1,'^SELECT',20), (2,1,'^INSERT',10);
```
五、注意事项
- 主从延迟:重要业务需读主库,可添加
/*#FORCE_MASTER*/
注释强制路由 - 事务处理:开启事务时所有查询应走主库
- 连接池管理:建议使用Swoole等常驻内存方案避免频繁连接
- 监控指标:定期检查SecondsBehindMaster值
通过上述方案,某电商平台实测降低主库负载65%,查询响应时间从320ms降至110ms。建议根据实际业务压力逐步实施,初期可采用最简单的PHP手动分离方案。
经验之谈:读写分离不是银弹,配合Redis缓存、SQL优化、分库分表才能构建完整的高并发数据库架构。
```