1. 无聊的理论知识
什么是读写分离
读写分离,基本的原理是让主数据库处理事务性增、改、删操作, 而从数据库处理查询操作。
为什么使用读写分离
从集中到分布,最基本的一个需求不是数据存储的瓶颈,而是在于计算的瓶颈,即 SQL 查询的瓶颈,我们知道,正常情况下,Insert SQL 就是几十个毫秒的时间内写入完成,而系 统中的大多数 Select SQL 则要几秒到几分钟才能有结果,很多复杂的 SQL,其消耗服器 CPU 的能力超强,不亚于死循环的威力。
读写分离方案
MyCat的读写分离是建立在MySQL主从复制基础之上实现的,所以必须先搭建MySQL的主从复制。数据库读写分离对于⼤型系统或者 访问量很⾼的互联网应用来说,是必不可少的⼀个重要功能。
注意: Mycat实现的读写分离和自动切换机制,需要MySQL的主从复制机制配合。
读写分离存在的问题
主从数据延迟,导致业务数据无法保证强一致性
Mysql 主从复制的常用拓扑结构
一主一从 最基础的复制结构,用来分担之前单台数据库服务器的压力, 可以进行读写分离。
一主多从 一台 Slave 承受不住读请求压力时,可以添加多台,进行负载均衡,分散读压力。
双主复制 双主结构就是用来解决这个问题的,互相将对方作为自己的 Master,自己作为对方的 Slave 来进行复制,但对外来讲,还是一个主和一个从。
级联复制 级联结构就是通过减少直接从属于 Master 的 Slave 数量,减轻 Master 的压力,分散复制请求,从而提高整体的复制效率。
双主级联 Mysql 的复制结构有很多种方式,复制的最大问题是数据延时,选择复制结构时需要根据自己的具体情况,并评估好目标结构的延时对系统的影响。
2. Mycat搭建读写分离
本文以一主一从的读写分离方案搭建进行演示。
mycat是直接接管我们的请求,然后分发到不同的数据库中,我们程序也是直接连接mycat,而不是数据库了。
2.1 准备工作
在配置之前,我们需要准备两个数据库,一主一从,并且已经完成了主从同步的配置,测试用的数据库、表确保都已经存在,同时创建好mycat要用的账户(主库、从库都需要配置)。
Mysql主从同步同步搭建过程参考文章包教包会:Mysql主从复制搭建,这里就不再赘述了。
因为已经主从同步,创建语句只需要在master库执行即可
创建测试数据库语句:
CREATE DATABASE IF NOT EXISTS `test-xxf`;
创建测试表语句,当然这里也可以不创建,利用Mycat也可以进行创建表的操作。
CREATE TABLE `xxf_user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`user_name` VARCHAR(30) NULL DEFAULT NULL COMMENT '用户姓名',
`email` VARCHAR(50) NULL DEFAULT NULL COMMENT '用户邮箱',
`phone` VARCHAR(11) NULL DEFAULT NULL COMMENT '手机号码',
`sex` CHAR(1) NULL DEFAULT NULL COMMENT '用户性别',
PRIMARY KEY (`id`) USING BTREE
) COMMENT='笑小枫-用户信息表' COLLATE='utf8_general_ci' ENGINE=InnoDB;
创建Mycat的账号,如果开启了全部操作的主从库同步,在主库创建则自动会同步到从库。
CREATE USER 'mycat'@'%' IDENTIFIED BY '123456';
-- 必须要有的权限 mysql8才有的
GRANT XA_RECOVER_ADMIN ON *.* TO 'mycat'@'%';
-- 权限根据需求来给,这里直接给的全部权限
GRANT ALL PRIVILEGES ON *.* TO 'mycat'@'%' ;
flush PRIVILEGES;
2.2 Mycat配置
在Mycat安装部署一文中已经配置了prototypeDs.datasource.json
的数据库连接。这里无需改动。
{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ_WRITE",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"prototypeDs",
"password":"123456",
"type":"JDBC",
"url":"jdbc:mysql://localhost:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"mycat",
"weight":0
}
3.3 添加主数据源
进入mycat目录下的conf/datasources
目录,复制 prototypeDs.datasource.json
并将名称设为master.datasource.json
。
cp prototypeDs.datasource.json master.datasource.json
操作完后,如下图所示:
修改master.datasource.json
vim master.datasource.json
主要修改数据源成jdbc:mysql://localhost:3306/test-xxf
、name属性为master
,如果用户名密码发生变化,则需要一并修改,然后保存退出。
{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ_WRITE",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"master",
"password":"123456",
"type":"JDBC",
"url":"jdbc:mysql://localhost:3306/test-xxf?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"mycat",
"weight":0
}
如果有多个主节点就再配置一份叫mater02.datasource.json
3.4 添加从数据源
同主数据源配置一样,复制master.datasource.json
设置为slave.datasource.json
,然后进行编辑
cp master.datasource.json slave.datasource.json
vim slave.datasource.json
主要修改数据源成从库连接jdbc:mysql://localhost:3307/test-xxf
、name属性为slave
、读写模式instanceType改成只读模式READ
,如果用户名密码发生变化,则需要一并修改,然后保存退出。
{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"slave",
"password":"123456",
"type":"JDBC",
"url":"jdbc:mysql://localhost:3307/test-xxf?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"mycat",
"weight":0
}
如果有多个从节点就再配置一份叫slave02.datasource.json
3.5 配置数据源集群
由于配置读写分离涉及到多个数据库,所以就要配置数据源集群。
cd conf/clusters
cp prototype.cluster.json master-slave.cluster.json
vim master-slave.cluster.json
主要配置主从数据源的名称,值就对应前边配置数据源(*.datasource.json
)中所定义的值
修改name为(*.cluster.json
)中所定义的值
{
// 集群类型:SINGLE_NODE(单节点)、MASTER_SLAVE(普通主从)、GARELA_CLUSTER(garela cluster/PXC集群)等
"clusterType":"MASTER_SLAVE",
"heartbeat":{
"heartbeatTimeout":1000,
"maxRetry":3,
"minSwitchTimeInterval":300,
"slaveThreshold":0
},
"masters":[
// 主节点数据源名称
"master"
// "master02"
],
"replicas":[
// 从节点数据源名称
"slave"
// "slave02"
],
"maxCon":200,
// 集群名称。在后面配置物理库(schema)时会用到
"name":"master-slave",
"readBalanceType":"BALANCE_ALL",
// NOT_SWITCH(不进行主从切换)、SWITCH(进行主从切换)
"switchType":"NOT_SWITCH"
}
3.6 配置物理库 schemas和mycat数据源/集群的关联关系
上边的集群和数据源都配置好了,那么就差跟mycat关联起来了,让mycat知道我们配置好的目标库应该指向哪个物理库,创建一个新的master_slave.schema.json
文件。
cd conf/schemas
vim master_slave.schema.json
{
// 物理库
"schemaName": "test-xxf",
// 指向集群,或者数据源
"targetName": "master-slave",
// 这里可以配置数据表相关的信息,在物理表已存在或需要启动时自动创建物理表时配置此项
"normalTables": {}
}
至此读写分离配置完成,下边开始测试。
3. 测试Mycat读写分离
在mycat上执行命令,可以查看到Mycat的数据源
/*+ mycat:showDataSources{} */
连接mycat,在mycat里面执行sql。准备下面的sql语句,插入一条数据。
INSERT INTO `xxf_user` VALUES (1, '张三', 'zhangsan@xiaoxiaofeng.com', '18300000000', '1');
然后可以在master和slave里面都看到了插入的数据。
因为我们数据设置的是,主数据库向从数据库同步,所以写操作发生在master数据源,然后同步到slave数据库。
执行查询语句,可以看到刚刚插入的数据。
SELECT * FROM xxf_user;
为了更好的判断数据库读的是主库还是从库,我们手动修改从库的user_name为张三slave
,修改从库数据,不会往主库同步,日常使用中不要修改从库数据,不然会导致数据不一致。
可以看到,一会查询的是张三
,一会是张三slave
,证明两个库都会查询,权重的话,可以在datasources下的master和slave数据源文件下修改weight
属性。
4. 总结一下吧
本文主要讲解了如何使用Mycat实现一主一从的读写分离。一主多从、双主复制、多主多从,文章也是简单的提了一下,小伙伴门感兴趣可以自己去尝试,就是配置多个主从的数据源。
如果在搭建的过程中有任何疑问,可以评论区留言或者关注微信公众号留言,博主看到会及时的给予解答。
5. 本系列文章
本系列文章持续更新中,包括Mycat搭建,读写分离,分库分表等,敬请期待。
后续更新完成统一维护链接,占个坑先…