前言
在我们的日常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/

本文转自 小强测试帮 51CTO博客,原文链接:http://blog.51cto.com/xqtesting/1348769,如需转载请自行联系原作者

一致性Hash与负载均衡相关推荐

  1. 详解【负载均衡】(负载均衡算法、一致性hash、负载均衡架构分析)

    作者:duktig 博客:https://duktig.cn 优秀还努力.愿你付出甘之如饴,所得归于欢喜. 本文源码参看:https://github.com/duktig666/distribute ...

  2. 一致性 Hash 在负载均衡中的应用

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:干掉 Navicat:这个 IDEA 的兄弟真香!个人原创100W+访问量博客:点击前往,查看更多 转自:Mar ...

  3. hash地址_一致性Hash在负载均衡中的应用

    作者:marklux 原文:http://marklux.cn/blog/90 简介 一致性Hash是一种特殊的Hash算法,由于其均衡性.持久性的映射特点,被广泛的应用于负载均衡领域,如nginx和 ...

  4. 聊聊一致性Hash在负载均衡中的应用

    作者:marklux http://marklux.cn/blog/90 简介 一致性Hash是一种特殊的Hash算法,由于其均衡性.持久性的映射特点,被广泛的应用于负载均衡领域,如nginx和mem ...

  5. 一致性Hash在负载均衡中的应用

    简介 一致性Hash是一种特殊的Hash算法,由于其均衡性.持久性的映射特点,被广泛的应用于负载均衡领域,如nginx和memcached都采用了一致性Hash来作为集群负载均衡的方案.本文将介绍一致 ...

  6. crc32算法_一致性hash算法负载均衡

    有没有好奇过redis.memcache等是怎么实现集群负载均衡的呢? 其实他们都是通过一致性hash算法实现节点调度的. 讲一致性hash算法前,先简述一下求余hash算法: hash(object ...

  7. 压力测试过负载均衡_一致性 Hash 在负载均衡中的应用

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 If you concentrate on the ONE thing in ...

  8. java 一致性hash算法 均衡分发_Dubbo一致性哈希负载均衡的源码和Bug,了解一下?...

    本文是对于Dubbo负载均衡策略之一的一致性哈希负载均衡的详细分析.对源码逐行解读.根据实际运行结果,配以丰富的图片,可能是东半球讲一致性哈希算法在Dubbo中的实现最详细的文章了. 文中所示源码,没 ...

  9. @cacheable 服务器 不一致_Dubbo一致性哈希负载均衡的源码和Bug,了解一下?

    持续输出原创文章,点击蓝字关注我吧 本文是对于Dubbo负载均衡策略之一的一致性哈希负载均衡的详细分析.对源码逐行解读.根据实际运行结果,配以丰富的图片,可能是东半球讲一致性哈希算法在Dubbo中的实 ...

  10. nginx负载均衡之一致性Hash方式

    ip_hash方式 关于nginx的负载均衡,大家都知道有一个ip_hash的方式,就是将客户端的ip取hash值,然后根据服务器 的数量取模,得出的值就是最后被路由到的服务器(服务器从0开始数),但 ...

最新文章

  1. 标准化工作导则2020_最新版 GB/T 1.12020 标准化工作导则 第 1 部分:标准化文件的结构和起草规则标准解读...
  2. HTML与CSS基础之兄弟元素(六)
  3. 对自学还是培训的看法
  4. java设置并行度_控制Java并行流的并行度
  5. centos 6.9 安装 Mysql 5.7.20 安装
  6. 【clickhouse】ClickHouse基础、实践、调优全视角解析
  7. [转]2020 年最具潜力 44 个顶级开源项目,涵盖 11 类 AI 学习框架、平台(值得收藏)
  8. 6月全球垃圾邮件上升6.9% 以色列高居榜首
  9. 堆和栈的概念和区别?
  10. Swing组件集合的事件处理(六)
  11. jmeter json提取器和正则表达式提取器
  12. 今秋如何让自己的C币也来个大丰收
  13. 微信小程序用地理编码做地图标注
  14. 门诊挂号c语言程序代码,C语言版医院管理系统
  15. 一篇博客解决网线挑选问题
  16. Halcon慢慢来(卡尺找线、找圆)
  17. 017 Vowels match
  18. 活猫还是死猫?| 薛定谔的猫 | 儿童故事
  19. Java多线程编程——线程同步与线程安全问题及synchronized关键字
  20. 国内首届中文人机对话技术评测赛果出炉,两项任务冠军团队都分享了哪些技术细节?...

热门文章

  1. 2017-2018-1 20155330 《信息安全系统设计基础》第3周学习总结
  2. ios开发之CoreData使用
  3. spring 事物配置几种
  4. 如何让一个层关闭之后,就算刷新页面了也不显示。除非关闭页面再次打开
  5. 2004-7-1+ 用户控件(动态加载)
  6. 《程序是怎样跑起来的》第六章有感
  7. 中文词向量论文综述(三)
  8. Html 解决长串英文字母显示不能自动换行
  9. string.Format字符串格式化说明
  10. mydbtest文档