myCat的一个重要功能就是数据库分片,允许你将一些规模较大的表分散到不同的数据库,来缓解数据库的压力,或者实现数据的隔离。
当然通过myCat来看,这些分片像是合起来的一张表,只是当sql到达myCat后,根据配置的分片规则,myCat去操作不同的数据库。
没有配置分片规则的表,需要配置为全局表,所有分片的数据是一样的。
如果没有配置分片规则,也没有配置为全局表,那么数据插入时所有分片插入,数据查询时所有分片都查出来,你有几个分片就会查出来几份数据。不过,你可以通过只给这个表配置一个数据节点,来达到既不分片也不全局的目的。
1.MyCat的基础配置
2.编写分片规则
- 打开conf文件夹下的rule.xml文件,添加以下代码
<!-- 分片规则,按租户分片 -->
<tableRule name="sharding-by-tenant">
<rule>
<columns>tenant_id</columns>
<algorithm>by-tenant</algorithm>
</rule>
</tableRule>
<!-- 分片方法,按照sharding-by-tenant.txt文件进行枚举分片 -->
<!-- type为分片字段的数据类型,1为字符串,0为int -->
<!-- defaultNode配置是否使用默认节点,默认为0,表示不设置默认节点,这样会导致遇到不识别的枚举值时会报错,如果设置的值大于零,该值就是默认节点,会把不识别的枚举值分配到默认节点。 -->
<function name="by-tenant" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">sharding-by-tenant.txt</property>
<property name="type">1</property>
<property name="defaultNode">0</property>
</function>
注意:mycat的配置文件,节点的顺序是有要求的,所有的tableRule要放在前面,所有的function要放在后面
- 在conf文件夹下创建sharding-by-tenant.txt文件,内容如下
220=0
30=1
意思是tenant_id字段值为220时,走第一个dataNode,值为30时,走第二个dataNode。找不到对应分片时,默认走第一个。
3.给表配置分片规则
- 打开schema.xml文件,为table配置分片规则
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="demo_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="sys_user" primaryKey="id" rule="sharding-by-tenant" dataNode="dn1,dn2" />
</schema>
<dataNode name="dn1" dataHost="dataHost220" database="demo_db" />
<dataNode name="dn2" dataHost="dataHost30" database="demo_db" />
<dataHost name="dataHost220" maxCon="1000" minCon="10" balance="3"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.3.220:3306" user="root" password="root">
<readHost host="hostS2" url="192.168.3.220:3307" user="root" password="root" />
</writeHost>
</dataHost>
<dataHost name="dataHost30" maxCon="1000" minCon="10" balance="3"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.3.30:3306" user="root" password="Root@123">
<readHost host="hostS2" url="192.168.3.30:3307" user="root" password="Root@123" />
</writeHost>
</dataHost>
</mycat:schema>
4.测试分片
mycat的枚举分片,根据分片字段,来进行分片的,分片字段不能修改。
插入一条数据时,根据分片字段会将其插入相应的分片数据库。
查询数据时,如果查询语句的where语句中包含分片字段,则只会去查询相应的分片数据库(没有匹配的枚举型会查默认节点),否则全部节点都查询。
可以根据以上特性,测试分片是否成功。现在tenant_id=220存在dataNode1,tenant_id=30存在dataNode2,如果向dataNode1中插入一条tenant_id=30的数据。通过mycat查询,带上条件为tenant_id=30,应该是查不到刚才的数据的。
5.分布式自增长主键问题
像这样进行分片,每个分片都进行自增长主键,那么在mycat中就会发生主键冲突,那么最好有一个分布式的统一主键管理。
mycat也提供了多种的分布式自增长主键方式,我选择了我认为最合适的一种。
- 在dn1的主库中,创建一个序列表。
像这个配置,mycat在启动时,会自动从表中,读取100条ID,用完了,再去读100条。这样即使你有多个mycat负载均衡,也不会出现主键冲突。
#所有操作都在 db1 上
#创建 MYCAT_SEQUENCE 表
DROP TABLE IF EXISTS MYCAT_SEQUENCE;
– name sequence 名称
– current_value 当前 value
– increment 增长步长! mycat在数据库中一次读取多少个sequence
CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT
NOT NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(name))
ENGINE=InnoDB;
#插入一条 sequence
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES (‘SYS_USER’,
100, 100);
注意:表名MYCAT_SEQUENCE必须是大写。
注意:在dn1节点的从库的配置文件my.cnf中,添加以下代码,来忽略对序列表的同步。
replicate-ignore-table = demo_db.MYCAT_SEQUENCE
- 在dn1的主库中,创建必须的方法
CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8
BEGIN
DECLARE retval VARCHAR(64);
SET retval='-999999999,NULL';
SELECT CONCAT(CAST(current_value AS CHAR),',',CAST(increment AS CHAR)) INTO retval FROM
MYCAT_SEQUENCE WHERE NAME = seq_name;
RETURN retval;
END
CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END
CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50),VALUE INTEGER) RETURNS varchar(64) CHARSET utf8
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END
- 在mycat的配置文件sequence_db_conf.properties中,添加以下代码
SYS_USER=dn1
这个“SYS_USER”即是序列表中name列的内容,也是表名。
- 在mycat的配置文件schema.xml中,为表SYS_USER添加自增长配置
<schema name="demo_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="sys_user" primaryKey="id" rule="sharding-by-tenant" autoIncrement="true" dataNode="dn1,dn2" />
</schema>
- 确保mycat的配置文件server.xml中,这一项值为1
<property name="sequnceHandlerType">1</property>
配置完成。
如果mycat启动不成功,请查看mycat/logs/wrapper.log日志
如果mycat启动后出现问题,或者功能出现问题,清查看mycat/logs/mycat.log日志