• 一致性哈希算法


    时间:2014.07.17

    地点:基地地板

    ----------------------------------------------------------------------------------------

    一、为什么我们须要一致性哈希算法

    考虑一个场景:server负载均衡问题。有n台server,比方n台cache。cache编号的选择和object的
    匹配应该採取什么用的策略才干满足保证功能的需求。

    假设我们採取例如以下简单的哈希映射关系:
    hash(object) mod n

    看起来这样一个系统工作正常,但考虑周到会有例如以下几个问题:
    问题1:有一天我们须要添加一台server。这时我们须要改变哈希映射关系为:
    hash(object) mod (n+1)
    问题2:有一天我们须要删除一台server,这时我们须要改变哈希映射关系为:
    hash(object) mod (n-1)

    问题3:怎么样使得server负载分配均匀

    如今我们看到麻烦来了,因为hash关系的变化。差点儿全部的object将会被hash到新的位置,即映射到新的server,这是一种灾难,于是我们就须要一致性哈希来改善这样的情况了。

    ----------------------------------------------------------------------------------------

    二、一致性哈希

      一致性哈希能够保证当随意一台server添加到系统或从系统中删除时,只唯独相关的有限个object须要又一次匹配。即一致性哈希最大程度地防止object与server之前的匹配关系。

    ----------------------------------------------------------------------------------------

    三、哈希空间(hash space)

        一般地,哈希函数将object映射到一个位的值上,哈希值取值范围为[0~2^32-1]。例如以下图所看到的。我们把哈希值域首尾相接联合成一个环形。于是也称呼为环形哈希空间。

                                                                       

                                                                        哈希空间

    ----------------------------------------------------------------------------------------

    四、将object映射到哈希空间

    如果有4个object,分别为object1~object4,如今我们使用哈希函数获得他们各自的key值。并映射到环形哈希空间中去。例如以下图所看到的:
    hash(object1)=key1;
    hash(object2)=key2;
    hash(object3)=key3;
    hash(object4)=key4;

                                          
                                                      

                                                      将object映射到哈希空间

    ----------------------------------------------------------------------------------------

    五、将cache映射到哈希空间

    我们採用相同的哈希函数。继续还将server也映射到该环形哈希空间中,
    如果我们有3台serverA,B,C,哈希之后例如以下:
    hash(cacheA)=keyA;
    hash(cacheB)=keyB;
    hash(cacheC)=keyC;

                                              

                                               将cache以相同的方式也映射到哈希空间

                                                                             

    ----------------------------------------------------------------------------------------

    六、将object与cache匹配

      经过之前的步骤,如今object和cache都已经成功映射到环形哈希空间去了。

    接下来,我们将决定objects怎么和cache形成映射:我们採取的策略是,将object按顺时针方向走。直到找到第一个cache,若果该cache是可用的,即形成object和cache匹配,否则继续寻找下一个cache。依据上述原则,在这里我们得到的匹配结果是:
        object1——>cacheA
        object2——>cacheC
        object3——>cacheC
        object4——>cacheB

    ----------------------------------------------------------------------------------------

    七、添加或删减cache

      如今考虑两种场景:1.当某一cache崩溃移除系统 ,因为object4是映射在cacheB上的,如今cacheB将被移除了。那么如今object4得重现更新这个映射,我们仅仅须要简单的沿顺时针方向找到下一个可用的cache,在这里是cacheC就可以。如图,而不必所以映射关系全盘修改。

                               

                                                  cacheB崩溃

    当将cacheD增加在object2和object3之间时,B和D之间的object也需又一次映射。在这里object2将绑定到新增加的cacheD上。

    例如以下图:

                                      

                                                         添加cacheD

    ----------------------------------------------------------------------------------------

    八、虚节点

        上述情况可以非常好的解决添加删除server节点时对整个系统大动干戈的问题。

    但还存在一个问题,那就是假设环形哈希空间上的cache较少的话,object的部署不会那么均匀。于是我们引入虚节点的概念。

     。它可以比較好的改善这一缺点。 虚节点是环形哈希空间上哥cache点的副本,每一个cache关联着几个环形上的虚节点,当我们添加一个节点时,这意味着我们实际上在环形空间上添加了几个这种虚节点,相同删除某一cache时。我们也将移除环形空间上
    全部和它相关的虚节点。

    继续考虑上面的样例,如今系统中有cachA和cacheC,引入虚节点。并如果各存在2份,于是在环形空间上。一起有4个虚节点。cacheA1和cacheA2代表cacheA。还有cacheC1和cacheC2代表C。例如以下图:于是,如今从object到虚节点的映射为:
         object1——>cacheA2;
         object2——>cacheA1;
         object3——>cacheC1;
         object4——>cacheC2
    这样分配就会显得相对均匀。例如以下图:


         

    九、一致性哈希算法的应用

      最后来个实际应用的样例。

    问题描写叙述: 比如手机朋友网有n个server,为了方便用户的訪问会在server上缓存数据,因此用户每次訪问的时候最好能保持同一台server。

    已有的做法是依据ServerIPIndex[QQNUM%n]得到请求的server,这样的方法非常方便将用户分到不同的server上去。可是假设一台server死掉了,那么n就变为了n-1,那么ServerIPIndex[QQNUM%n]与ServerIPIndex[QQNUM%(n-1)]基本上都不一样了,所以大多数用户的请求都会转到其它server,这样会发生大量訪问错误。


    问: 怎样改进或者换一种方法,使得:
    (1)一台server死掉后。不会造成大面积的訪问错误,
    (2)原有的訪问基本还是停留在同一台server上。
    (3)尽量考虑负载均衡。


    显然,传统的办法题目已经给出,即用模余方法:做法非常easy。但存在非常多问题不满足需求。于是我们考虑一致性哈希算法。正如前面所述。


    其他应用场景:
        在做server负载均衡时候可供选择的负载均衡的算法有非常多,包含:  轮循算法(Round Robin)、哈希算法(HASH)、最少连接算法(Least Connection)、响应速度算法(Response Time)、加权法(Weighted )等。当中哈希算法是最为经常使用的算法.
        最典型的应用场景就是: 有N台server提供缓存服务,须要对server进行负载均衡。将请求平均分发到每台server上,每台机器负责1/N的服务。


        经常使用的算法是对hash结果取余数 (hash() mod N):对机器编号从0到N-1,依照自己定义的hash()算法,对每一个请求的hash()值按N取模,得到余数i。然后将请求分发到编号为i的机器。

    但这种算法方法存在致命问题。假设某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时须要将当掉的server从算法从去除,此时候会有(N-1)/N的server的缓存数据须要又一次进行计算。假设新增一台机器,会有N /(N+1)的server的缓存数据须要进行又一次计算。对于系统而言,这一般是不可接受的颠簸(由于这意味着大量缓存的失效或者数据须要转移)。那么,怎样设计一个负载均衡策略,使得受到影响的请求尽可能的少呢?
        在Memcached、Key-Value Store、Bittorrent DHT、LVS中都採用了Consistent Hashing算法,能够说Consistent Hashing 是分布式系统负载均衡的首选算法。




    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    迭代器和生成器
    函数嵌套
    页面调用dll
    C++MFC之picture control控件铺满图片
    C++中去掉string字符串中的 等
    C++之map使用
    C++之条形码,windows下zint库的编译及应用(二)
    C++之条形码,windows下zint库的编译及应用(一)
    C++通过HTTP请求Get或Post方式请求Json数据(转)
    从长字符串中获取想要的字符串
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4624433.html
Copyright © 2020-2023  润新知