Mycat 分片规则
Mycat 通过
rule.xml的tableRule+function组合实现分片:选字段、选算法、配参数。常用九种:范围、取模、一致性 hash、枚举、应用指定、固定分片 hash、字符串 hash、按天、自然月。
一、规则总览
| 规则 | algorithm | 适用场景 |
|---|---|---|
| 范围 | rang-long | 按 id 区间分段,如 0-500 万 |
| 取模 | mod-long | 数据均匀打散,最简单 |
| 一致性 hash | murmur | 节点扩容时尽量少迁移数据 |
| 枚举 | hash-int | 按省份、性别、状态等固定值分流 |
| 应用指定 | sharding-by-substring | 应用按编码前缀指定分片 |
| 固定分片 hash | sharding-by-long-hash | 二进制位运算,连续值聚合 |
| 字符串 hash | sharding-by-stringhash | 按字符串子串 hash 分片 |
| 按天 | sharding-by-date | 日志、流水按天分片 |
| 自然月 | partbymonth | 按月分片 |
二、范围(rang-long)
根据指定的字段及其配置的范围与数据节点的对应情况,来决定该数据属于哪一个分片。
<table name="tb_operate" dataNode="dn4,dn5,dn6" rule="auto-sharding-long" />
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
autopartition-long.txt:
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2
区间必须连续且不重叠,
=0/1/2对应dataNode列表中的第几个节点。
三、取模(mod-long)
根据指定的字段值与节点数量进行求模运算,根据运算结果决定数据属于哪一个分片。
<table name="tb_log" dataNode="dn4,dn5,dn6" rule="mod-long" />
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
count必须等于dataNode的节点数量,否则会路由到不存在的节点。
四、一致性 hash(murmur)
所谓一致性哈希:相同的哈希因子计算值总是被划分到相同的分区表中,不会因为分区节点的增加而改变原来数据的分区位置。
<table name="tb_order" dataNode="dn4,dn5,dn6" rule="sharding-by-murmur" />
<tableRule name="sharding-by-murmur">
<rule>
<columns>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">3</property> <!-- 分片节点数量,必须指定 -->
<property name="virtualBucketTimes">160</property> <!-- 虚拟节点倍数,默认 160 -->
<!-- <property name="weightMapFile">weightMapFile</property> 节点权重,未指定默认为 1 -->
</function>
| 参数 | 含义 |
|---|---|
seed | 哈希种子,默认 0 |
count | 要分片的数据库节点数量,必须指定 |
virtualBucketTimes | 一个实际节点映射的虚拟节点数,默认 160 倍 |
weightMapFile | 节点权重文件,未指定权重的节点默认为 1 |
五、枚举(hash-int)
通过在配置文件中配置可能的枚举值,指定数据分布到不同数据节点上,适用于按照省份、性别、状态拆分数据等业务。
<table name="tb_user" dataNode="dn4,dn5,dn6" rule="sharding-by-intfile-enumstatus" />
<tableRule name="sharding-by-intfile-enumstatus">
<rule>
<columns>status</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="defaultNode">2</property>
<property name="mapFile">partition-hash-int.txt</property>
</function>
partition-hash-int.txt:
1=0
2=1
3=2
defaultNode是枚举值未命中时的默认节点;文件中的值必须与数据节点下标对应。
六、应用指定(sharding-by-substring)
运行阶段由应用自主决定路由到哪个分片,直接根据**字符子串(必须是数字)**计算分片号。
<table name="tb_app" dataNode="dn4,dn5,dn6" rule="sharding-by-substring" />
<tableRule name="sharding-by-substring">
<rule>
<columns>id</columns>
<algorithm>sharding-by-substring</algorithm>
</rule>
</tableRule>
<function name="sharding-by-substring" class="io.mycat.route.function.PartitionDirectBySubString">
<property name="startIndex">0</property> <!-- zero-based -->
<property name="size">2</property> <!-- 截取长度 -->
<property name="partitionCount">3</property> <!-- 分片数量 -->
<property name="defaultPartition">2</property> <!-- 默认分片 -->
</function>
例:
0010001取前 2 位00→ 分片 0;0110001→ 分片 1;0210001→ 分片 2。
七、固定分片 hash(sharding-by-long-hash)
该算法类似于十进制的求模运算,但是为二进制的操作:取 id 的二进制低 10 位与 1111111111 进行位与运算。
xxxxxxxxxx
& 1111111111
------------
0000000000 / 1111111111
<table name="tb_longhash" dataNode="dn4,dn5,dn6" rule="sharding-by-long-hash" />
<tableRule name="sharding-by-long-hash">
<rule>
<columns>id</columns>
<algorithm>sharding-by-long-hash</algorithm>
</rule>
</tableRule>
<function name="sharding-by-long-hash" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
</function>
| 参数 | 含义 |
|---|---|
partitionCount | 各分片的数量分配 |
partitionLength | 各分片长度,默认最大 1024 |
约束:
partitionCount与partitionLength的数组长度必须一致。特点:连续的值可能分配到相同分片,降低事务处理难度;可以均匀也可以非均匀分配;分片字段必须为数字类型。
八、字符串 hash 解析(sharding-by-stringhash)
截取字符串中指定位置的子字符串,进行 hash 算法,算出分片。
<table name="tb_strhash" dataNode="dn4,dn5" rule="sharding-by-stringhash" />
<tableRule name="sharding-by-stringhash">
<rule>
<columns>name</columns>
<algorithm>sharding-by-stringhash</algorithm>
</rule>
</tableRule>
<function name="sharding-by-stringhash" class="io.mycat.route.function.PartitionByString">
<property name="partitionLength">512</property> <!-- zero-based -->
<property name="partitionCount">2</property>
<property name="hashSlice">0:2</property>
</function>
hashSlice 的格式是 start:end:
| 写法 | 含义 |
|---|---|
0(出现在 end 位置) | 代表 str.length() |
-1 | 代表 str.length() - 1 |
| 大于 0 | 代表数字本身 |
例:
world截取0:2得到wor,hash 后26629 & (1024 - 1) = 5。
九、按天日期分片(sharding-by-date)
<table name="tb_datepart" dataNode="dn4,dn5,dn6" rule="sharding-by-date" />
<tableRule name="sharding-by-date">
<rule>
<columns>create_time</columns>
<algorithm>sharding-by-date</algorithm>
</rule>
</tableRule>
<function name="sharding-by-date" class="io.mycat.route.function.PartitionByDate">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2022-01-01</property>
<property name="sEndDate">2022-01-30</property>
<property name="sPartitionDay">10</property>
</function>
| 参数 | 含义 |
|---|---|
dateFormat | 日期格式 |
sBeginDate | 开始日期 |
sEndDate | 结束日期 |
sPartitionDay | 每多少天为一个分片 |
- 从开始时间算,每 10 天为一个分片;到达结束时间之后,会重复开始分片插入。
- 配置表的
dataNode分片数必须和分片规则数量一致:如 2022-01-01 到 2022-12-31、每 10 天一个分片,共需 37 个分片。
十、自然月(partbymonth)
使用场景为按照月份来分片,每个自然月为一个分片。
<table name="tb_monthpart" dataNode="dn4,dn5,dn6" rule="sharding-by-month" />
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>partbymonth</algorithm>
</rule>
</tableRule>
<function name="partbymonth" class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2022-01-01</property>
<property name="sEndDate">2022-03-31</property>
</function>
从开始时间起一个月一个分片,到达结束时间后重复开始分片插入;2022-01-01 到 2022-12-31 共需 12 个分片。
速查
<!-- 表上指定规则 -->
<table name="tb_log" dataNode="dn4,dn5,dn6" rule="mod-long" />
<!-- tableRule:字段 + 算法 -->
<tableRule name="mod-long">
<rule><columns>id</columns><algorithm>mod-long</algorithm></rule>
</tableRule>
<!-- function:实现类 + 参数 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<property name="count">3</property>
</function>
# 范围:autopartition-long.txt
0-500M=0
500M-1000M=1
1000M-1500M=2
# 枚举:partition-hash-int.txt
1=0
2=1
3=2
| 需求 | 选哪种规则 |
|---|---|
| 按 id 区间 | 范围 rang-long |
| 均匀打散 | 取模 mod-long |
| 扩容少迁移 | 一致性 hash murmur |
| 按状态 / 省份 | 枚举 hash-int |
| 按编码前缀 | 应用指定 sharding-by-substring |
| 连续 id 尽量同片 | 固定分片 hash |
| 按字符串片段 | 字符串 hash |
| 按天 / 按月 | sharding-by-date / partbymonth |
相关
- Mycat 配置:
rule.xml与function的对应关系 - Mycat 垂直拆分与水平拆分:
rule在schema.xml中如何引用 - Mycat 管理与监控:查看分片节点与执行 SQL