哈希分布与一致性哈希算法简介

来源:互联网 发布:淘宝卖家15天账期延长 编辑:程序博客网 时间:2024/05/25 05:35

转自:http://www.cnblogs.com/liunx/archive/2010/03/24/1693925.html

转摘请注明:博客园一条辉的博客(liunx.cnblogs.com

前言
在我们的日常web应用开发当中memcached可以算作是当今的标准开发配置了。相信memcache的基本原理大家也都了解过了,memcache虽然是分布式的应用服务,但分布的原则是由client端的api来决定的,api根据存储用的key以及已知的服务器列表,根据key的hash计算将指定的key存储到对应的服务器列表上。

基本的原理以及分布
在这里我们通常使用的方法是根据 key的hash值%服务器数取余数 的方法来决定当前这个key的内容发往哪一个服务器的。这里会涉及到一个hash算法的分布问题,哈希的原理用一句话解释就是两个集合间的映射关系函数,在我们通常的应用中基本上可以理解为 在集合A(任意字母数字等组合,此处为存储用的key)里的一条记录去查找集合B(如0-2^32)中的对应记录。(题外话:md5的碰撞或者说冲突其实就是发生在这里,也就是说多个A的记录映射到了同一个B的记录)

实际应用
显然在我们的应用中集合A的记录应该更均匀的分布在集合B的各个位置,这样才能尽量避免我们的数据被分布发送到单一的服务器上,在danga的memcached的原始版本(perl)中使用的是crc32的算法用java的实现写出来:
    private static int origCompatHashingAlg( String key ) {
        int hash    = 0;
        char[] cArr = key.toCharArray();

        for ( int i = 0; i < cArr.length; ++i ) {
            hash = (hash * 33) + cArr[i];
        }

        return hash;
    }
这里还有另一个改进版本的算法:
    private static int newCompatHashingAlg( String key ) {
        CRC32 checksum = new CRC32();
        checksum.update( key.getBytes() );
        int crc = (int) checksum.getValue();

        return (crc >> 16) & 0x7fff;
    }

分布率测试
有人做过测试,随机选择的key在服务器数量为5的时候所有key在服务器群组上的分布概率是:
origCompatHashingAlg:
0 10%
1 9%
2 60%
3 9%
4 9%

newCompatHashingAlg:
0 19%
1 19%
2 20%
3 20%
4 20%

显然使用旧的crc32算法会导致第三个memcached服务的负载更高,但使用新算法会让服务之间的负载更加均衡。
其他常用的hash算法还有FNV-1a Hash,RS Hash,JS Hash,PJW Hash,ELF Hash,AP Hash等等。有兴趣的童鞋可以查看这里:

http://www.partow.net/programming/hashfunctions/

http://hi.baidu.com/algorithms/blog/item/79caabee879ece2a2cf53440.html

小结
至此我们了解到了在我们的应用当中要做到尽量让我们的映射更加均匀分布,可以使服务的负载更加合理均衡。

新问题
但到目前为止我们依然面对了这样一个问题:就是服务实例本身发生变动的时候,导致服务列表变动从而会照成大量的cache数据请求会miss,几乎大部分数据会需要迁移到另外的服务实例上。这样在大型服务在线时,瞬时对后端数据库/硬盘照成的压力很可能导致整个服务的crash。

一致性哈希(Consistent Hashing)
在此我们采用了一种新的方式来解决问题,处理服务器的选择不再仅仅依赖key的hash本身而是将服务实例(节点)的配置也进行hash运算。

  1. 首先求出每个服务节点的hash,并将其配置到一个0~2^32的圆环(continuum)区间上。
  2. 其次使用同样的方法求出你所需要存储的key的hash,也将其配置到这个圆环(continuum)上。
  3. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务节点上。如果超过2^32仍然找不到服务节点,就会保存到第一个memcached服务节点上。

整个数据的图例:


当增加服务节点时:

其他:只有在圆环上增加服务节点的位置为逆时针方向的第一个服务节点上的键会受到影响。

小结
一致性哈希算法最大程度的避免了key在服务节点列表上的重新分布,其他附带的改进就是有的一致性哈希算法还增加了虚拟服务节点的方法,也就是一个服务节点在环上有多个映射点,这样就能抑制分布不均匀,
最大限度地减小服务节点增减时的缓存重新分布。

应用
在memcached的实际应用,虽然官方的版本并不支持Consistent Hashing,但是已经有了现实的Consistent Hashing实现以及虚节点的实现,第一个实现的是last.fm(国外流行的音乐平台)开发的libketama,
其中调用的hash的部分的java版本的实现(基于md5):
    /**
     * Calculates the ketama hash value for a string 
     * @param s
     * @return
     */
    public static Long md5HashingAlg(String key) {

        if(md5==null) {
            try {
                md5 = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException e) {
                log.error( "++++ no md5 algorythm found" );
                throw new IllegalStateException( "++++ no md5 algorythm found");            
            }
        }

        md5.reset();
        md5.update(key.getBytes());
        byte[] bKey = md5.digest();
        long res = ((long)(bKey[3]&0xFF) << 24) | ((long)(bKey[2]&0xFF) << 16) | ((long)(bKey[1]&0xFF) << 8) | (long)(bKey[0]&0xFF);
        return res;
    }
在一致性哈希的算法/策略环境中,按照测试来说时间和分布性都是综合来说比较让人满意的,参见:
http://www.javaeye.com/topic/346682

总结
在我们的web开发应用中的分布式缓存系统里哈希算法承担着系统架构上的关键点。
使用分布更合理的算法可以使得多个服务节点间的负载相对均衡,可以最大程度的避免资源的浪费以及服务器过载。
使用一致性哈希算法,可以最大程度的降低服务硬件环境变化带来的数据迁移代价和风险。
使用更合理的配置策略和算法可以使分布式缓存系统更加高效稳定的为我们整体的应用服务。

展望
一致性哈希的算法/策略来源于p2p网络,其实纵观p2p网络应用的场景,在许多地方与我们的应用有很多相似的地方,可以学习借鉴。
参考文章:
对等网络(P2P)中主流分布式哈希算法比较分析
http://www.ppcn.net/n3443c38.aspx

其他参考文章:
http://www.taiwanren.com/blog/article.asp?id=840
http://www.iwms.net/n923c43.aspx
http://tech.idv2.com/2008/07/24/memcached-004/

相关代码:
last.fm的ketama代码
http://static.last.fm/rj/ketama.tar.bz2

php版的Consistent Hashing实现:Flexihash
主页:
http://paul.annesley.cc/articles/2008/04/flexihash-consistent-hashing-php
google code上的代码主页:
http://code.google.com/p/flexihash/
现在已经移居到github上了:
http://github.com/pda/flexihash/


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 中银淘宝校园卡影响征信问题怎么办 中银E盾快到期了怎么办 京东e卡电子卡卡密泄漏怎么办 买错了京东e卡怎么办 京东购买手机激活后有问题怎么办 优购m9锁屏密码忘记了怎么办视频 中百仓储的购物卡过期了怎么办 武汉中百超市购物卡过期怎么办 已认证抵扣的发票发生退货怎么办 京东白条分期买手机额度不够怎么办 京东白条闪付手机不支持开通怎么办 拼多多不小心下两次单付款了怎么办 不小心给了京东快递差评怎么办 京东金融不小心卸载了怎么办 如果京东快递不小心完成订单怎么办 订机票时没有用常旅客卡怎么办 京东退货退款卖家已签收了怎么办 京东账号手机号换了密码忘了怎么办 qq飞车手游录像下载失败怎么办 手机知道qq号怎么破解密码怎么办 网上购物已付钱迟迟不发货怎么办 有人冒充微信头像和熟人借钱怎么办 微信红包输了50多万怎么办 脖子里的绳结接口磨脖子怎么办 母比格犬生了小狗毛色变了怎么办 母比格犬生了小狗毛色很差怎么办 貂皮大衣上的暗扣掉了怎么办 呢子夹克袖子长但又不想改短怎么办 黑色的衣服熨的有点发亮怎么办 宿管阿姨工作中与学生起冲突怎么办 中通快递发的衣服不合适怎么办 加盟母婴店如果不干了货怎么办 双十一搞活动买的东西退货怎么办 天猫预售30天不发货怎么办 天猫搞活动的商品总不发货怎么办 淘宝买的东西物流把货物损坏怎么办 苹果手机5s每部存满怎么办 天猫退货分开发货退的话怎么办 淘宝优惠券电脑端显示不出来怎么办 天猫退货退款寄错了怎么办 天猫已退款货又发过来了怎么办