MyCat 下载

官网Mycat 数据库中间件

源码下载点我直接下载

配置启动参数

首先运行一下MycatStartup

然后配置

1
2
3
4
#环境变量
-DMYCAT_HOME=D:\My\project\Mycat-Server\src\main
#设置堆外内存大小:当使用mycat对非分片查询时,会把所有的数据查询出来,然后把这部分数据放在堆外内存中
-XX:MaxDirectMemorySize=512M

在 Mycat 有核心三个配置文件,分别为:sever.xml、schema.xml、rule.xml

  • sever.xml:是 Mycat 服务器参数调整和用户授权的配置文件
  • schema.xml:是逻辑库定义和表以及分片定义的配置文件
  • rule.xml:是分片规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下,配置文件修改需要重启

Mycat 核心概念

  • 逻辑库:Mycat 中的虚拟数据库。对应实际数据库的概念。在没有使用 mycat 时,应用需要确定当前连接的数据库等信息,那么当使用 mycat 后,也需要先虚拟一个数据库,用于应用的连接。
  • 逻辑表:mycat 中的虚拟数据表。对应时间数据库中数据表的概念。
  • 非分片表:没有进行数据切分的表。
  • 分片表:已经被数据拆分的表,每个分片表中都有原有数据表的一部分数据。多张分片表可以构成一个完整数据表。
  • ER 表:子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组(Table Group)保证数据 Join 不会跨库操作。表分组(Table Group)是解决跨分片数据 join 的一种很好的思路,也是数据切分规划的重要一条规则
  • 全局表:可以理解为是一张数据冗余表,如状态表,每一个数据分片节点又保存了一份状态表数据。数据冗余是解决跨分片数据 join 的一种很好的思路,也是数据切分规划的另外一条重要规则。
  • 分片节点(dataNode):数据切分后,每一个数据分片表所在的数据库就是分片节点。
  • 节点主机(dataHost):数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
  • 分片规则(rule):按照某种业务规则把数据分到某个分片的规则就是分片规则。
  • 全局序列号(sequence):也可以理解为分布式 id。数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence),如 UUID、雪花算法等。

环境准备

server.xml 文件中的 system 标签下配置所有的参数,全部为环境参数,可以根据当前需要进行开启和配置

如:设置 mycat 连接端口号:默认端口:8066

1
<property name="serverPort">8066</property>

通过 Mycat 访问数据库

server.xml 配置

应用连接 mycat 的话,也需要设置用户名、密码、被连接数据库信息,要配置这些信息的话,可以修改 server.xml,在其内部添加内容如下:

1
2
3
4
5
6
7
8
9
10
<!--配置自定义用户信息-->
<!--连接用户名-->
<user name="mycat">
<!--连接密码-->
<property name="password">123456</property>
<!--创建虚拟数据库-->
<property name="schemas">userDB</property>
<!--指定该库是否只读-->
<!--<property name="readOnly">true</property>-->
</user>

schema.xml 配置

当配置了一个虚拟数据库后,还需要修改 schema.xml,对虚拟库进行详细配置

schema.xml 中分为三部分内容:逻辑库名字对应的真实库的名字,真实库对应具体的连接地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

<!--配置虚拟数据库-->
<!--name:虚拟逻辑数据库名称,对应server.xml中的schemas属性值-->
<!--dataNode:逻辑库中逻辑表的默认数据节点-->
<!--sqlMaxLimit:类似于SQL上添加limit,如schema为非分片库,则该属性无效-->
<schema name="userDB" checkSQLschema="true" dataNode="localdn" sqlMaxLimit="500">
<!--配置虚拟逻辑表-->
<!--name:逻辑表名称,必须唯一-->
<!--dataNode:逻辑表所处的数据节点,值必须与dataNode标签中的name属性对应。如果值过多可以用$连接,如:dn$1-99,dn$200-400-->
<!--primaryKey:逻辑表对应的真实表的主键id的字段名-->
<table name="t_user" dataNode="localdn" primaryKey="id"/>
</schema>

<!--配置dataNode信息-->
<!--name:当前datanode名称-->
<!--dataHost:分片节点所处的节点主机,该值必须与dataHost标签中的name属性对应-->
<!--database:当前数据节点所对应的实际物理数据库-->
<dataNode name="localdn" dataHost="localdh" database="test"/>

<!--配置节点主机-->
<!--balance:用于进行读操作指向,有三个值可选
0:所有读操作都发送到当前可用的writeHost上
1:所有读操作都随机的发送到readHost上
2:所有读操作都随机发送在writeHost与readHost上
-->
<!--maxCon:指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数-->
<!--minCon:指定每个读写实例连接池的最小连接,初始化连接池的大小-->
<!--name:当前节点主机名称,不允许出现重复-->
<!--dbType:当时使用的数据库类型-->
<!--dbDriver:当前使用的数据库驱动-->
<!--writeType:用于写操作指向,有三个值可选
0:所有写操作都发送到可用的writeHost上
1:所有写操作都随机发送到readHost上
2:所有写操作都随机发送在writeHost与readHost上
-->
<!--readHost是从属于writeHost的,即意味着它从那个writeHost获取同步数据。
因此,当它所属的writeHost宕机了,则它也不会再参与到读写分离中来,即“不工作了”。这是因为此时,它的数据已经“不可靠”了。
基于这个考虑,目前mycat 1.3和1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下,从节点还能读取数据。
则需要在Mycat里配置为两个writeHost并设置banlance=1。”-->
<!--switchType:设置节点切换操作,有三个值可选
-1:不自动切换
1:自动切换,默认值
2:基于mysql主从同步的状态决定是否切换
-->
<!--slaveThreshold:主从同步状态决定是否切换,延迟超过该值就不切换-->
<dataHost balance="0" maxCon="100" minCon="10" name="localdh" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查询心跳-->
<heartbeat>select user()</heartbeat>
<!--配置写节点实际物理数据库信息-->
<writeHost url="jdbc:mysql://192.168.200.15:3306" host="host1" password="123456" user="root"></writeHost>
</dataHost>
</mycat:schema>

访问测试

通过 navicat 创建本地数据库连接并创建对应数据库,同时创建 mycat 连接。 在 mycat 连接中操作表,添加数据,可以发现,本地数据库中同步的也新增了对应的数据。

数据分片

1、取模分片

当一个数据表中的数据量非常大时,就需要考虑对表内数据进行分片,拆分的规则有很多种,比较简单的一种就是,通过对 id 进行取模,完成数据分片。

修改 schema.xml

table 标签新增属性:subTablesrule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

<!--配置虚拟数据库-->
<!--name:虚拟逻辑数据库名称,对应server.xml中的schemas属性值-->
<!--dataNode:逻辑库中逻辑表的默认数据节点-->
<!--sqlMaxLimit:类似于SQL上添加limit,如schema为非分片库,则该属性无效-->
<schema name="userDB" checkSQLschema="true" dataNode="localdn" sqlMaxLimit="500">
<!--配置虚拟逻辑表-->
<!--name:逻辑表名称,必须唯一-->
<!--dataNode:逻辑表所处的数据节点,值必须与dataNode标签中的name属性对应。如果值过多可以用$连接,如:dn$1-99,dn$200-400-->
<!--primaryKey:逻辑表对应的真实表的主键id的字段名,根据真实表的id列取模-->
<!--subTables:分表的名称。可以存在多个,t_user1,t_user2,t_user3.如果分表较多,可以通过$连接:t_user$1-3-->
<!--rule:分片规则,对应rule.xml中配置-->
<table name="t_user" dataNode="localdn" primaryKey="id" subTables="t_user$1-3" rule="mod-long"/>
</schema>

修改 rule.xml

在 schema.xml 中已经指定规则为 mod-long。因此需要到该文件中修改对应信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<tableRule name="mod-long">
<rule>
<!--当用用于id取模的字段-->
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>

<!--修改当前的分片数量-->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<!-- 根据datanode数量进行取模分片,也就是要模几。 -->
<property name="count">3</property>
</function>

新增数据测试

mycatuserDB数据库中插入 9 条数据

1
2
3
4
5
6
7
8
9
INSERT INTO t_user(id) VALUES(1);
INSERT INTO t_user(id) VALUES(2);
INSERT INTO t_user(id) VALUES(3);
INSERT INTO t_user(id) VALUES(4);
INSERT INTO t_user(id) VALUES(5);
INSERT INTO t_user(id) VALUES(6);
INSERT INTO t_user(id) VALUES(7);
INSERT INTO t_user(id) VALUES(8);
INSERT INTO t_user(id) VALUES(9);

问题分析

  • 散列不均匀,出现数据倾斜(因为对 3 取模,但是数据量不一定能被 3 取模,比如 10 条数据)

    • 每张表中的数据量差距较大(比如插入的 id 是随机的)
  • 动态扩容时,存在重新计算,出现数据丢失(比如把对 3 取模改为对 4 取模)

    • 动态扩容后新增表时,需要对模数修改时有可能就会造成当查询某个分片时,在该分片中找不到对应数据

2、全局 id 分片

当进行数据切分后,数据会存放在多张表中,如果仍然通过数据库自增 id 的方式,就会出现 ID 重复的问题,造成数据错乱。所以当拆分完数据后,需要让每一条数据都有自己的 ID,并且在多表中不能出现重复。比较常见的会使用雪花算法来生成分布式 id。

在 Mycat 中也提供了四种方式来进行分布式 id 生成:基于文件、基于数据库、基于时间戳和基于 ZooKeeper。

基于本地文件

优点:

  • 本地加载,读取速度较快

缺点:

  • MyCAT 重新发布后,配置文件中的 sequence 会初始化

  • 生成的 id 没有意义

  • MyCat 如果存在多个,会出现 id 重复冲突

流程:

  1. 修改sequence_conf.properties

    把后面的注释删掉!!!

    从 1000 开始到 200000 结束,一旦从新启动又会从 1000 开始,就会重复报错。

1
2
3
4
USER.HISIDS=  #使用过的历史分段,可不配置
USER.MINID=1 #最小ID值
USER.MAXID=200000 #最大ID值
USER.CURID=1000 #当前ID值
  1. 修改server.xml

    0 是使用文件保存文件,1 是使用数据库保存文件,2 是时间戳,3 是 zookeeper

1
2
3
4
5
6
7
8
9
10
11
<!--设置全局序号生成方式
0:文件
1:数据库
2:时间戳
3:zookeeper
-->
<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
<property name="sequenceHandlerType">0</property>
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<property name="sequenceHanlderClass">io.mycat.route.sequence.handler.HttpIncrSequenceHandler</property>

测试:

插入数据

MYCATSEQ_USER 这里的 USER 就是上面sequence_conf.properties里定义的USER,需要保持一致,且大写

1
insert into t_user(id,username) values('next value for MYCATSEQ_USER','wangwu')

其他三种配置方式:

数据库

  • 在实际的物理表中执行dbseq - utf8mb4中的sql语句,执行完毕后,会创建一张表

执行完成后会创建一张表,手动添加一条字段

  • 修改sequence_db_conf.properties文件

    T_USER需要和上面添加的字段的表明保持一致

1
T_USER=localdn
  • 修改 server.xml 文件,修改全局序列号生成方式为数据库方式
1
<property name="sequenceHandlerType">1</property>
  • 修改 schema.xml, 在 table 中添加自增属性
1
<table name="t_user" dataNode="localdn" primaryKey="id" subTables="t_user$1-3" rule="mod-long" autoIncrement="true"/>
  • mycat中的userDB数据库中执行语句
1
insert into t_user(id,username) values('next value for MYCATSEQ_T_USER','wangwu')

zookeeper

  • 修改server.xml,更改生成模式
1
<property name="sequenceHandlerType">3</property>
  • 修改myid.properties,配置 zookeeper 连接信息
1
2
3
4
5
loadZk=false
zkURL=192.168.200.15:2181
clusterId=01
myid=mycat_fz_01
clusterNodes=mycat_fz_01
  • 修改sequence_distributed_conf.properties
1
2
INSTANCEID=ZK #声明使用zk生成
CLUSTERID=01
  • 新增数据
1
2
#MYCATSEQ_这个后缀可以随便写即可
insert into t_user(id,username) values('next value for MYCATSEQ_TB_AAAA','atguigu')
  • 特点
    • ID 结构:long 64 位,ID 最大可占 63 位
    • 可以承受单机房单机器单线程 1000*(2^6)=640000 的并发。
    • 无悲观锁,无强竞争,吞吐量更高

时间戳

  • 修改server.xml。更改生成方式

    1
    <property name="sequenceHandlerType">2</property>
  • 修改sequence_time_conf.properties

1
2
3
4
#sequence depend on TIME
#WORKID与DATAACENTERID: 0-31 任意整数。多mycat节点下,每个节点的WORKID、DATAACENTERID不能重复,组成唯一标识,总共支持32*32=1024 种组合
WORKID=01
DATAACENTERID=01
  • 新增数据

    1
    2
    #MYCATSEQ_这个后缀可以随便写即可
    insert into t_user(id,username) values('next value for MYCATSEQ_TB_BBBB','atguigu')
  • 特点

    • 不存在 id 重复的现象
    • 数据类型太长,建议字段类型采用 bigint(最大取值 18446744073709551615)

3、枚举分片

适用于在特定业务场景下,将不同的数据存放于不同的数据库中,如按省份存放订单、按存放人员信息等。

  1. 修改schema.xml,修改table标签中name属性为当前操作的表名,rule属性为sharding-by-intfile
1
<table name="t_user" dataNode="dn129,dn130" primaryKey="id" rule="sharding-by-intfile"/>
  1. 修改rule.xml,配置tableRulesharding-by-intfilecolumns属性为当前指定分片字段
1
2
3
4
5
6
<tableRule name="sharding-by-intfile">
<rule>
<columns>sex</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
  1. 修改rule.xmlhash-int
1
2
3
4
5
6
7
8
<function name="hash-int"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
<!--type默认值为0,0表示Integer,非零表示String-->
<property name="type">1</property>
<!--defaultNode 当有一些特殊数据信息可以存放于默认节点中,如即不是male也不是female。默认节点:小于0表示不设置默认节点,大于等于0表示设置默认节点,不能解析的枚举就存到默认节点-->
<property name="defaultNode">0</property>
</function>
  1. 修改partition-hash-int.txt。指定分片字段不同值存在于不同的数据库节点
1
2
male=0 #代表第一个datanode
female=1 #代表第二个datanode
  1. 注意事项

    该方案适用于特定业务场景进行数据分片,但该方式容易出现数据倾斜,如不同省份的订单量一定会不同。订单量大的省份还会进行数据分库,数据库架构就会继续发生对应改变。

4、固定 hash 分片

固定 hash 分片的工作原理类似与redis cluster槽的概念,在固定 hash 中会有一个范围是 0-1024,内部会进行二进制运算操作,如取 id 的二进制低 10 位 与 1111111111 进行&运算。从而当出现连接数据插入,其有可能会进入到同一个分片中,减少了分布式事务操作,提升插入效率同时尽量减少了数据倾斜问题,但不能避免不出现数据倾斜。

按照上面这张图就存在两个分区,partition1 和 partition2。partition1 的范围是 0-255,partition2 的范围是 256-1024。

当向分区中存数据时,先将 id 值转换为二进制,接着将转换过来的二进制和 1111111111 进行与运算&,再对结果值转换为十进制,从而确定当前数据应该存入哪个分区中。

  • 1023 的二进制&1111111111 运算后为 1023,故落入第二个分区

  • 1024 的二进制&1111111111 运算后为 0,故落入第一个分区

  • 266 的二进制&1111111111 运算后为 266,故落入第二个分区内

  1. 修改schema.xml,配置自定义固定 hash 分配规则
1
<table name="t_user" dataNode="dn129,dn130" primaryKey="id" rule="partition-by-fixed-hash"/>
  1. 修改rule.xml,配置自定义固定 hash 分片规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<tableRule name="partition-by-fixed-hash">
<rule>
<columns>id</columns>
<algorithm>partition-by-fixed-hash</algorithm>
</rule>
</tableRule>

<!--
partitionCount: 存在多少个节点,如1,1 1,1,1
partitionLength: 每个节点分配的范围大小
-->
<function name="partition-by-fixed-hash" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">1,1</property>
<!--配置的是区间0-256,256-768 -->
<property name="partitionLength">256,768</property>
</function>
  1. 测试,添加数据,可以发现数据会根据计算,落入相应的数据库节点。

5、固定范围分片

该规则有点像枚举与固定 hash 的综合体,设置某一个字段,然后规定该字段值的不同范围值会进入到哪一个 dataNode。适用于明确知道分片字段的某个范围属于某个分片

优点:适用于想明确知道某个分片字段的某个范围具体在哪一个节点

缺点:如果短时间内有大量的批量插入操作,那么某个分片节点可能一下子会承受比较大的数据库压力,而别的分片节点此时可能处于闲置状态,无法利用其它节点进行分担压力(热点数据问题)

  1. 修改schema.xml
1
<table name="tb_user_range" dataNode="dn129,dn130" primaryKey="user_id" rule="auto-sharding-long"/>
  1. 修改rule.xml
1
2
3
4
5
6
<tableRule name="auto-sharding-long">
<rule>
<columns>age</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>

修改autopartition-long.txt,定义自定义范围

1
2
3
4
5
6
7
8
9
10
#用于定义dataNode对应的数据范围,如果配置多了会报错。
# range start-end ,data node index
# K=1000,M=10000.
#0-500M=0
#500M-1000M=1
#1000M-1500M=2

#所有的节点配置都是从0开始,0代表节点1
0-20=0
21-50=1
  1. 测试,添加用户信息,年龄分别为 9 和 33

6、取模范围分片

这种方式结合了范围分片和取模分片,主要是为后续的数据迁移做准备。

优点:可以自主决定取模后数据的节点分布

缺点:dataNode 划分节点是事先建好的,需要扩展时比较麻烦

  1. 修改 schema.xml,配置分片规则
1
<table name="t_user" dataNode="dn129,dn130" primaryKey="id" rule="sharding-by-partition"/>
  1. 修改 rule.xml,添加分片规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<tableRule name="sharding-by-partition">
<rule>
<columns>id</columns>
<algorithm>sharding-by-partition</algorithm>
</rule>
</tableRule>

<function name="sharding-by-partition" class="io.mycat.route.function.PartitionByPattern">
<!--求模基数-->
<property name="patternValue">256</property>
<!--默认节点-->
<property name="defaultNode">0</property>
<!--指定规则配置文件-->
<property name="mapFile">partition-pattern.txt</property>
</function>
  1. 添加 partition-pattern.txt,(自己新建这个文件)文件内部配置节点中数据范围
1
2
3
#0-128表示id%256后的数据范围。
0-128=0
129-256=1
  1. 测试

7、字符串 hash 分片

在业务场景下,有时可能会根据某个分片字段的前几个值来进行取模。如地址信息只取省份、姓名只取前一个字的姓等。此时则可以使用该种方式。

其工作方式与取模范围分片类型,该分片方式支持数值、符号、字母取模。

  1. 修改 schema.xml。
1
<table name="tb_user_string_hash" dataNode="dn129,dn130" primaryKey="user_id" rule="sharding-by-string-hash"/>
  1. 修改 rule.xml,定义拆分规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<tableRule name="sharding-by-string-hash">
<rule>
<columns>user_name</columns>
<algorithm>sharding-by-string-hash-function</algorithm>
</rule>
</tableRule>

<function name="sharding-by-string-hash-function" class="io.mycat.route.function.PartitionByPrefixPattern">
<!--求模基数 -->
<property name="patternValue">256</property>
<!-- 截取的位数 -->
<property name="prefixLength">1</property>
<property name="mapFile">partition-pattern-string-hash.txt</property>
</function>
  1. 新建 partition-pattern-string-hash.txt。指定数据分片节点
1
2
0-128=0
129-256=1

4)运行后可以发现 ,不同的姓名取模后,会进入不同的分片节点。

8、一致性 hash

通过一致性 hash 分片可以最大限度的让数据均匀分布,但是均匀分布也会带来问题,就是分布式事务。

原理(重点)

一致性 hash 算法引入了 hash 环的概念。环的大小是 0~2^32-1。首先通过 crc16 算法计算出数据节点在 hash 环中的位置。

当存储数据时,也会采用同样的算法,计算出数据 key 的 hash 值,映射到 hash 环上。

然后从数据映射的位置开始,以顺时针的方式找出距离最近的数据节点,接着将数据存入到该节点中。

此时可以发现,数据并没有达到预期的数据均匀,可以发现如果两个数据节点在环上的距离,决定有大量数据存入了 dataNode2,而仅有少量数据存入 dataNode1。

为了解决数据不均匀的问题,在 mycat 中可以设置虚拟数据映射节点。同时这些虚拟节点会映射到实际数据节点。

数据仍然以顺时针方式寻找数据节点,当找到最近的数据节点无论是实际还是虚拟,都会进行存储,如果是虚拟数据节点的话,最终会将数据保存到实际数据节点中。 从而尽量的使数据均匀分布。

实现流程如下:

  1. 修改 schema.xml

    1
    <table name="tb_user_murmur" dataNode="dn129,dn130" primaryKey="user_id" rule="sharding-by-murmur"/>
  2. 修改 rule.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <tableRule name="sharding-by-murmur">
    <rule>
    <columns>user_id</columns>
    <algorithm>murmur</algorithm>
    </rule>
    </tableRule>

    <function name="murmur"
    class="io.mycat.route.function.PartitionByMurmurHash">
    <property name="seed">0</property><!-- 默认是0即可 -->
    <property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
    <property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
    <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
    <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
    用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
    </function>
  3. 测试: 循环插入一千条数据,数据会尽量均匀的分布在两个节点中。

9、时间分片

当数据量非常大时,有时会考虑,按天去分库分表。这种场景是非常常见的。同时也有利于后期的数据查询。

  1. 修改 schema.xml

    1
    <table name="t_user_day" dataNode="dn129,dn130" primaryKey="id" rule="sharding-by-date"/>
  2. 修改 rule.xml,每十天一个分片,从起始时间开始计算,分片不够,则报错。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <tableRule name="sharding-by-date">
    <rule>
    <columns>create_time</columns>
    <algorithm>partbyday</algorithm>
    </rule>
    </tableRule>

    <function name="partbyday"
    class="io.mycat.route.function.PartitionByDate">
    <!--日期格式-->
    <property name="dateFormat">yyyy-MM-dd hh:mm:ss</property>
    <!-- 官方要求的默认值 -->
    <property name="sNaturalDay">0</property>
    <!--从哪天开始,并且只能插入2020年的数据,2021的无法插入-->
    <property name="sBeginDate">2021-01-01</property>
    <!--每隔几天一个分片-->
    <property name="sPartionDay">10</property>
    </function>
  3. 测试: 当时间为 1 月 1-10 号之间,会进入 129 节点。当时间为 11-20 号之间,会进入 130 节点,当超出则报错。