3、读写分离配置扩展
通过对集群配置的修改,可以根据需求实现更多种情况的读写分离配置,总结如下
(1)读写分离(一主一从,无备)(m是主,s是从)
{ "clusterType":"MASTER_SLAVE", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "m" ], "maxCon":200, "name":"prototype", "readBalanceType":"BALANCE_ALL", "replicas":[ "s" ], "switchType":"SWITCH" }
(2)读写分离(一主一从,一备)(m是主,s是从备)
{ "clusterType":"MASTER_SLAVE", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "m","s" ], "maxCon":200, "name":"prototype", "readBalanceType":"BALANCE_ALL", "replicas":[ "s" ], "switchType":"SWITCH" }
(2)读写分离(一主一从,一备)(m是主,s是从,b是备)
{ "clusterType":"MASTER_SLAVE", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "m","b" ], "maxCon":200, "name":"prototype", "readBalanceType":"BALANCE_ALL", "replicas":[ "s" ], "switchType":"SWITCH" }
(4)MHA(一主一从,一备)(m是主,s是从,b是备,READ_ONLY判断主)
{ "clusterType":"MHA", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "m","b" ], "maxCon":200, "name":"prototype", "readBalanceType":"BALANCE_ALL", "replicas":[ "s" ], "switchType":"SWITCH" }
(5)MGA(一主一从,一备)(m是主,s是从,b是备,READ_ONLY判断主)
{ "clusterType":"MGA", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "m","b" ], "maxCon":200, "name":"prototype", "readBalanceType":"BALANCE_ALL", "replicas":[ "s" ], "switchType":"SWITCH" }
(6)GARELA_CLUSTER(一主一从,一备)(m是主,s是从,b多主)
{ "clusterType":"GARELA_CLUSTER", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "m","b" ], "maxCon":200, "name":"prototype", "readBalanceType":"BALANCE_ALL", "replicas":[ "s" ], "switchType":"SWITCH" }
第四章 垂直拆分——分库
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同 的数据库上面,这样也就将数据或者说压力分担到不同的库上面,如下图:
系统被切分成了,用户,订单交易,支付几个模块。
5.1 如何分库
一个问题:在两台主机上的两个数据库中的表,能否关联查询?
答案:不可以关联查询
分库的原则: 有紧密关联关系的表应该在一个库里,相互没有关联关系的表可以分到不同的库里。
#客户表 rows:20万 CREATE TABLE customer( id INT AUTO_INCREMENT, NAME VARCHAR(200), PRIMARY KEY(id) ); #订单表 rows:600万 CREATE TABLE orders( id INT AUTO_INCREMENT, order_type INT, customer_id INT, amount DECIMAL(10,2), PRIMARY KEY(id) ); #订单详细表 rows:600万 CREATE TABLE orders_detail( id INT AUTO_INCREMENT, detail VARCHAR(2000), order_id INT, PRIMARY KEY(id) ); #订单状态字典表 rows:20 CREATE TABLE dict_order_type( id INT AUTO_INCREMENT, order_type VARCHAR(200), PRIMARY KEY(id) );
以上四个表如何分库?客户表分在一个数据库,另外三张都需要关联查询,分在另外一个数据库。
5.2 如何分表
1、选择要拆分的表
MySQL单表存储数据条数是有瓶颈的,单表达到1000万条数据就达到了瓶颈,会影响查询效率,需要进行水平拆分(分表)进行优化。
例如:例子中的orders、orders…detail都已经达到600万行数据,需要进行分表优化。
2、 分表字段
以 orders 表为例,可以根据不同自字段进行分表
编号 | 分表字段 | 效果 |
1 | id(主键、 或创建时间) | 查询订单注重时效,历史订单被查询的次数少,如此分片会造成一个节点访问多,一个访问少,不平均。 |
2 | customer_id(客户 id) | 根据客户 id 去分,两个节点访问平均,一个客户的所 有订单都在同一个节点 |
5.3 实现分库分表
首先,不需要双主双从了
删掉数据源
Mycat2 一大优势就是可以在终端直接创建数据源、集群、库表,并在创建时指定分库、分表。与1.6版本比大大简化了分库分表的操作
1、添加数据库、存储数据源
/*+mycat:.createDataSource{ "name" :" dw0" , - "url" :" jdbc:mysql://192.168.253.139:3306", "user":"root", "password":"123456" }*/ ; /*+mycat:createDataSource{ "name" :"dr0" , "url" :"jdbc:mysql://192.168.253.139:3306", "user":"root", "password" :"123456" }*/ ; /*+mycat:.createDataSource{ "name" :" dw1" , - "url" :" jdbc:mysql://192.168.253.140:3306", "user":"root", "password":"123456" }*/ ; /*+mycat:createDataSource{ "name" :"dr1" , "url" :"jdbc:mysql://192.168.253.140:3306", "user":"root", "password" :"123456" }*/ ;
手动创建
{ "dbType":"mysql", "idleTimeout":60000, "initSqls":[], "initSqlsGetConnection":true, "instanceType":"READ_WRITE", "maxCon":1000, "maxConnectTimeout":3000, "maxRetryCount":5, "minCon":1, "name":"dw0", #注意 "password":"123456", "type":"JDBC", "url":"jdbc:mysql://192.168.253.139:3306?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true", #注意主机ip 注意不指定库 "user":"root", "weight":0 }
2、添加集群配置
把新添加的数据源配置成集群
#//在mycat终端输入 /*! mycat:createCluster{"name":"c0"," masters": ["dw0"],"replicas":["dr0"]}*/; /*!-mycat:createCluster{"name":"c1", "masters": ["dw1"],"replicas":["dr1"]}*/ ; #可以查看集群配置信息 cd /usr/local/mycat/conf/clusters
手动配置
"clusterType":"MASTER_SLAVE", "heartbeat":{ "heartbeatTimeout":1000, "maxRetry":3, "minSwitchTimeInterval":300, "slaveThreshold":0 }, "masters":[ "dw0" ], "maxCon":200, "name":"c0", #注意 "readBalanceType":"BALANCE_ALL", "replicas":[ "dr0" ], "switchType":"SWITCH" }
启动 Mycat并登录
./mycat console
3、创建全局表
#添加数据库db1 主机2也要创建 CREATE DATABASE db1;
vim db1.schema.json
#在建表语句中加上关键字BROADCAST(广播,即为全局表) CREATE TABLE db1.`travelrecord` ( `id` bigint NOT NULL AUTO_INCREMENT, `use_id` varchar(100) DEFAULT NULL, `traveldate` date DEFAULT NULL, `fee` decimal(10,0) DEFAULT NULL, `days` int DEFAULT NULL, `blob` longblob, PRIMARY KEY(`id`) , KEY `id` (`id`) )ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST; #进入相关目录查看schema 配置
4、 创建分片表(分库分表)
#在 Mycat终端直接运行建表语句进行数据分片 CREATE TABLE db1.orders( id BIGINT NOT NULL AUTO_INCREMENT, order_type INT, customer_id INT, amount DECIMAL(10,2), PRIMARY KEY(id) )ENGINE=INNODB DEFAULT CHARSET=utf8 dbpartition BY mod_hash(customer_id) tbpartition BY mod_hash(customer_id) tbpartitions 1 dbpartitions 2; #数据库分片规则,表分片规则,以及各分多少片
mysql> use TESTDB; #在 mycat 里向 orders 表插入数据, INSERT 字段不能省略 INSERT INTO orders(id,order_type,customer_id,amount) VALUES (1,101,100,100100); INSERT INTO orders(id,order_type,customer_id,amount) VALUES(2,101,100,100300); INSERT INTO orders(id,order_type,customer_id,amount) VALUES(3,101,101,120000); INSERT INTO orders(id,order_type,customer_id,amount) VALUES(4,101,101,103000); INSERT INTO orders(id,order_type,customer_id,amount) VALUES(5,102,101,100400); INSERT INTO orders(id,order_type,customer_id,amount) VALUES(6,102,100,100020);
#同样可以查看生成的配置信息 #进入相关目录查看schema配置 vim db1.schema.json
查看数据库可见,分片数据
主机1
主机2
在 Mycat终端查询依然可以看到全部数据
Mycat
5、创建ER表
与分片表关联的表如何分表,也就是ER表如何分表,如下
#在 Mycat终端直接运行建表语句进行数据分片 CREATE TABLE orders_detail( `id` BIGINT NOT NULL AUTO_INCREMENT, detail VARCHAR(2000), order_id INT, PRIMARY KEY(id) )ENGINE=INNODB DEFAULT CHARSET=utf8 dbpartition BY mod_hash(order_id) tbpartition BY mod_hash(order_id) tbpartitions 1 dbpartitions 2 ;
INSERT INTO orders_detail(id,detail,order_id) values(1,'detail1',1); INSERT INTO orders_detail(id,detail,order_id) VALUES(2,'detail1',2); INSERT INTO orders_detail(id,detail,order_id) VALUES(3,'detail1',3); INSERT INTO orders_detail(id,detail,order_id) VALUES(4,'detail1',4); INSERT INTO orders_detail(id,detail,order_id) VALUES(5,'detail1',5); INSERT INTO orders_detail(id,detail,order_id) VALUES(6,'detail1',6);
mycat
主机1
不是按照想象的126划得
主机2
#上述两表具有相同的分片算法,但是分片字段不相同 #Mycat2在涉及这两个表的join分片字段等价关系的时候可以完成join的下推 #Mycat2无需指定ER表,是自动识别的,具体看分片算法的接口 #查看配置的表是否具有ER关系,使用/*+·mycat:showErGroup{}*/
#group_id表示相同的组,该组中的表具有相同的存储分布
#运行关联查询语句 Select o.*,od.detail from orders o inner join orders_detail od on o.id=od.order_id;
5.4-常用分片规则
1、分片算法简介
Mycat2支持常用的(自动)HASH型分片算法也兼容1.6的内置的(cobar)分片算法.
HASH型分片算法默认要求集群名字以c为前缀,数字为后缀, c0就是分片表第一个节点, c1就是第二个节点.该命名规则允许用户手动改变
2、Mycat2 与1.x版本区别
Mycat2-Hash型分片算法多数基于MOD_HASH(MOD对应.JAVA的%运算),实际上是取余运算。
Mycat2-Hash型分片算法对于值的处理,总是把分片值转换到列属性的数据类型再运算。
而1.x系列的分片算法统一转换到字符串类型再运算且只能根据一个分片字段计算出存储节点下标。
Mycat2-Hash型分片算法适用于等价条件查询。
而1.x系列由于含有用户经验的路由规则。1.x系列的分片规则总是先转换成字符串再运算。
3、分片规则与适用性
分片算法 | 描述 | 分库 | 分表 | 数值类型 |
MOD_HASH | 取模哈希 | 是 | 是 | 数值,字符串口 |
UNI_HASH2 | 取模哈希 | 是 | 是 | 数值,字符串 |
RIGHT_SHIFT | 右移哈希 | 是 | 是 | 数值 |
RANGE_HASH | 两字段其一取模 | 是 | 是 | 数值,字符串 |
YYYYMM | 按年月哈希 | 是 | 是 | DATE,DATETIME |
YYYYDD | 按年日哈希 | 是 | 是 | DATE,DATETIME |
MM | 按月哈希 | 否 | 是 | DATE,DATETIME |
DD | 按日期哈希 | 否 | 是 | DATE,DATETIME |
MMDD | 按月日哈希 | 是 | 是 | DATE,DATETIME |
WEEK | 按周哈希 | 否 | 是 | DATE,DATETIME |
STR_HASH | 字符串哈希 | 是 | 是 | 字符串 |