一致性hash 简单实现
package com.jackiesteed.algorithms;import java.util.*;/*** 虚拟节点个数需要事先确定好, 而且不能修改.* 核心代码模拟了一下remapping的逻辑, 如何做到均衡分配.* 如何保证一致性呢? 每次重新分配的时候, 只有被移动的虚拟节点才会收到影响, 保持了一致性.* 一致性hash 简单实现, 单线程使用* key 固定为String, value 支持泛型* 感觉只是走了下流程, 离实际使用在性能, 并发方面还要改进.* Created by jackie on 5/24/15.*/
public class ConsistentHashMap <T>{/*** 存储机器id对应的真实ip, 用来做远程调用.*/private Map<String, Stack<Integer>> realNodeMap;/*** 虚拟节点到真实节点的映射* 虚拟节点数根据现实情况来权衡.* 节点数极大的话, 可以保证趋向于决定均匀分布, 但是remapping的时间开销交大.* 节点数少, 压力不一定非常均匀, 但是remapping速度回块一些.* 但是虚拟节点数, 一定要是服务所需的机器数的N倍之多.*/private String[] virtualRealMap;/*** 用来模拟分布式系统里面的每台机器* key 是ip, value mock机器里面的存储, 是个java.util.Map*/private Map<String, Map<String, T>> hostMock;/*** 构造函数里面初始化虚拟节点个数.* @param virtualNodeCount*/public ConsistentHashMap(int virtualNodeCount){virtualRealMap = new String[virtualNodeCount];realNodeMap = new HashMap<String, Stack<Integer>>();hostMock = new HashMap<String, Map<String, T>>();}/*** 对外接口, 写入数据到分布式存储里面.* @param key* @param value*/public void put(String key, T value){put(getRealHashCode(key), key, value);}/*** 对外暴露的接口, 从分布式存储提取数据.* @param key* @return*/public T get(String key){return get(getRealHashCode(key), key);}/*** 根据key计算需要映射的真是机器的id.* @param key* @return*/private String getRealHashCode(String key){//字符串原本的hash值int oriHashCode = key.hashCode();//key对应的虚拟节点的hash值int virtualHashCode = (oriHashCode % virtualRealMap.length + virtualRealMap.length) % virtualRealMap.length;//映射出来的真实String ip  = virtualRealMap[virtualHashCode];return ip;}/*** 这个其实就是和真是的数据存储进行交互了, ip用来访问真实机器.* @param ip* @param key* @param value*/private void put(String ip, String key, T value){hostMock.get(ip).put(key, value);}/*** realHashCode表示对应机器的id, 从这台机器上面获取数据.* @param* @param key* @return*/private T get(String ip, String key){return hostMock.get(ip).get(key);}/*** 添加一台机器.* @param ip*/public void addHost(String ip){/*** 如果已经存在了, 就不加入*/if(realNodeMap.containsKey(ip))return;hostMock.put(ip, new HashMap<String, T>());//目前还没有机器加入, 那么需要走特殊的初始化流程if(realNodeMap.isEmpty()){Stack<Integer> virtualIds = new Stack<Integer>();for(int i = 0; i < virtualRealMap.length; i++){virtualRealMap[i] = ip;virtualIds.push(i);}realNodeMap.put(ip, virtualIds);return;}int expectCount = virtualRealMap.length / (realNodeMap.size() + 1);Stack<Integer> virtualIds = new Stack<Integer>();while(virtualIds.size() < expectCount){for(Map.Entry<String, Stack<Integer>> entry : realNodeMap.entrySet()){Stack<Integer> oldVirtualIds = entry.getValue();while(oldVirtualIds.size() > expectCount){int virtualId = oldVirtualIds.pop();virtualRealMap[virtualId] = ip;virtualIds.push(virtualId);}if(virtualIds.size() >= expectCount)break;}}realNodeMap.put(ip, virtualIds);}/*** 从分布式系统里删除一台机器* @param ip*/public void deleteHost(String ip){if(!realNodeMap.containsKey(ip))return;hostMock.remove(ip);Stack<Integer> virtualIds = realNodeMap.get(ip);int expectCount = virtualRealMap.length / (realNodeMap.size() - 1);realNodeMap.remove(ip);//说明这是最后一个ip, 没有办法把这个ip映射的虚拟节点重新映射了, 直接全部都删掉.if(realNodeMap.isEmpty()){for(int i = 0; i < virtualRealMap.length; i++){virtualRealMap[i] = null;}return;}while(!virtualIds.isEmpty()){for(Map.Entry<String, Stack<Integer>> entry : realNodeMap.entrySet()){Stack<Integer> oldVirtualIds = entry.getValue();while(oldVirtualIds.size() < expectCount && !virtualIds.isEmpty()){int virtualId = virtualIds.pop();virtualRealMap[virtualId] = ip;oldVirtualIds.push(virtualId);}if(virtualIds.isEmpty())break;}//如果不增加, 有可能永远分配不出去.expectCount++;}}public void dump(){System.out.println("=====================================================");System.out.println("VirtualNodeCount : " + virtualRealMap.length);for(Map.Entry<String, Stack<Integer>> entry : realNodeMap.entrySet()){System.out.print(entry.getKey() + " : | ");for(Integer virtualId : entry.getValue()){System.out.format("%2d | ", virtualId);}System.out.println();}System.out.println("=====================================================");}public static void main(String[] args){ConsistentHashMap<String> consistentHashMap = new ConsistentHashMap<String>(30);consistentHashMap.addHost("192.168.0.1");consistentHashMap.addHost("192.168.0.2");consistentHashMap.addHost("192.168.0.4");consistentHashMap.addHost("192.168.0.3");consistentHashMap.addHost("192.168.0.8");consistentHashMap.addHost("192.168.0.13");consistentHashMap.addHost("192.168.0.14");consistentHashMap.deleteHost("192.168.0.4");consistentHashMap.deleteHost("192.168.0.1");consistentHashMap.deleteHost("192.168.0.2");consistentHashMap.addHost("123.123.123.123");consistentHashMap.addHost("123.123.123.124");consistentHashMap.addHost("123.123.123.125");consistentHashMap.dump();consistentHashMap.put("jackie", "abc");System.out.println(consistentHashMap.get("jackie"));}
}

posted on 2015-05-24 23:47 Jackiesteed 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/jackiesteed/articles/4526848.html

一致性hash 简单实现相关推荐

  1. 一致性Hash简单介绍和使用

    背景: 一致性Hash用于分布式缓存系统,将Key值映射到详细机器Ip上,而且添加和删除1台机器的数据移动量较小,对现网影响较小 实现: 1 Hash环:将节点的Hash值映射到一个Hash环中.每一 ...

  2. 一致性 Hash 算法的实际应用

    前言 记得一年前分享过一篇<一致性 Hash 算法分析>,当时只是分析了这个算法的实现原理.解决了什么问题等. 但没有实际实现一个这样的算法,毕竟要加深印象还得自己撸一遍,于是本次就当前的 ...

  3. 不会一致性hash算法,劝你简历别写搞过负载均衡

    这两天看到技术群里,有小伙伴在讨论一致性hash算法的问题,正愁没啥写的题目就来了,那就简单介绍下它的原理.下边我们以分布式缓存中经典场景举例,面试中也是经常提及的一些话题,看看什么是一致性hash算 ...

  4. 什么是一致性 Hash 算法

    数据分片 先让我们看一个例子吧 我们经常会用 Redis 做缓存,把一些数据放在上面,以减少数据的压力. 当数据量少,访问压力不大的时候,通常一台Redis就能搞定,为了高可用,弄个主从也就足够了: ...

  5. hash算法_一致性hash算法简介

    一致性hash算法有什么用?我们为什么需要一致性hash算法?这两个问题的答案可以看这篇文章 分布式系统路由算法简介. 了解了一致性hash算法出现的背景,我们来看看什么是一致性hash算法.一致性h ...

  6. 一致性hash算法_分布式寻址算法

    一.分布式寻址算法简介 分布式寻址算法是很重要的内容,不了解这些算法,也就不能透彻的了解各种分布式中间件的原理.简单说一下这些高大上的寻址到底是个啥意思,比如在elasticsearch中,采用的是多 ...

  7. php 实现一致性hash 算法 memcache

    散列表的应用 涉及到数据查找比对,首先考虑到使用HashSet.HashSet最大的好处就是实现查找时间复杂度为O(1).使用HashSet需要解决一个重要问题:冲突问题.对比研究了网上一些字符串哈希 ...

  8. 一致性hash算法简介

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

  9. Redis:一致性Hash算法

    1. 前言 在Redis 集群模式Cluster中,Redis采用的是分片Sharding的方式,也就是将数据采用一定的分区策略,分发到相应的集群节点中.但是我们使用上述HASH算法进行缓存时,会出现 ...

最新文章

  1. char 类型的数组转换到CSting
  2. vcenter6.0+EXSI6.0 部署虚拟机win10,安装vmtools后不能显示桌面
  3. php 垃圾回收机制 转载
  4. Matlab图像处理创新实践-实验4【综合设计大实验——GUI综合设计】
  5. subList生成的列表和原列表的对比
  6. HTML/CSS/JavaScript学习笔记【持续更新】
  7. nodejs 嵌套消除和高并发
  8. Java_String_01_由转义字符串得到其原本字符串
  9. 浅谈http协议六种请求方法,get、head、put、delete、post、options区别
  10. 高校学生管理系统(课设毕设有源码)
  11. 基于linux嵌入式课程设计报告,嵌入式linux课程设计报告.doc
  12. php 判断客户端类型,怎么使用php判断客户端的类型
  13. editplus配置python_Editplus配置Python的开发环境
  14. ELK抓取AWS-ELB日志的logstash配置文件
  15. linux是基于什么的开源操作系统,什么是开源操作系统
  16. php面试题之四——PHP面向对象(基础部分)
  17. 华为荣耀c4刷入linux系统,华为荣耀畅玩4C移动4G(CHM-TL00 Android 4.4)刷Recovery教程
  18. 一年级abb式词语并造句_用ABB造句-怎么用abb式词语造句-用ABB式的词语造句子
  19. SLAM学习——李群与李代数
  20. Java 类加载顺序与成员变量初始化

热门文章

  1. AM3354开发 -- 使用root模式登录Ubuntu18.04
  2. hdu-1251(基本字典树)
  3. layui select下拉框改变之 change 监听事件
  4. 【问链-区块链基础知识系列】 第十五课 数字货币交易所的前世、今生和未来(二)
  5. spring 事务原理_Spring声明式事务处理的实现原理,来自面试官的穷追拷问
  6. I2C和SPI异同及使用注意
  7. python自定义函数实例计算1-n的偶偶数和_python用户输入一个整数N,计算并输出1到N相加的和,请问这个程序错在哪里了?...
  8. 计算机无法找到实达打印机,实达打印机使用方法教程
  9. c 实现html5,html5 实现手机摇一摇功能(C)
  10. 为什么读博士以及有什么意义