范围求模分片先进行范围分片计算出分片组,组内再求模。
优点可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题
综合了范围分片和求模分片的优点,分片组内使用求模可以保证组内数据比较均匀,分片组之间是范围分片可以兼顾范围查询。
最好事先规划好分片的数量,数据扩容时按分片组扩容,则原有分片组的数据不需要迁移。由于分片组内数据比较均匀,所以分片组内可以避免热点数据问题。
首先,需要你准备俩个库。
本篇db1的连接地址为192.168.247.140:3000
db2的为192.168.247.140:3001
并在俩个库新建一个test表
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
修改配置文件
server.xml默认即可,只需要知道登录mycat的用户名和密码。
修改schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="test" primaryKey="id" dataNode="dn1,dn2" rule="mod-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost2" database="db2" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.247.140:3000" user="root" password="password" />
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.247.140:3001" user="root" password="password" />
</dataHost>
</mycat:schema>
修改rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
<property name="defaultNode">0</property>
</function>
</mycat:rule>
mapFile
:代表配置文件路径defaultNode
:超过范围后的默认节点顺序号,节点从0 开始。
打开conf目录下的partition-range-mod.txt
# range start-end ,data node group size
0-1M=1
1M1-2M=1
M
表示一万,第一行是0到1万分配一个节点M1
表示万零一(10001),第二行表示10001到20000分配一个节点。=
号后面的数字代表该分片组所拥有的分片的数量。比如你有5个节点,设置一行=1
,那你就剩下4个节点,剩下的配置的和只能小于等于4。
重启mycat
# ./mycat restart
# mysql -h ip地址 -uroot -p123456 -P8066
mysql> use TESTDB
mysql> INSERT INTO test (id, name)VALUES ('9999', 'weikaixxxxxx');
mysql> INSERT INTO test (id, name)VALUES ('10000', 'weikaixxxxxx');
mysql> INSERT INTO test (id, name)VALUES ('10001', 'weikaixxxxxx');
mysql> INSERT INTO test (id, name)VALUES ('20000', 'weikaixxxxxx');
当超过20000时,会添加到默认节点中,0表示节点1,1表示节点2
扩容
新建第三个库和一张test表,表内有id和name字段
mysql> create database db3;
mysql> use db3
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
修改schema.xml,增加一个节点,注意命名,名字要改对了!
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="test" primaryKey="id" dataNode="dn1,dn2,dn3" rule="auto-sharding-rang-mod" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost2" database="db2" />
<dataNode name="dn3" dataHost="localhost3" database="db3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.247.140:3000" user="root" password="password" />
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.247.140:3001" user="root" password="password" />
</dataHost>
<dataHost name="localhost3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM3" url="192.168.247.140:3002" user="root" password="password" />
</dataHost>
</mycat:schema>
修改partition-range-mod.txt
我们现在有三个节点了,0到10000我分配俩个节点。
# range start-end ,data node group size
0-1M=2
1M1-2M=1
重启mycat,重启的过程去清空俩个表
# ./mycat restart
# mysql -h ip地址 -uroot -p123456 -P8066
mysql> use TESTDB
mysql> INSERT INTO test (id, name)VALUES ('9999', 'weikaixxxxxx');
mysql> INSERT INTO test (id, name)VALUES ('10000', 'weikaixxxxxx');
mysql> INSERT INTO test (id, name)VALUES ('10001', 'weikaixxxxxx');
mysql> INSERT INTO test (id, name)VALUES ('20000', 'weikaixxxxxx');
0-1M=2
分配到了db1和db2,1M1-2M=1
分配到了db3。
如果只是单一的求模分片的话,会有一个扩容的问题,就是扩容时,需要做数据迁移,也就是你得把所有库导出来,再导入,使数据均匀(如果导入时报错呢?)。
为什么要这样?当你有俩个节点都达到性能瓶颈了,你再加一个节点,mycat还是会写入那俩个已经不堪重负的节点,也就是你新增的节点并没有起到多大作用。
如果只是单一的指定范围分片,对并发又不友好。因为0到10000,都是在写进那个节点,其它节点空闲。
所以,范围求模分片就是它俩的结合体。0到10000,可以分配多个节点,在并发写入时可以分摊压力,新增节点时,只要配置一行从几到几
就能完成扩容。我这里只加了一个db3节点,如果再加一个db4,分配俩个节点,就会和db1和db2一样均衡了。