Mycat 学习(三)

Mycat分片规则

在数据切分处理中,特别是水平切分中,中间件最终要的两个处理过程就是数据的切分、数据的聚合。选择合适的切分规则,至关重要,因为它决定了后续数据聚合的难易程度,甚至可以避免跨库的数据聚合处理。

前面讲了数据切分中重要的几条原则,其中有几条是数据冗余,表分组(Table Group),这都是业务上规避跨库join 的很好的方式,但不是所有的业务场景都适合这样的规则,

主键分片 vs 非主键分片

当没有任何字段可以作为分片字段的时候,主键分片就是唯一选择,其优点是按照主键的查询最快。

若有某个合适的业务字段比较合适作为分片字段,则建议采用此业务字段分片,选择分片字段的条件如下:

Ÿ 尽可能的比较均匀分布数据到各个节点上;

Ÿ 该业务字段是最频繁的或者最重要的查询条件。

常见的除了主键之外的其他可能分片字段有“订单创建时间”、“店铺类别”或“所在省”等。

选择合适分片的规则,尽量规避跨库Join 是一条最重要的原则,每种规则都有特定的场景,分析每种规则去选择合适的应用到项目中。

分片枚举

通过在配置文件中配置可能的枚举id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的,这类业务使用本条规则,配置如下:

<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">

    <property name="mapFile">partition-hash-int.txt</property>

    <property name="type">0</property>

    <property name="defaultNode">0</property>

</function>
复制代码

partition-hash-int.txt 配置:

10000=0

10010=1

DEFAULT_NODE=1

上面columns 标识将要分片的表字段,algorithm 分片函数,

其中分片函数配置中,mapFile 标识配置文件名称,type 默认值为0,0 表示Integer,非零表示String,

所有的节点配置都是从0 开始,及0 代表节点1

 defaultNode 默认节点:小于0 表示不设置默认节点,大于等于0 表示设置默认节点 默认节点的作用:枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点, 如果不配置默认节点(defaultNode 值小于0 表示不配置默认节点),碰到 不识别的枚举值就会报错, can’t find datanode for sharding column:column_name val:ffffffff

固定分片 hash 算法

本条规则类似于十进制的求模运算,区别在于是二进制的操作,是取id 的二进制低10 位,即id 二进制&1111111111。

<function name="func1" class="io.mycat.route.function.PartitionByLong">

    <property name="partitionCount">2,1</property>

    <property name="partitionLength">256,512</property>

</function>
复制代码

配置说明:

上面columns 标识将要分片的表字段,algorithm 分片函数,partitionCount 分片个数列表,partitionLength 分片范围列表

分区长度:最大支持1024个 分区

约束:

count,length 两个数组的长度必须是一致的。

1024 = sum((count[i]*length[i])). count 和length 两个向量的点积恒等于1024

用法例子:

本例的分区策略:希望将数据水平分成3 份,前两份各占25%,第三份占50%。(故本例非均匀分区)

 |<———————1024———————————>|

 |<—-256—>|<—-256—>|<———-512————->|

 | partition0 | partition1 | partition2 |

  0 -------255,256------511,512----1023

如果需要平均分配设置:平均分为4 分片,partitionCount*partitionLength=1024

<function name="func1" class="io.mycat.route.function.PartitionByLong">

    <property name="partitionCount">4</property>

    <property name="partitionLength">256</property>

</function>
复制代码

范围约定

此分片适用于,提前规划好分片字段某个范围属于哪个分片,

start <= range <= end.

range start-end ,data node index

K=1000,M=10000.

<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">

    <property name="mapFile">autopartition-long.txt</property>

    <property name="defaultNode">0</property>

</function>
复制代码

配置说明:

上面columns 标识将要分片的表字段,algorithm 分片函数,

rang-long 函数中mapFile 代表配置文件路径

defaultNode 超过范围后的默认节点。

所有的节点配置都是从0 开始,及0 代表节点1,此配置非常简单,即预先制定可能的id 范围到某个分片

0-500M=0

500M-1000M=1

1000M-1500M=2

0-10000000=0

10000001-20000000=1

取模

此规则为对分片字段求摸运算。

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">

    <property name="count">3</property>

</function>
复制代码

配置说明:

此种配置非常明确即根据id 进行十进制求模运算。

按日期(天)分片

此规则为按天分片。

<function name="sharding-by-date" class="io.mycat.route.function.PartitionByDate">

    <property name="dateFormat">yyyy-MM-dd</property>

    <property name="sBeginDate">2014-01-01</property>

    <property name="sEndDate">2014-01-02</property>

    <property name="sPartionDay">10</property>

</function>
复制代码

配置说明:

dateFormat :日期格式

sBeginDate :开始日期

sEndDate:结束日期

sPartionDay :分区天数,即默认从开始日期算起,分隔10 天一个分区

如果配置了sEndDate 则代表数据达到了这个日期的分片后后循环从开始分片插入。

取模范围约束

此种规则是取模运算与范围约束的结合。

<function name="sharding-by-pattern" class="io.mycat.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 partition range start-end ,data node index

1-32=0

33-64=1

65-96=2

97-128=3

129-160=4

161-192=5

193-224=6

225-256=7

0-0=7

配置说明:

上面columns 标识将要分片的表字段,algorithm 分片函数,patternValue 即求模基数,defaoultNode默认节点,默认节点,小于0表示不设置默认节点,大于等于0表示设置默认节点,如果超出配置的范围,则使用默认节点,mapFile 配置文件路径。

配置文件中,1-32 即代表id%256 后分布的范围,如果在1-32 则在分区1,其他类推,如果id 非数据,则会分配在defaoultNode 默认节点。

截取数字做 hash 求模范围约束

此种规则类似于取模范围约束,此规则支持数据符号字母取模。

<function name="sharding-by-pattern"

class="io.mycat.route.function.PartitionByPrefixPattern">

    <property name="patternValue">256</property>

    <property name="prefixLength">5</property>

    <property name="mapFile">partition-pattern.txt</property>

</function>
复制代码

partition-pattern.txt

1-4=0

5-8=1

9-12=2

13-16=3

17-20=4

21-24=5

25-28=6

29-32=7

0-0=7

配置说明:

patternValue 即求模基数,prefixLength截取的位数

mapFile 配置文件路径

配置文件中,1-32 即代表id%256 后分布的范围,如果在1-32 则在分区1,其他类推

此种方式类似方式6 只不过采取的是将列种获取前prefixLength 位列所有ASCII 码的和进行求模。

截取数字 hash 解析

此规则是截取字符串中的int 数值hash 分片。

<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>
复制代码

配置说明:

函数中partitionLength 代表字符串hash 求模基数,

partitionCount 分区数,

hashSlice hash 预算位,即根据子字符串中int 值hash 运算

一致性 hash

一致性hash 预算有效解决了分布式数据的扩容问题。

<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>
复制代码

一致性哈希和虚拟一致性哈希

一致性哈希:

  1. 首先求出服务器(节点)的哈希值,并将其配置到0~2的32次方的圆上。

  2. 然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。

  3. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过2的32次方仍然找不到服务器,就会保存到第一台服务器上。

一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题,此时必然造成大量数据集中到Node A上,而只有极少量会定位到Node B上。

为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。

例如,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六个虚拟节点:同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。

这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

image.png

按单月小时拆分

此规则是单月内按照小时拆分,最小粒度是小时,可以一天最多24 个分片,最少1 个分片,一个月完后下月从头开始循环。

每个月月尾,需要手工清理数据。

<function name="sharding-by-hour" class="io.mycat.route.function.LatestMonthPartion">

    <property name="splitOneDay">24</property>

</function>

复制代码

配置说明:

columns: 拆分字段,字符串类型(yyyymmddHH)

splitOneDay : 一天切分的分片数

范围求模分片

先进行范围分片计算出归属分片组,组内再根据组内分片数量求模。

<function name="rang-mod"

class="io.mycat.route.function.PartitionByRangeMod">

    <property name="mapFile">partition-range-mod.txt</property>

    <property name="defaultNode">21</property>

</function>
复制代码

配置说明:

rang-mod 函数中mapFile 代表配置文件路径

defaultNode 超过范围后的默认节点顺序号,节点从0 开始。

partition-range-mod.txt

range start-end ,data node group size

以下配置一个范围代表一个分片组,=号后面的数字代表该分片组所拥有的分片的数量。

0-200M=5 //代表有5 个分片节点

200M1-400M=1

400M1-600M=4

600M1-800M=4

800M1-1000M=6

日期范围 hash 分片

思想与范围求模一致,当由于日期在取模会有数据集中问题,所以改成hash 方法。

先根据日期分组,再根据时间hash 使得短期内数据分布的更均匀。

<function name="range-date-hash"

class="io.mycat.route.function.PartitionByRangeDateHash">

    <property name="sBeginDate">2014-01-01 00:00:00</property>

    <property name="sPartionDay">3</property>

    <property name="dateFormat">yyyy-MM-dd HH:mm:ss</property>

    <property name="groupPartionSize">6</property>

</function>
复制代码

sPartionDay 代表多少天分一个分片

groupPartionSize 代表分片组的大小,在上述的例子中分片组共包含天数为6*3=18天

自然月分片

按月份列分区,每个自然月一个分片,格式between 操作解析的范例。

<function name="sharding-by-month" class="io.mycat.route.function.PartitionByMonth">

    <property name="dateFormat">yyyy-MM-dd</property>

    <property name="sBeginDate">2014-01-01</property>

</function>
复制代码

配置说明:

dateFormat : 日期字符串格式,默认为yyyy-MM-dd

sBeginDate : 开始日期,无默认值

sEndDate:结束日期,无默认值

节点从0 开始分片

应用指定

此规则是在运行阶段有应用自主决定路由到那个分片。

<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">8</property>

    <property name="defaultPartition">0</property>

</function>
复制代码

配置说明:

此方法为直接根据字符子串(必须是数字)计算分区号(由应用传递参数,显式指定分区号)。

例如id=05-100000002在此配置中代表根据id 中从startIndex=0,开始,截取siz=2 位数字即05,05 就是获取的分区,如果没传

默认分配到defaultPartition

猜你喜欢

转载自juejin.im/post/7069413121672085512
今日推荐