最近用微擎开发了几个基于微信公众号的项目,分析其主从配置实现方案
首先配置
/data/config.php
<?php
defined('IN_IA') or exit('Access Denied');
$config = array();
$config['db']['master']['host'] = '127.0.0.1';
$config['db']['master']['username'] = 'root';
$config['db']['master']['password'] = 'root';
$config['db']['master']['port'] = '3306';
$config['db']['master']['database'] = 'wq_yiliao';
$config['db']['master']['charset'] = 'utf8';
$config['db']['master']['pconnect'] = 0;
$config['db']['master']['tablepre'] = 'ims_';
$config['db']['slave_status'] = true;
$config['db']['slave']['1']['host'] = '127.0.0.1';
$config['db']['slave']['1']['username'] = 'root';
$config['db']['slave']['1']['password'] = 'root';
$config['db']['slave']['1']['port'] = '3306';
$config['db']['slave']['1']['database'] = 'wq_yiliao';
$config['db']['slave']['1']['charset'] = 'utf8';
$config['db']['slave']['1']['pconnect'] = 0;
$config['db']['slave']['1']['tablepre'] = 'ims_';
$config['db']['slave']['1']['weight'] = 0;
$config['db']['slave_status'] = true;
$config['db']['slave']['2']['host'] = '127.0.0.1';
$config['db']['slave']['2']['username'] = 'root';
$config['db']['slave']['2']['password'] = 'root';
$config['db']['slave']['2']['port'] = '3306';
$config['db']['slave']['2']['database'] = 'wq_yiliao';
$config['db']['slave']['2']['charset'] = 'utf8';
$config['db']['slave']['2']['pconnect'] = 0;
$config['db']['slave']['2']['tablepre'] = 'ims_';
$config['db']['slave']['2']['weight'] = 2;
$config['db']['common']['slave_except_table'] = array('core_sessions');
可以不断增加从库,从库还有权重;有不使用从库的表,core_session,微擎对session有数据库自定义处理,肯定得排除在外
其次对主库还是从库的选择,根据配置走主库还是从库
/framework/function/pdo.func.php
defined('IN_IA') or exit('Access Denied');
function pdo() {
global $_W;
static $db;
if(empty($db)) {
if($_W['config']['db']['slave_status'] == true && !empty($_W['config']['db']['slave'])) {
load()->classs('slave.db');
$db = new SlaveDb('master');
} else {
load()->classs('db');
if(empty($_W['config']['db']['master'])) {
$_W['config']['db']['master'] = $GLOBALS['_W']['config']['db'];
$db = new DB($_W['config']['db']);
} else {
$db = new DB('master');
}
}
}
return $db;
}
重点就是这个SlaveDb类,继承了Db类,根据规则把主库或者pdo对象返回,重点挑两个方法看
slave_choose 从库权重小算法
init_connect 中的
if(!(!$slave_except && strtoupper(substr($sql, 0 , 6)) === 'SELECT' && $this->slave_connect())) {
$this->master_connect();
}
发现了排除表,对于select走从库,其他的走主库
/framework/class/slave.db.class.php
protected function slave_choose(){
if(!isset($this->weight)) {
foreach ($this->cfg['slave'] as $key => $value) {
$this->weight .= str_repeat($key, 1 + intval($value['weight']));
}
}
$sid = $this->weight[mt_rand(0, strlen($this->weight) -1)];
$this->slaveid = 'slave_' . $sid;
if(!isset($this->cfg[$this->slaveid])) {
$this->cfg[$this->slaveid] = $this->cfg['slave'][$sid];
}
}
public function init_connect($sql) {
if(!($this->cfg['slave_status'] == true && !empty($this->cfg['slave']))) {
$this->master_connect();
} else {
$sql = trim($sql);
$sql_lower = strtolower($sql);
$slave_except = false;
if(!strexists($sql_lower, 'where ')) {
$tablename = substr($sql_lower, strpos($sql_lower, 'from ') + 5);
} else {
$tablename = substr($sql_lower, strpos($sql_lower, 'from ') + 5, strpos($sql_lower, ' where') - strpos($sql_lower, 'from ') - 5);
}
$tablename = trim($tablename, '`');
$tablename = str_replace($this->tablepre, '', $tablename);
if(!empty($this->cfg['common']['slave_except_table']) && in_array(strtolower($tablename), $this->cfg['common']['slave_except_table'])) {
$slave_except = true;
}
if(!(!$slave_except && strtoupper(substr($sql, 0 , 6)) === 'SELECT' && $this->slave_connect())) {
$this->master_connect();
}
}
return true;
}