MySQL-PHP DB类 怎样能使已有应用平滑过渡到MYSQL主从模式

MySQL-PHP DB类 怎样能使已有应用平滑过渡到MYSQL主从模式

虐人心 发布于 2017-02-19 字数 3932 浏览 1157 回复 4

当前 数据库架构已经设置成 主从模式

对于应用来讲,当前使用了wp中使用的DB类,我如何修改这个PHP DB类能够使应用平滑的过渡到 主/从模式,就是说 我只是在底层去修改 DB类,而对上层应用中的代码保持不变

要求做到 主库只写数据;从库 读数据

/**
* 关于读写分离的一些想法
*
* 基于 主/从 数据库部署模式的数据操作的封装,能够对要执行的操作进行自动甄别.
* 一般而言: 对主库都进行Write ,而对 从库 则是进行Read
*
* 难点在于如何甄别 操作的类型是 读/写 ?
*
* Read 操作主要是 select 查询;
* Write 操作主要是
* 1. 创建/删除/修改 表,视图,触发器等;
* 2. 插入/删除/更新/替换 表记录数据
*
* 如何 进行 甄别呢?
* 1. 由调用者手工指定要执行的是什么操作
* 2. 由程序自动识别要执行的sql是什么操作
*
*/





自己的一些 主从模式分离的理解以及雏形代码
/**
* CoreDbExecutor 用于对底层数据库的读/写 操作进行分离
*
* 数据库的执行的操作总体分为两大类: 读/写
*
* 关于读写分离的一些想法
*
* 对于 主/从 数据库部署模式的数据操作,要能够对要执行的操作进行自动甄别.
* 一般而言: 对主库都进行Write ,而对 从库 则是进行Read
*
* 难点在于如何甄别 操作的类型是 读/写 ?
*
* Read 操作主要是 select,show 等查询;
* Write 操作主要是
* 1. 创建/删除/修改 表,视图,触发器等;
* 2. 插入/删除/更新/替换 表记录数据
*
* 如何 进行 甄别呢?
* 1. 由调用者手工指定要执行的是什么操作
* 2. 由程序自动识别要执行的sql是什么操作
*
* 此处选择的是 第一种实现方式,故定义 getReader()|getWriter()
*
* 不论 单一DB模式;主/从DB模式;集群DB模式 都应实现这个接口来提供读写分离
*
* 在应用的内部凡需要使用DB服务的地方都必须 明确选择使用哪种操作方式,以方便以后的模式切换
*
*/
interface CoreDbExecutor {

/**
* @return CoreDb
*/
function getReader();

/**
* @return CoreDb
*/
function getWriter();

}

/**
* 单数据库执行者模式: 读/写 均使用一个数据库
*
*/
class CoreDbMajor implements CoreDbExecutor {

private $db = null;

function __construct(array $dsn){
$this->db = CoreDB::instance($dsn);
}

function getReader() {
if (!$this->db->isConnect()) $this->db->connect();
return $this->db;
}

function getWriter() {
if (!$this->db->isConnect()) $this->db->connect();
return $this->db;
}

}

/**
* 主/从数据库执行者模式: 读 使用从数据库;写 使用主数据库
*
*/
class CoreDbMasterSlaver implements CoreDbExecutor {

const key_master = 'master';
const key_slaver = 'slaver';

/**
* @var CoreDB
*/
protected $masterDB = null;

/**
* @var CoreDB
*/
protected $slaverDB = null;

function __construct(array $config){
$masterDsn = isset($config[self::key_master]) ? $config[self::key_master] : null;
$slaverDsn = isset($config[self::key_slaver]) ? $config[self::key_slaver] : null;

if (empty($masterDsn)){
throw new InvalidDSNException($masterDsn);
}
if (empty($slaverDsn)){
throw new InvalidDSNException($slaverDsn);
}

$this->masterDB = CoreDB::instance($masterDsn);
$this->slaverDB = CoreDB::instance($slaverDsn);
}

function getReader() {
if (!$this->slaverDB->isConnect()) $this->slaverDB->connect();
return $this->slaverDB;
}

function getWriter() {
if (!$this->masterDB->isConnect()) $this->masterDB->connect();
return $this->masterDB;
}

}

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

虐人心 2017-10-27 4 楼

我之前碰到的情形,DB连接类里的底层将DML(CRUD)语句和普通查询语句用exec和query分开了。比较顺利的无缝切换到了主从分离。
最大的问题是主从之间的数据延时没法控制,对于一些实时性要求特别高的细节没能找到轻量级方案完美解决。
淘宝在这方面做了很多底层研发,参考资料:
http://www.taobaodba.com/html/category/mysql-2

虐人心 2017-07-13 3 楼

如果你当前已经有现成的DB类来操作数据库,那么就不建议你去改一个开源框架或者现成系统的DB层,MySQL提供了一个代理叫做MySQL Proxy完全可以满足你的要求而且不需要改动任何代码,它会自动识别MySQL实例访问的SQL是读操作还是写操作。

参考资料:
http://hi.baidu.com/ge_geshuai/blog/item/c31ce595f28d2655d0135e7f.html

泛泛之交 2017-05-05 2 楼

我们以前是这样做的:
配置文件中
$wdb=array("host"=>"192.168.0.1",'port'=>3306,'user'=>'abc','pwd'=>'abc');
$rdb=array("host"=>"192.168.0.2",'port'=>3306,'user'=>'abc','pwd'=>'abc');

然后在DB中实例化两个link,
然后通过DB::getWDB() ---获取指向$wdb的数据库

DB::getRDB() ---获取指向$rdb的数据库

在开始阶段时,只有一台数据库服务器:192.168.0.1,rdb,wdb都指向192.168.0.1,到配置主从结构时,改ip即可

晚风撩人 2017-05-03 1 楼

我觉得还是看业务层都提供了哪些db方法,全部列出来, getALL/getOne/update/insert/delete/其他,不允许业务层使用列表之外的方法,然后上层根据这些方法自动获取主从的实例,对于业务层算是实现平滑过度了;关键是一定要有规则不能乱用