一致性Hash热点

一致性Hash算法是来解决热点问题,如果虚拟节点设置过小热点问题仍旧存在。

关于一致性Hash算法的原理我就不说了,网上有很多人提供自己编写的一致性Hash算法的代码示例,我在跑网上的代码示例发现还是有热点问题。为此我翻阅了Jedis的ShardedJedis类的源码把它的一致性Hash算法提取出来,作为自己的一个工具类,以后自己工程开发中用起来也放心些,毕竟jedis的代码经受了大家的验证。

提取jedis的一致性hash代码作为通用工具类

看看人家码神写的代码,这泛型,这继承,这多态用的,写的真是好,代码通用性真是没话说。

在Sharded方法中:

1 ,定义了一个TreeMap ,TreeMap 用于存储虚拟节点(在初始化方法中,将每台服务器节点采用hash算法划分为160个(默认的,DEFAULT_WEIGHT)虚拟节点(当然也可以配置划分权重)

2 ,定义一个LinkedHashMap,用于存储每一个Redis服务器的物理连接,其中shardInfo的createResource就是物理连接信息 。

3,对于key采用与初始化时同样的hash(MurmurHash或者MD5)算法,然后从TreeMap获取大于等于键hash值得节点,取最邻近节点;

4,当key的hash值大于虚拟节点hash值得最大值时(也就是tail为空),取第一个虚拟节点。

相关完整的源码可以查看我的github的intsmaze-hash这个model,传送点https://github.com/intsmaze/intsmaze。

  1. package cn.intsmaze.hash.shard;
  2. public class Sharded<R, S extends ShardInfo<R>> {
  3. public static final int DEFAULT_WEIGHT = 1;
  4. private TreeMap<Long, S> nodes;
  5. private final Hashing algo;
  6. private final Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>();
  7. public Sharded(List<S> shards) {
  8. this(shards, Hashing.MURMUR_HASH); // MD5 is really not good as we works
  9. // with 64-bits not 128
  10. }
  11. public Sharded(List<S> shards, Hashing algo) {
  12. this.algo = algo;
  13. this.shards=shards;
  14. initialize(shards);
  15. }
  16. private void initialize(List<S> shards) {
  17. nodes = new TreeMap<Long, S>();
  18. for (int i = 0; i != shards.size(); ++i) {
  19. final S shardInfo = shards.get(i);
  20. if (shardInfo.getTableName() == null) for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
  21. nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n), shardInfo);
  22. }
  23. else for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
  24. nodes.put(this.algo.hash(shardInfo.getTableName() + "*" + shardInfo.getWeight() + n), shardInfo);
  25. }
  26. resources.put(shardInfo, shardInfo.createResource());//调用IntsmazeShardInfo的createResource()方法 如果我们的实现不需要控制远程的连接,那么这个方法就不没什么用
  27. }
  28. }
  29. /**
  30. * 这个是找到key对应的节点后,不是仅仅返回属于的节点名称而是返回对应的实例连接
  31. * @param key
  32. * @return
  33. */
  34. public R getShardByResources(String key) {
  35. return resources.get(getShardInfo(key));
  36. }
  37. /**
  38. * 这个是找到key对应的节点后,返回属于的节点名称
  39. * @param key
  40. * @return
  41. */
  42. public S getShard(String key) {
  43. return getShardInfo(key);
  44. }
  45. public S getShardInfo(byte[] key) {
  46. SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
  47. if (tail.isEmpty()) {
  48. return nodes.get(nodes.firstKey());
  49. }
  50. return tail.get(tail.firstKey());
  51. }
  52. public S getShardInfo(String key) {
  53. return getShardInfo(SafeEncoder.encode(key));
  54. }
  55. }
  56. package cn.intsmaze.hash.shard;
  57. public class IntsmazeShardedConnection extends Sharded<Intsmaze, IntsmazeShardInfo>{
  58. public IntsmazeShardedConnection(List<IntsmazeShardInfo> shards) {
  59. super(shards);
  60. }
  61. public String getTable(String key) {
  62. IntsmazeShardInfo intsmazeShardInfo = getShard(key);
  63. return intsmazeShardInfo.getTableName();
  64. }
  65. }
  66. package cn.intsmaze.hash.shard;
  67. public class IntsmazeShardInfo extends ShardInfo<Intsmaze> {
  68. private String host;
  69. private int port;
  70. public IntsmazeShardInfo(String host, String tableName) {
  71. super(Sharded.DEFAULT_WEIGHT, tableName);
  72. URI uri = URI.create(host);
  73. this.host = uri.getHost();
  74. this.port = uri.getPort();
  75. }
  76. @Override
  77. public Intsmaze createResource() {
  78. return new Intsmaze(this);
  79. }
  80. }
  81. package cn.intsmaze.hash.shard;
  82. public abstract class ShardInfo<T> {
  83. private int weight;
  84. private String tableName;
  85. public ShardInfo() {
  86. }
  87. public ShardInfo(int weight,String tableName) {
  88. this.weight = weight;
  89. this.tableName=tableName;
  90. }
  91. protected abstract T createResource();
  92. }
  93. package cn.intsmaze.hash.shard;
  94. public class Test {
  95. private static IntsmazeShardedConnection sharding;
  96. public static void setUpBeforeClass() throws Exception {
  97. List<IntsmazeShardInfo> shards = Arrays.asList(
  98. new IntsmazeShardInfo("localhost:6379", "intsmaze-A"),
  99. new IntsmazeShardInfo("localhost::6379", "intsmaze-B"),
  100. new IntsmazeShardInfo("localhost::6379", "intsmaze-C"),
  101. new IntsmazeShardInfo("localhost::6379", "intsmaze-D"),
  102. new IntsmazeShardInfo("localhost::6379", "intsmaze-E"));
  103. sharding = new IntsmazeShardedConnection(shards);
  104. }
  105. public void shardNormal() {
  106. Map<String,Long> map=new HashMap<String,Long>();
  107. for (int i = 0; i < 10000000; i++) {
  108. String result = sharding.getTable("sn" + i);
  109. Long num=map.get(result);
  110. if(num==null)
  111. {
  112. map.put(result,1L);
  113. }
  114. else
  115. {
  116. num=num+1;
  117. map.put(result,num);
  118. }
  119. }
  120. Set<Map.Entry<String, Long>> entries = map.entrySet();
  121. Iterator<Map.Entry<String, Long>> iterator = entries.iterator();
  122. while(iterator.hasNext())
  123. {
  124. Map.Entry<String, Long> next = iterator.next();
  125. System.out.println(next.getKey()+"--->>>"+next.getValue());
  126. }
  127. }
  128. public static void main(String[] args) throws Exception {
  129. Test t=new Test();
  130. t.setUpBeforeClass();
  131. t.shardNormal();
  132. }
  133. }

没有热点问题

把jedis的源码提取出来后,跑了一下,发现没有热点问题,原理不是采用算法的问题,而是一个物理节点对应的虚拟节点的数量的问题导致使用hash算法后,还是有热点问题。jedis源码物理节点对应虚拟节点时160,而网上大部分代码都是10以下,所以导致了热点问题,这也告诉我们,实现一致性Hash算法时,不要太吝啬,虚拟节点设置的大点,热点问题就不会再有。

相关完整的源码可以查看我的github的intsmaze-hash这个model,传送点https://github.com/intsmaze/intsmaze。

提取jedis源码的一致性hash代码作为通用工具类的更多相关文章

  1. 读 Kafka 源码写优雅业务代码:配置类

    这个 Kafka 的专题,我会从系统整体架构,设计到代码落地.和大家一起杠源码,学技巧,涨知识.希望大家持续关注一起见证成长! 我相信:技术的道路,十年如一日!十年磨一剑! 往期文章 Kafka 探险 ...

  2. nginx源码分析之hash的实现

    nginx实现了自己的hash数据结构,正如数据结构中讲述的那样,nginx用开放链表法解决冲突,不过不同的是一旦一个hash表被初始化后就不会被修改,即插入和删除,只进行查询操作,所以nginx通过 ...

  3. java-通过 HashMap、HashSet 的源码分析其 Hash 存储机制

    通过 HashMap.HashSet 的源码分析其 Hash 存储机制 集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并非真正的把 Java 对象放入数组中.仅仅是把对象的 ...

  4. Jedis源码浅析

    1.概述 Jedis是redis官网推荐的redis java client,代码维护在github https://github.com/xetorthio/jedis. 本质上Jedis帮我们封装 ...

  5. [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构

    [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构 目录 [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构 0x00 摘要 0x01 文件简介 0x02 总体架构 0x03 总体代码 0x0 ...

  6. WeMall微信商城源码活动报名插件代码详情

    WeMall微信商城源码插件活动报名代码是用于商业推广的比较有效的方式,分享了部分比较重要的代码,供技术员学习参考,商家可自由设置报名项目,活动时间,报名内容 代码详情地址:http://addon. ...

  7. WeMall微信商城源码插件大转盘代码详情

    WeMall微信商城源码插件大转盘代码是用于商业推广的比较有效的方式,分享了部分比较重要的代码,供技术员学习参考 代码详情地址:http://addon.wemallshop.com/Product/ ...

  8. 手机自动化测试:Appium源码分析之跟踪代码分析九

    手机自动化测试:Appium源码分析之跟踪代码分析九   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家 ...

  9. 手机自动化测试:Appium源码分析之跟踪代码分析八

    手机自动化测试:Appium源码分析之跟踪代码分析八   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家 ...

随机推荐

  1. 智能ERP主副机设置

    智能ERP主副机设置 1. 将主机的电脑设置成固定IP,IP地址请自行设置,设置好后需要记住,配置副机的时候会用到 2. 在主机上安装智能ERP,安装完后,会弹出数据库配置,主机直接点校验 3. 校验 ...

  2. mssql sqlserver 获取指定日期为本月第几个工作日

    转自:http://www.maomao365.com/?p=6771 摘要: 下文讲述工作中,需要获取指定日期在当月的工作日 下文讲述常规的指定工作日所在月的天数分析,实现思路:1 生成一个国家法定 ...

  3. UGUI ContentSizeFitter之Button根据Text自适应

    环境 Unity3D 5.3.6f1 练习地址:https://github.com/zhaoqingqing/UGUIDemo  布局放在Layout文件夹 文档:https://docs.unit ...

  4. 使用蒲公英路由器 X3 设置为网络中继器

    由于我的路由器放的时间比较久没有用了,所以先让路由器来个升级.链接图如下: 在浏览器地址栏中输入  oraybox.com,系统会自动跳到 https://pgybox.oray.com/passpo ...

  5. 数组实例的 copyWithin()

    用途:在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组.也就是说,使用这个方法,会修改数组本身. 用法:Array.prototype.copyWithin(targ ...

  6. Fetch请求后台的数据

    <style> #btn{ width: 50px; height: 50px; background-color: red; } #output{ width: 100px; heigh ...

  7. nginx 拦截 swagger 登录

    随着微服务的也来越多,每个服务都有单独的文档,那么问题来了,怎么把所有文档整合在一起呢 本方法采用服务器拦截的方式进行处理 首先需要在opt 的主目录中 /opt/ 创建一个新文件 htpasswd此 ...

  8. Teradata 终止回滚方法(rcvmanager工具)

    1.使用root用户登录数据库节点 ssh root 2.启动database window cnsterm 3.启动rcvmanager start rcvmanager 4.确认utiltiy在哪 ...

  9. JS页面打印

    平常浏览网页和文档的时候,随处可见打印两个字,有时候不小心点到或者快捷键触发到,就会弹出一个打印的页面,上边显示的打印机是GoldGrid Virtual Printer,这是计算机的虚拟打印机,打印 ...

  10. Java面试知识点之计算机网络篇(一)

    前言:在Java面试中,计算机网络的知识也是一项重点,因此笔者在此对计算机网络的相关知识进行总结. 1.OSI参考模型 自下而上:物理层(物理介质,比特流).数据链路层(网卡.交换机).网络层(IP协 ...