正文
在项目数据读写遇到瓶颈时,首先想到的就是分库、分表,然后就是读写分离。
分库标准是项目分类,针对不同项目,如果用户群体角色也不同,数据不交叉(如项目质量管理和客户数据管理就不交叉),那就可以分成多个库,这样可以从一定程度上减轻库的压力。
分表标准是功能分类,不同的功能尽量分成不同的表,还可以把使用频次高低考虑进来,频次低的也单独建个关联表吧。
接下来是重点:数据库读写分离,主从数据库。
在yii2的项目配置项目中修改,一主多从:
'db' => [
'class' => 'yii\db\Connection',
// 主库配置
'dsn' => 'mysql:host=192.168.0.1;port=3306;dbname=company',
'username' => 'root',
'password' => 'root',
'charset' => 'utf8',
// 从库配置
'slaveConfig' => [
'username' => 'root',
'password' => 'root',
'charset' => 'utf8',
],
'slaves' => [
['dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=company'],
['dsn' => 'mysql:host=127.0.0.2;port=3306;dbname=company']
['dsn' => 'mysql:host=127.0.0.3;port=3306;dbname=company']
['dsn' => 'mysql:host=127.0.0.4;port=3306;dbname=company']
['dsn' => 'mysql:host=127.0.0.5;port=3306;dbname=company']
],
],
看一个多主多从配置:
'db' => [
'class' => 'yii\db\Connection',
'charset' => 'utf8',
// 主库配置
'masterConfig' => [
'username' => 'root',
'password' => 'root',
'attributes' => [
PDO::ATTR_TIMEOUT => 5
]
],
'masters' => [ //主库列表 配置单项
['dsn' => 'mysql:host=192.168.0.1;port=3306;dbname=company'],
['dsn' => 'mysql:host=192.168.0.2;port=3306;dbname=company'],
],
// 从库配置
'slaveConfig' => [
'username' => 'root',
'password' => 'root',
'attributes' => [
PDO::ATTR_TIMEOUT => 10
]
],
'slaves' => [
['dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=company'],
['dsn' => 'mysql:host=127.0.0.2;port=3306;dbname=company'],
['dsn' => 'mysql:host=127.0.0.3;port=3306;dbname=company'],
['dsn' => 'mysql:host=127.0.0.4;port=3306;dbname=company'],
['dsn' => 'mysql:host=127.0.0.5;port=3306;dbname=company'],
],
],
可以看到,是连接的不同服务器IP。服务器上mysql读写分离的配置看这里:
http://www.yii-china.com/post/detail/283.html
数据库做了读写分离,可不能卡在项目程序里,所以项目相应的读写处也要做读写分离。
models中按库建立文件夹生成model文件。sources中按读写分离建文件夹。
比如读的部分,引入model然后具体读取:
写的,就只负责写入和更新:
如果遇到必须查主库的情况,也有对应方法示例:
public function getKehuInfoById( $id )
{
return Yii::$app->db->useMaster(function() use ($id) {
return Kehu::findOne( $id );
});
}
看一下useMaster源码:
public function useMaster(callable $callback)
{
$enableSlave = $this->enableSlaves;
$this->enableSlaves = false;
$result = call_user_func($callback, $this);
$this->enableSlaves = $enableSlave;
return $result;
}
看到这里应该就会发现,只是把 Yii::$app->db->enableSlaves 的属性值改了一下,所以我们也可以这么用:
Yii::$app->db->enableSlaves = false;
$res = Kehu::findOne( $id );
Yii::$app->db->enableSlaves = true;
现在有一种情况是数据库主从同步存在延迟,如果在一个程序线程中存入后就要读取这条数据怎么办呢?数据肯定读不到,只有主库有。 还有一种情况是,数据存入后,通过异步程序读取,现在就取决于数据库主从同步的速度和异步调用的速度中谁快了。这不是人为能把握的: 如果读从库,数据可能还没同步过来,导致读不到数据;如果指定读主库,主库压力还是没解决,那我们设置数据库主从就没有意义了。 我们需要一种解决方案。
其实我们可以这样操作:我们先读从库,如果读不到数据,再去读主库,这样就增加了灵活性,而且照顾了初衷。
如下:
public function getKehuInfoById($id)
{
$model = Kehu::findOne($id);
if (empty($model)) {
$model = Yii::$app->db->useMaster(function() use ($id) {
return Kehu::findOne($id);
});
}
return $model;
}
参考资料
http://blog.sina.com.cn/s/blog_6aba78b40102xc3v.html
http://www.yiichina.com/doc/guide/2.0/db-dao
https://blog.csdn.net/qmhball/article/details/53668113