1. 枚举法:

通过在配置文件中配置可能的枚举id,自己配置分片,使用规则:

<tableRule name="sharding-by-intfile">

<rule>

<columns>user_id</columns>

<algorithm>hash-int</algorithm>

</rule>

</tableRule>

<function name="hash-int" class="org.opencloudb.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表示不配置默认节点),碰到
*                不识别的枚举值就会报错,
*                like this:can't find datanode for sharding column:column_name val:ffffffff
   
*/

2.固定分片hash算法

<tableRule
name="rule1">

<rule>

<columns>user_id</columns>

<algorithm>func1</algorithm>

</rule>

</tableRule>

<function name="func1"
class="org.opencloudb.route.function.PartitionByLong">

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

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

</function>

配置说明:

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

partitionCount
分片个数列表,partitionLength
分片范围列表
分区长度:默认为最大2^n=1024 ,即最大支持1024分区

约束 :

count,length两个数组的长度必须是一致的。
1024 =
sum((count[i]*length[i])). count
和length两个向量的点积恒等于1024

用法例子:

本例的分区策略:希望将数据水平分成3份,前两份各占25%,第三份占50%。(故本例非均匀分区)
        //
|<---------------------1024------------------------>|
        // |<----256--->|<----256--->|<----------512---------->|
        // | partition0 | partition1 | partition2 |
        // | 共2份,故count[0]=2 | 共1份,故count[1]=1 |
        int[] count = new int[] { 2, 1 };
        int[] length = new int[] { 256, 512 };
        PartitionUtil pu = new PartitionUtil(count,
length);

// 下面代码演示分别以offerId字段或memberId字段根据上述分区策略拆分的分配结果
        int DEFAULT_STR_HEAD_LEN = 8; // cobar默认会配置为此值
        long offerId = 12345;
        String memberId = "qiushuo";

// 若根据offerId分配,partNo1将等于0,即按照上述分区策略,offerId为12345时将会被分配到partition0中
        int partNo1 = pu.partition(offerId);

// 若根据memberId分配,partNo2将等于2,即按照上述分区策略,memberId为qiushuo时将会被分到partition2中
        int partNo2 = pu.partition(memberId, 0,
DEFAULT_STR_HEAD_LEN);

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

<function
name="func1"
class="org.opencloudb.route.function.PartitionByLong">

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

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

  </function>

3.范围约定

<tableRule
name="auto-sharding-long">

    <rule>

      <columns>user_id</columns>

     
<algorithm>rang-long</algorithm>

    </rule>

  </tableRule>

<function
name="rang-long"
class="org.opencloudb.route.function.AutoPartitionByLong">

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

  </function>

# range start-end ,data node index

# K=1000,M=10000.

0-500M=0

500M-1000M=1

1000M-1500M=2

0-10000000=0

10000001-20000000=1

配置说明:

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

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

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

4.求模法

<tableRule
name="mod-long">

    <rule>

      <columns>user_id</columns>

     
<algorithm>mod-long</algorithm>

    </rule>

  </tableRule>

  <function name="mod-long"
class="org.opencloudb.route.function.PartitionByMod">

   <!-- how many data nodes  -->

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

  </function>

配置说明:

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

此种配置非常明确即根据id进行十进制求模预算,相比方式1,此种在批量插入时需要切换数据源,id不连续

5.日期列分区法

<tableRule
name="sharding-by-date">

      <rule>

       
<columns>create_time</columns>

       
<algorithm>sharding-by-date</algorithm>

      </rule>

   </tableRule> 

<function
name="sharding-by-date"
class="org.opencloudb.route.function.PartitionByDate">

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

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

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

  </function>

配置说明:

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

配置中配置了开始日期,分区天数,即默认从开始日期算起,分隔10天一个分区

Assert.assertEquals(true, 0 ==
partition.calculate("2014-01-01"));
Assert.assertEquals(true, 0 == partition.calculate("2014-01-10"));
Assert.assertEquals(true, 1 == partition.calculate("2014-01-11"));
Assert.assertEquals(true, 12 == partition.calculate("2014-05-01"));

6.通配取模

<tableRule
name="sharding-by-pattern">

<rule>

<columns>user_id</columns>

<algorithm>sharding-by-pattern</algorithm>

</rule>

</tableRule>

<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
partition range start-end ,data node index

###### first
host configuration

1-32=0

33-64=1

65-96=2

97-128=3

########
second host configuration

129-160=4

161-192=5

193-224=6

225-256=7

0-0=7

配置说明:

上面columns
标识将要分片的表字段,algorithm 分片函数,patternValue
即求模基数,defaoultNode 默认节点,如果配置了默认,则不会按照求模运算

mapFile 配置文件路径

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

String idVal = "0";
Assert.assertEquals(true, 7 == autoPartition.calculate(idVal));
idVal = "45a";
Assert.assertEquals(true, 2 ==
autoPartition.calculate(idVal));

7. ASCII码求模通配

<tableRule
name="sharding-by-prefixpattern">

<rule>

<columns>user_id</columns>

<algorithm>sharding-by-prefixpattern</algorithm>

</rule>

</tableRule>

<function
name="sharding-by-pattern"
class="org.opencloudb.route.function.PartitionByPattern">

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

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

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

</function>

partition-pattern.txt

# range
start-end ,data node index

# ASCII

# 48-57=0-9

# 64、65-90=@、A-Z

# 97-122=a-z

###### first
host configuration

1-4=0

5-8=1

9-12=2

13-16=3

###### second
host configuration

17-20=4

21-24=5

25-28=6

29-32=7

0-0=7

配置说明:

上面columns
标识将要分片的表字段,algorithm 分片函数,patternValue
即求模基数,prefixLength ASCII 截取的位数

mapFile 配置文件路径

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

此种方式类似方式6只不过采取的是将列种获取前prefixLength位列所有ASCII码的和进行求模sum%patternValue ,获取的值,在通配范围内的

即 分片数,

/**
* ASCII编码:
* 48-57=0-9阿拉伯数字
* 64、65-90=@、A-Z
* 97-122=a-z
*
*/

String
idVal="gf89f9a";
Assert.assertEquals(true, 0==autoPartition.calculate(idVal));

idVal="8df99a";
Assert.assertEquals(true, 4==autoPartition.calculate(idVal));

idVal="8dhdf99a";
Assert.assertEquals(true, 3==autoPartition.calculate(idVal));

8.编程指定

<tableRule
name="sharding-by-substring">

<rule>

<columns>user_id</columns>

<algorithm>sharding-by-substring</algorithm>

</rule>

</tableRule>

<function
name="sharding-by-substring"
class="org.opencloudb.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>

配置说明:

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

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

例如id=05-100000002

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

9.字符串拆分hash解析

<tableRule name="sharding-by-stringhash">

      <rule>

       
<columns>user_id</columns>

       
<algorithm>sharding-by-stringhash</algorithm>

      </rule>

   </tableRule>

<function name="sharding-by-substring"
class="org.opencloudb.route.function.PartitionDirectBySubString">

    <property
name=length>512</property> <!-- zero-based -->

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

    <property
name="hashSlice">0:2</property>

  </function>

配置说明:

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

函数中length代表字符串hash求模基数,count分区数,hashSlice hash预算位

即根据子字符串 hash运算

hashSlice : 0 means str.length(), -1 means str.length()-1

/**
     * "2" -&gt; (0,2)<br/>
     * "1:2" -&gt; (1,2)<br/>
     * "1:" -&gt; (1,0)<br/>
     * "-1:" -&gt; (-1,0)<br/>
     * ":-1" -&gt; (0,-1)<br/>
     * ":" -&gt; (0,0)<br/>
     */
例子:

String
idVal=null;

rule.setPartitionLength("512");

rule.setPartitionCount("2");

rule.init();

rule.setHashSlice("0:2");

//             idVal = "0";

//             Assert.assertEquals(true, 0 ==
rule.calculate(idVal));

//             idVal = "45a";

//             Assert.assertEquals(true, 1 ==
rule.calculate(idVal));

//last 4

rule = new PartitionByString();

rule.setPartitionLength("512");

rule.setPartitionCount("2");

rule.init();

//last 4 characters

rule.setHashSlice("-4:0");

idVal = "aaaabbb0000";

Assert.assertEquals(true, 0 ==
rule.calculate(idVal));

idVal = "aaaabbb2359";

Assert.assertEquals(true, 0 ==
rule.calculate(idVal));

10,一致性hash

<tableRule
name="sharding-by-murmur">

<rule>

<columns>user_id</columns>

<algorithm>murmur</algorithm>

</rule>

</tableRule>

<function
name="murmur"
class="org.opencloudb.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>

一致性hash预算有效解决了分布式数据的扩容问题,前1-9中id规则都多少存在数据扩容难题,而10规则解决了数据扩容难点

关于一致性hash详细:

一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。

一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:

1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。

2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。 

3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。 

4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同
的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。

在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。接下来主要讲解一下一致性哈希算法是如何设计的:

环形Hash空间

按照常用的hash算法来将对应的key哈希到一个具有2^32次方个桶的空间中,即0~(2^32)-1的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭合的环形。如下图

把数据通过一定的hash算法处理后映射到环上

现在我们将object1、object2、object3、object4四个对象通过特定的Hash函数计算出对应的key值,然后散列到Hash环上。如下图:

Hash(object1) = key1;

Hash(object2) = key2;

Hash(object3) = key3;

Hash(object4) = key4;

将机器通过hash算法映射到环上

在采用一致性哈希算法的分布式集群中将新的机器加入,其原理是通过使用与对象存储一样的Hash算法将机器也映射到环中(一般情况下对机器的hash计算是采用机器的IP或者机器唯一的别名作为输入值),然后以顺时针的方向计算,将所有对象存储到离自己最近的机器中。

假设现在有NODE1,NODE2,NODE3三台机器,通过Hash算法得到对应的KEY值,映射到环中,其示意图如下:

Hash(NODE1) = KEY1;

Hash(NODE2) = KEY2;

Hash(NODE3) = KEY3;

通过上图可以看出对象与机器处于同一哈希空间中,这样按顺时针转动object1存储到了NODE1中,object3存储到了NODE2中,object2、object4存储到了NODE3中。在这样的部署环境中,hash环是不会变更的,因此,通过算出对象的hash值就能快速的定位到对应的机器中,这样就能找到对象真正的存储位置了。

机器的删除与添加

普通hash求余算法最为不妥的地方就是在有机器的添加或者删除之后会照成大量的对象存储位置失效,这样就大大的不满足单调性了。下面来分析一下一致性哈希算法是如何处理的。

1. 节点(机器)的删除

以上面的分布为例,如果NODE2出现故障被删除了,那么按照顺时针迁移的方法,object3将会被迁移到NODE3中,这样仅仅是object3的映射位置发生了变化,其它的对象没有任何的改动。如下图:

2. 节点(机器)的添加

如果往集群中添加一个新的节点NODE4,通过对应的哈希算法得到KEY4,并映射到环中,如下图:

通过按顺时针迁移的规则,那么object2被迁移到了NODE4中,其它对象还保持这原有的存储位置。通过对节点的添加和删除的分析,一致性哈希算法在保持了单调性的同时,还是数据的迁移达到了最小,这样的算法对分布式集群来说是非常合适的,避免了大量数据迁移,减小了服务器的的压力。

平衡性

根据上面的图解分析,一致性哈希算法满足了单调性和负载均衡的特性以及一般hash算法的分散性,但这还并不能当做其被广泛应用的原由,因为还缺少了平衡性。下面将分析一致性哈希算法是如何满足平衡性的。hash算法是不保证平衡的,如上面只部署了NODE1和NODE3的情况(NODE2被删除的图),object1存储到了NODE1中,而object2、object3、object4都存储到了NODE3中,这样就照成了非常不平衡的状态。在一致性哈希算法中,为了尽可能的满足平衡性,其引入了虚拟节点。

——“虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列。

以上面只部署了NODE1和NODE3的情况(NODE2被删除的图)为例,之前的对象在机器上的分布很不均衡,现在我们以2个副本(复制个数)为例,这样整个hash环中就存在了4个虚拟节点,最后对象映射的关系图如下:

根据上图可知对象的映射关系:object1->NODE1-1,object2->NODE1-2,object3->NODE3-2,object4->NODE3-1。通过虚拟节点的引入,对象的分布就比较均衡了。那么在实际操作中,正真的对象查询是如何工作的呢?对象从hash到虚拟节点到实际节点的转换如下图:

“虚拟节点”的hash计算可以采用对应节点的IP地址加数字后缀的方式。例如假设NODE1的IP地址为192.168.1.100。引入“虚拟节点”前,计算 cache A 的 hash 值:

Hash(“192.168.1.100”);

引入“虚拟节点”后,计算“虚拟节”点NODE1-1和NODE1-2的hash值:

Hash(“192.168.1.100#1”); // NODE1-1

Hash(“192.168.1.100#2”); // NODE1-2

以上所有规则每种都有特定使用场景,可以选择性使用。

MyCat的分片规则的更多相关文章

  1. Mysql系列六:(Mycat分片路由原理、Mycat常用分片规则及对应源码介绍)

    一.Mycat分片路由原理 我们先来看下面的一个SQL在Mycat里面是如何执行的: , ); 有3个分片dn1,dn2,dn3, id=5000001这条数据在dn2上,id=10000001这条数 ...

  2. MyCAT常用分片规则之分片枚举

    MyCAT支持多种分片规则,下面测试的这种是分片枚举.适用场景,列值的个数是固定的,譬如省份,月份等. 在这里,需定义三个值,规则均是在rule.xml中定义. 1. tableRule 2. fun ...

  3. MyCat 介绍、分片规则、调优的内容收集

    一.MyCat的简介 MyCat高可用.负载均衡架构图: 详细知识点:  MySQL分布式集群之MyCAT(一)简介(修正) 二.MyCat的schema.xml讲解 详细知识点:MySQL分布式集群 ...

  4. MyCat 枚举分片设计思考,查询命中条件

    Mycat多租户实现的两种方式 MyCat,各种分片规则,仅保证插入的时候分片.表关联,join,查询怎么命中分片条件,还是需要设计. 今天稍微测了一下. ER 分片,此方式,插入的时候能分片,但是查 ...

  5. Mycat 分片规则详解--单月小时分片

    实现方式:单月内按照小时拆分,最小粒度是小时,一天最多可以有24个分片,最少1个分片,下个月从头开始循环 优点:使数据按照小时来进行分时存储,颗粒度比日期(天)分片要小,适用于数据采集类存储分片 缺点 ...

  6. Mycat 分片规则详解--日期(天)分片

    实现方式:按照日期来分片 优点:使数据按照日期来进行分时存储 缺点:由于数据是连续的,所以该方案不能有效的利用资源 配置示例: <tableRule name="sharding-by ...

  7. Mycat 分片规则详解--应用指定分片

    实现方式:根据字符串的子串(必须是数字)计算分区号(由调用方传递参数,显示指定分区号),例如,id=05-12232323,其中 id 是从 startIndex = 0,size=2,即截取的子串是 ...

  8. Mycat 分片规则详解--取模分片

    实现方式:切分规则根据配置中输入的数值n.此种分片规则将数据分成n份(通常dn节点也为n),从而将数据均匀的分布于各节点上. 优点:这种策略可以很好的分散数据库写的压力.比较适合于单点查询的情景 缺点 ...

  9. Mycat 分片规则详解--枚举分片

    实现方式:切分规则根据文件(partition-hash-int.txt)配置的可能的枚举来进行分片,此种分片规则理解为枚举分区,会比较适合于取值固定的场合,比如说省份(固定值) 优点:适用于按照省份 ...

随机推荐

  1. 切换usb口的命令

    open:dd if=imx6dl-sabresd-usboc.dtb of=/dev/mmcblk0 bs=512 seek=1536 conv=fsyncclose:dd if=imx6dl-sa ...

  2. JS正则表达式从入门到入土(9)—— test方法以及它的那些坑

    test方法 test方法介绍 RegExp.prototype.test(str) test方法用于测试字符串参数中是否存在匹配正则表达式模式的字符串 test方法的使用 let reg = /\w ...

  3. CSS Text(文本)

    CSS Text(文本) 一.文本颜色 color 颜色属性被用来设置文字的颜色. 颜色是通过CSS最经常的指定: 十六进制值 - 如: #FF0000 一个RGB值 - 如: RGB(255,0,0 ...

  4. Excel水平线画不直,图形对象对不齐,怎么办

    看够了千篇一律的数字报表,不妨添加些图形对象来调剂下,今天小编excel小课堂(ID:excel-xiaoketang 长按复制)给各位分享10个插入图形对象时简单实用的小技巧. 01课题 今天小编e ...

  5. Job流程:Mapper类分析

    此文紧接Job流程:决定map个数的因素,Map任务被提交到Yarn后,被ApplicationMaster启动,任务的形式是YarnChild进程,在其中会执行MapTask的run()方法.无论是 ...

  6. linux下nano中复制粘贴剪切的快捷键是什么

    答: 1.复制:alt+6 2.剪切:ctrl+k 3.粘贴:ctrl+u 4.自由剪切: ctrl+6指定起始剪切位置,按上下左右键来选中内容,然后按下ctrl+k即可自由剪切 5.撤销: alt+ ...

  7. 混合开发的大趋势之一React Native与Android联调

    转载请注明出处:王亟亟的大牛之路 先安利,有空我都会更,看到的好东西都会放进来:https://github.com/ddwhan0123/Useful-Open-Source-Android 公司某 ...

  8. windows批量删除ip

    cmd下输入如下命令第一步:netsh -c int ip dump >c:\ip.txt在C盘根目录看到一个ip.txt的文件,内容为当前网卡的设置信息,为了能更直观的看清楚IP的设置信息. ...

  9. jdk官网历史版本下载&Oracle账号密码

    jdk官网下载地址: https://www.oracle.com/technetwork/java/javase/archive-139210.html 账号密码: 1772885836@qq.co ...

  10. Select级联菜单,用Ajax获取Json绑定下拉框(jQuery)

    需求类似这样  ↓ ↓ ↓   -->    菜单A发生变化,动态取数据填充下拉菜单B. JS代码如下: <script type="text/javascript"& ...