Mycat–理论–03–Mycat分片规则概述
1、连续分片
- 1到11000000,都放到dn1
- 1000001到2000000,都放到dn2
1.1、优点、缺点
优点
- 扩容无需迁移数据
- 范围条件查询消耗资源少
缺点
- 存在数据热点的可能性
- 就是频繁查询的数据,都在一台机器上
- 并发访问能力受限于单一或少量DataNode
2、离散分片
- 奇数放到dn1,偶数放到dn2
- 原理:x%mode
2.1、优点、缺点
优点
- 并发访问能力增强
- 数据存在多个节点上
- 范围条件查询性能提升
缺点
- 数据扩容比较困难,涉及到数据迁移问题
- 数据库连接消耗比较多
3、典型范围查询的场景对比
4、数据分片问题
5、综合类分片(二次分片)
- 先按范围分片,再按离散分片
- 好处:
- 容易扩容,迁移的数据比较少
- 一定程度解决数据热点问题。
6、连续分片规则
- 自定义数字范围分片
- 按日期(天)分片
- 按单月小时分片
- 自然月分片
6.1、自定义数字范围分片
提前规划好分片字段某个范围属于哪个分片
<function name="rang-long" class="org.opencloudb.route.function.AutoPartitionByLong">
# 配置文件名称
<property name="mapFile">autopartition-long.txt</property>
# defaultNode: 超过范围后的默认节点。
<property name="defaultNode">0</property>
</function>
autopartition-long.txt 配置
# 0-10000000 在0节点
# 所有的节点配置都是从0开始
0-10000000=0
# 10000001-20000000 在1节点
10000001-20000000=1
6.2、按日期(天)分片
- 从开始日期算起,按照天数来分片,例如,从2021-01-01,每10天一个分片
- 注意事项:
- 需要提前将分片规划好,建好,否则有可能日期超出实际配置分片数
<function name="sharding-by-date" class="org.opencloudb.route.function.PartitionByDate">
<!—日期格式-->
<property name="dateFormat">yyyy-MM-dd</property>
<!—开始日期-->
<property name="sBeginDate">2021-01-01</property>
<!—每分片天数-->
<property name="sPartionDay">10</property>
</function>
6.3、按单月小时分片
- 最小粒度是小时,可以一天最多24个分片,最少1个分片,一个月完后下月从头开始循环。
- 注意事项:
- 每个月月尾,需要手工清理数据。
<function name="sharding-by-hour" class="org.opencloudb.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>
6.4、自然月分片
- 每个自然月一个分片
- 注意事项:需要提前将分片数规划好,建好,否则有可能日期超出实际配置分片数
<function name="sharding-by-month" class="org.opencloudb.route.function.PartitionByMonth">
<!—日期格式-->
<property name="dateFormat">yyyy-MM-dd</property>
<!—开始日期-->
<property name="sBeginDate">2014-01-01</property>
</function>
7、离散分片规则
- 枚举分片
- 程序指定分区的分片
- 十进制求模分片
- 字符串hash分片
- 一致性哈希分片
7.1、枚举分片
- 通过在配置文件中配置可能的枚举id,自己配置分片
- 本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的
<function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap">
# 配置文件名称
<property name="mapFile">partition-hash-int.txt</property>
# type默认值为0(0表示Integer,非零表示String)
<property name="type">0</property>
# 默认节点的作用:枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点
<property name="defaultNode">0</property>
</function>
partition-hash-int.txt 配置
10000=0
10010=1
7.2、程序指定分区的分片
- 此规则是程序在运行阶段 自主决定路由到那个分片。
- 此方法由应用传递参数,显式指定分区号
<function name="sharding-by-substring" class="org.opencloudb.route.function.PartitionDirectBySubString">
<!-- 从哪个位置开始 -->
<property name="startIndex">0</property>
<!-- 截取2位数字作为分区号 -->
<property name="size">2</property>
<!-- 分区数量为8 -->
<property name="partitionCount">8</property>
<!-- 默认分配到0 分区 -->
<property name="defaultPartition">0</property>
</function>
举例:id=05-100000002
根据id中从startIndex=0 开始,截取siz=2位数字即05,05就是获取的分区
7.3、十进制求模分片
- 为对分片字段十进制取模运算
- 数据分布最均匀
<function name="mod-long" class="org.opencloudb.route.function.PartitionByMod">
<!-- 分区数量,也就是 按 n%3 来分区 -->
<property name="count">3</property>
</function>
7.4、符串hash分片
- 截取字符串中的int数值hash分片
<function name="sharding-by-stringhash" class="org.opencloudb.route.function.PartitionByString">
# length代表字符串hash求模基数,count分区数,其中length*count=1024
<property name=length>512</property>
<property name="count">2</property>
# hash预算位,表示怎么去截取字符串
<property name="hashSlice">0:2</property>
</function>
hash预算位
例1:值"45abc",hash预算位0:2 ,取其中45进行计算
例2:值"aaaabbb2345",hash预算位-4:0 ,取其中2345进行计算
7.5、一致性Hash分片
- 此规则优点在于扩容时迁移数据量比较少,前提
- 分片节点比较多
- 虚拟节点分配多些。
- 虚拟节点少
- 会造成数据分布不够均匀
- 分片节点比较少:
- 迁移量会比较多
扩容原理图:在node4和node2范围之间,新增节点node5
配置
<function name="murmur" class="org.opencloudb.route.function.PartitionByMurmurHash">
<!-- 默认是0-->
<property name="seed">0</property>
<!-- 分片节点数量-->
<property name="count">2</property>
<!-- 一个实际的数据库节点被映射为多少虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍-->
<property name="virtualBucketTimes">160</property>
</function>
8、综合类分片规则(本质:先范围,后hash)
- 范围求模分片
- 日期范围hash分片
- 取模范围约束分片
- ASCII码求模范围约束(字符串)
- 固定分片hash(二进制)
8.1、范围求模分片
先进行范围分片计算出分片组,组内再求模
- 优点可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题
- 分片组内使用求模可以保证组内数据比较均匀,分片组之间是范围分片可以兼顾范围查询。
- 最好事先规划好分片的数量,数据扩容时按分片组扩容,则原有分片组的数据不需要迁移。由于分片组内数据比较均匀,所以分片组内可以避免热点数据问题。
<function name="rang-mod" class="org.opencloudb.route.function.PartitionByRangeMod">
# 配置文件名称
<property name="mapFile">partition-range-mod.txt</property>
# 默认节点
<property name="defaultNode">21</property>
</function>
partition-range-mod.txt
# 0-200M,是一个分片组,这个组内有5个分片节点
0-200M=5
200M1-400M=1
400M1-600M=4
600M1-800M=4
800M1-1000M=6
8.2、日期范围hash分片
- 思想与范围求模一致,当由于日期在取模会有数据集中问题,所以改成hash方法。
- 要求日期格式尽量精确些,不然达不到局部均匀的目的
8.3、取模范围约束分片
- 取模运算与范围约束的结合,主要为了后续数据迁移做准备,即可以自主决定取模后数据的节点分布。
<function name="sharding-by-pattern" class="org.opencloudb.route.function.PartitionByPattern">
# 求模基数,
<property name="patternValue">256</property>
# 默认节点
<property name="defaultNode">2</property>
# 配置文件名称
<property name="mapFile">partition-pattern.txt</property>
</function>
partition-pattern.txt
- id%256后分布的范围是0到255。
- 我们按照32划分节点,1-32则在节点0,33-64则在节点1。其他类推,如果id非数字,则会分配在defaoultNode中
8.4、ASCII码求模范围约束分片
- 此种规则类似于取模范围约束
- 此规则支持数据符号字母取模。
<function name="sharding-by-pattern" class="org.opencloudb.route.function.PartitionByPrefixPattern">
# 求模基数
<property name="patternValue">256</property>
# 截取的位数
<property name="prefixLength">5</property>
# 配置文件名称
<property name="mapFile">partition-pattern.txt</property>
</function>
partition-pattern.txt
举例
假设分片字段code的值为AA01BCSDSD123
- 截取5位内容为:AA01B
- 获取每一位的有ASCII码:65,65,8,9,66
- 求和ASCII码:sum=65+65+8+9+66=213
- 求模 sum%patternValue=213/256=213
假设我们配置=200-256=12,那么213属于这个范围,也就是code为AA01BCSDSD123的内容在节点12。
8.5、固定分片hash(二进制)
- 规则类似于十进制的求模运算,区别在于二进制的操作,是取id的二进制低10位,即id二进制&1111111111。
- 实际效果与求模范围类似。此算法根据二进制则可能会分到连续的分片
<function name="func1" class="org.opencloudb.route.function.PartitionByLong">
# 分片个数列表
<property name="partitionCount">2,1</property>
# 分片范围列表
<property name="partitionLength">256,512</property>
</function>
分区长度
默认为最大2^10=1024 ,即最大支持1024分区
约束
1024 = sum((count[i]*length[i]))
举例
本例的分区策略:希望将数据水平分成3份,前两份各占25%,第三份占50%。
256范围的有2份,512范围的有一份,也就是上面的配置
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
9、BucketRule分片规则
预分好16384个桶,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中
每个 物理结点负责一部分桶的管理,当发生节点的增减时,调整桶的分布即可
举例
假设Redis Cluster三个节点A/B/C,则
Node A 包含桶的编号可以为: 0 到 5500.
Node B 包含桶的编号可以为: 5500 到 11000.
Node C包含桶的编号可以为: 11001 到 16384.
预分桶的方案介于"硬Hash"和"一致性Hash"之间,牺牲了一定的灵活性,但相比"一致性Hash",数据的管理成本大大降低