数据库读写分离对于大型系统或者访问量很高的互联网应用来说,是必不可少的一个重要功能。对于MySQL来说,标准的读写分离是主从模式,一个写节点Master后面跟着多个读节点,读节点的数量取决于系统的压力,通常是1-3个读节点的配置。
Mycat读写分离和自动切换机制,需要mysql的主从复制机制配合。
从 Mycat 1.4 开始支持MySQL主从复制状态绑定的读写分离机制,让读更加安全可靠,配置如下:
配置文件的意思是:
[root@mycat-server conf]# vim schema.xml
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="small" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_item" dataNode="dn1" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()heartbeat>
<writeHost host="hostM" url="mysql-server-01:3306" user="root" password="888888">
<readHost host="hostS" url="mysql-server-02:3306" user="root" password="888888" />
writeHost>
dataHost>
mycat:schema>
执行如下建表语句,执行之后可以看到Master服务器上的数据库 db1 中存在了 tb_item 表。再看看Slave服务器上的 db1 数据库中也存在了 tb_item 表。
-- ----------------------------
-- Table structure for tb_item
-- ----------------------------
DROP TABLE IF EXISTS `tb_item`;
CREATE TABLE `tb_item` (
`id` bigint(20) NOT NULL COMMENT '商品id,同时也是商品编号',
`title` varchar(100) NOT NULL COMMENT '商品标题',
`sell_point` varchar(500) DEFAULT NULL COMMENT '商品卖点',
`price` bigint(20) NOT NULL COMMENT '商品价格,单位为:分',
`num` int(10) NOT NULL COMMENT '库存数量',
`barcode` varchar(30) DEFAULT NULL COMMENT '商品条形码',
`image` varchar(500) DEFAULT NULL COMMENT '商品图片',
`cid` bigint(10) NOT NULL COMMENT '所属类目,叶子类目',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '商品状态,1-正常,2-下架,3-删除',
`created` datetime NOT NULL COMMENT '创建时间',
`updated` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `cid` (`cid`),
KEY `status` (`status`),
KEY `updated` (`updated`)
) COMMENT='商品表';
INSERT INTO TB_ITEM (
ID,
TITLE,
SELL_POINT,
PRICE,
NUM,
BARCODE,
IMAGE,
CID,
STATUS,
CREATED,
UPDATED
)
VALUES
(
'15000000',
'夏普(SHARP)LCD-52DS51A 52英寸 日本原装液晶面板 内置WIFI智能全高清液晶电视',
'要好屏,选夏普!日本原装面板,智能电视,高画质高音质!还有升级版安卓智能新机52DS52供您选择!',
'549900',
'99999',
NULL,
'http://image.taotao.com/jd/63af01c37a18454ab2fef4670046272e.jpg',
'76',
'1',
'2015-03-08 21:27:45',
'2015-03-08 21:27:45'
);
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="small" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_item" dataNode="dn1" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()heartbeat>
<writeHost host="hostM1" url="mysql-server-01:3306" user="root" password="888888">writeHost>
<writeHost host="hostS1" url="mysql-server-02:3306" user="root" password="888888">writeHost>
dataHost>
mycat:schema>
以上两种配置方式,第一种当写挂了读不可用,第二种可以继续使用。另外,事务内部的一切操作都会走写节点,所以读操作不要加事务。
如果读延时较大,我们可以使用MyCat注解的方式强制走写节点。
继续上面测试部分的第四小节:测试读写分离。接下来测试MyCat的注解方式。
图中可能看不清楚,强制走写节点的语句如下:
/*#mycat:db_type=master*/ SELECT * FROM tb_item ;
另外,测试时发现强制走读节点失败,不知道为什么,也没有深究(实在没有多少时间):
/*#mycat:db_type=slave*/ SELECT * FROM tb_item ;
1.4 开始支持 MySQL 主从复制状态绑定的读写分离机制,让读更加安全可靠,配置如下:
switchType="2"
和 slaveThreshold="100"
,此时意味着开启 MySQL 主从复制状态绑定的读写分离与切换机制;Mycat 心跳机制通过检测 show slave status 中的 "Seconds_Behind_Master"
,"Slave_IO_Running"
,"Slave_SQL_Running"
三个字段来确定当前主从同步的状态以及 Seconds_Behind_Master 主从复制时延。当 Seconds_Behind_Master > slaveThreshold
时,读写分离筛选器会过滤掉此 Slave 机器,防止读到很久之前的旧数据。而当主节点宕机后,切换逻辑会检查 Slave 上的 Seconds_Behind_Master 是否为 0,为 0 时则表示主从同步,可以安全切换,否则不会切换。
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="small" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_item" dataNode="dn1" />
schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0"
dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave status heartbeat>
<writeHost host="hostM1" url="mysql-server-01:3306" user="root" password="888888">writeHost>
<writeHost host="hostS1" url="mysql-server-02:3306" user="root" password="888888">writeHost>
dataHost>
mycat:schema>
将主节点(写节点)停止,再插入一条数据,可以看到是可以插入的,此时写节点已经关闭,读节点出现了俩条数据:
另外,注意:将主节点重新启动,MyCat 不会重新将其加入进来。(已亲自试验)
官方文档中有这么一段:
writeType="0", 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个
writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties .