一致性hash的实现
一致性hash解决的问题
在解决分布式系统中负载均衡的问题时候可以使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡的作用。
但是普通的余数hash(hash(比如用户id)%服务器机器数)算法伸缩性很差,当新增或者下线服务器机器时候,用户id与服务器的映射关系会大量失效。一致性hash则利用hash环对其进行了改进。
一致性hash的特性
①,单调性
单调性(Monotonicity),单调性是指如果已经有一些请求通过哈希分派到了相应的服务器进行处理,又有新的服务器加入到系统中时候,应保证原有的请求可以被映射到原有的或者新的服务器中去,而不会被映射到原来的其它服务器上去。
原文:https://blog.csdn.net/u011305680/article/details/79721030
参考: https://www.jianshu.com/p/e968c081f563
1、不带虚拟节点的
- package hash;
- import java.util.SortedMap;
- import java.util.TreeMap;
- /**
- * 不带虚拟节点的一致性Hash算法
- * 重点:1.如何造一个hash环,2.如何在哈希环上映射服务器节点,3.如何找到对应的节点
- */
- public class ConsistentHashingWithoutVirtualNode {
- //待添加入Hash环的服务器列表
- private static String[] servers = { "192.168.0.0:111", "192.168.0.1:111",
- "192.168.0.2:111", "192.168.0.3:111", "192.168.0.4:111" };
- //key表示服务器的hash值,value表示服务器
- private static SortedMap<Integer, String> sortedMap = new TreeMap<Integer, String>();
- //程序初始化,将所有的服务器放入sortedMap中
- static {
- for (int i=0; i<servers.length; i++) {
- int hash = getHash(servers[i]);
- System.out.println("[" + servers[i] + "]加入集合中, 其Hash值为" + hash);
- sortedMap.put(hash, servers[i]);
- }
- System.out.println();
- }
- //得到应当路由到的结点
- private static String getServer(String key) {
- //得到该key的hash值
- int hash = getHash(key);
- //得到大于该Hash值的所有Map
- SortedMap<Integer, String> subMap = sortedMap.tailMap(hash);
- if(subMap.isEmpty()){
- //如果没有比该key的hash值大的,则从第一个node开始
- Integer i = sortedMap.firstKey();
- //返回对应的服务器
- return sortedMap.get(i);
- }else{
- //第一个Key就是顺时针过去离node最近的那个结点
- Integer i = subMap.firstKey();
- //返回对应的服务器
- return subMap.get(i);
- }
- }
- //使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别
- private static int getHash(String str) {
- final int p = 16777619;
- int hash = (int) 2166136261L;
- for (int i = 0; i < str.length(); i++)
- hash = (hash ^ str.charAt(i)) * p;
- hash += hash << 13;
- hash ^= hash >> 7;
- hash += hash << 3;
- hash ^= hash >> 17;
- hash += hash << 5;
- // 如果算出来的值为负数则取其绝对值
- if (hash < 0)
- hash = Math.abs(hash);
- return hash;
- }
- public static void main(String[] args) {
- String[] keys = {"太阳", "月亮", "星星"};
- for(int i=0; i<keys.length; i++)
- System.out.println("[" + keys[i] + "]的hash值为" + getHash(keys[i])
- + ", 被路由到结点[" + getServer(keys[i]) + "]");
- }
- }
2、带虚拟节点的
- package hash;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.SortedMap;
- import java.util.TreeMap;
- import org.apache.commons.lang.StringUtils;
- /**
- * 带虚拟节点的一致性Hash算法
- */
- public class ConsistentHashingWithoutVirtualNode {
- //待添加入Hash环的服务器列表
- private static String[] servers = {"192.168.0.0:111", "192.168.0.1:111", "192.168.0.2:111",
- "192.168.0.3:111", "192.168.0.4:111"};
- //真实结点列表,考虑到服务器上线、下线的场景,即添加、删除的场景会比较频繁,这里使用LinkedList会更好
- private static List<String> realNodes = new LinkedList<String>();
- //虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称
- private static SortedMap<Integer, String> virtualNodes = new TreeMap<Integer, String>();
- //虚拟节点的数目,这里写死,为了演示需要,一个真实结点对应5个虚拟节点
- private static final int VIRTUAL_NODES = 5;
- static{
- //先把原始的服务器添加到真实结点列表中
- for(int i=0; i<servers.length; i++)
- realNodes.add(servers[i]);
- //再添加虚拟节点,遍历LinkedList使用foreach循环效率会比较高
- for (String str : realNodes){
- for(int i=0; i<VIRTUAL_NODES; i++){
- String virtualNodeName = str + "&&VN" + String.valueOf(i);
- int hash = getHash(virtualNodeName);
- System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash);
- virtualNodes.put(hash, virtualNodeName);
- }
- }
- System.out.println();
- }
- //使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别
- private static int getHash(String str){
- final int p = 16777619;
- int hash = (int)2166136261L;
- for (int i = 0; i < str.length(); i++)
- hash = (hash ^ str.charAt(i)) * p;
- hash += hash << 13;
- hash ^= hash >> 7;
- hash += hash << 3;
- hash ^= hash >> 17;
- hash += hash << 5;
- // 如果算出来的值为负数则取其绝对值
- if (hash < 0)
- hash = Math.abs(hash);
- return hash;
- }
- //得到应当路由到的结点
- private static String getServer(String key){
- //得到该key的hash值
- int hash = getHash(key);
- // 得到大于该Hash值的所有Map
- SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash);
- String virtualNode;
- if(subMap.isEmpty()){
- //如果没有比该key的hash值大的,则从第一个node开始
- Integer i = virtualNodes.firstKey();
- //返回对应的服务器
- virtualNode = virtualNodes.get(i);
- }else{
- //第一个Key就是顺时针过去离node最近的那个结点
- Integer i = subMap.firstKey();
- //返回对应的服务器
- virtualNode = subMap.get(i);
- }
- //virtualNode虚拟节点名称要截取一下
- if(StringUtils.isNotBlank(virtualNode)){
- return virtualNode.substring(0, virtualNode.indexOf("&&"));
- }
- return null;
- }
- public static void main(String[] args){
- String[] keys = {"太阳", "月亮", "星星"};
- for(int i=0; i<keys.length; i++)
- System.out.println("[" + keys[i] + "]的hash值为" +
- getHash(keys[i]) + ", 被路由到结点[" + getServer(keys[i]) + "]");
- }
- }
一致性hash的实现的更多相关文章
- 对一致性Hash算法,Java代码实现的深入研究
一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...
- 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用
一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...
- 一致性hash算法详解
转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT) ...
- 探索c#之一致性Hash详解
阅读目录: 使用场景 算法原理 虚拟节点 代码示例 使用场景 以Redis为例,当系统需要缓存的内容超过单机内存大小时,例如要缓存100G数据,单机内存仅有16G时.这时候就需要考虑进行缓存数据分片, ...
- 一致性hash算法简介
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希 ...
- 分布式缓存技术memcached学习(四)—— 一致性hash算法原理
分布式一致性hash算法简介 当你看到“分布式一致性hash算法”这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前,我们先来了解一下这几 ...
- 关于Memcached一致性hash的探究
参考文章 http://blog.chinaunix.net/uid-20498361-id-4303232.html http://blog.csdn.net/kongqz/article/deta ...
- 一致性 hash 算法( consistent hashing )a
一致性 hash 算法( consistent hashing ) 张亮 consistent hashing 算法早在 1997 年就在论文 Consistent hashing and rando ...
- Ceph剖析:数据分布之CRUSH算法与一致性Hash
作者:吴香伟 发表于 2014/09/05 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 数据分布是分布式存储系统的一个重要部分,数据分布算法至少要考虑以下三个 ...
- 一致性Hash算法
from wikipedia 一致哈希 历史 1997年由MIT的Karger等在一篇学术论文中提出如何将“一致性Hash”应用于用户易变的分布式Web服务中.也可用于实现健壮缓存来减少大型Web应用 ...
随机推荐
- IntelliJ IDEA 2018.3.2无法正常输入字符问题解决方案
昨天升级IDEA的版本到2018.3.2,今天打开项目发现只要在代码编辑器输入字符(英文.符号或中文等)都会立刻被强制删除,造成一个无法正常输入的现象(回车换行可以).仔细观察这种想象后发有可能是代码 ...
- iOS - 记住用户登录状态保存用户名密码
我们在使用APP时常用的一个功能:用户第一次进入APP时自动进入登录注册页,提示用户注册登录,用户登录成功后才进入主页,再次进入APP时,不用再次登录就直接进到主页了,就算杀掉该APP进程再次进入,依 ...
- python和计算机的交互
网易邮箱都2万+满了,但是只有手动删除.实在太多,于是想使用python脚本实现,python有很多现成的库可以使用,这就是python的好处,而不是c++或者java,python的库说明网站:ht ...
- arch 将 普通用户添加到 docker 组
如果还没有 docker group 就添加一个: sudo groupadd docker 如果你想用你的使用者帳戶(非root帳戶)來使用Docker,把你的帳戶加到Docker的群組中 sudo ...
- ffmpeg 转换 mp4 成 flv
参考资料: https://addpipe.com/blog/flv-to-mp4/ ffmpeg -i demo.mp4 -c:v libx264 -crf 19 demo.flv 或者 ffmpe ...
- 27、 jq 拖拽
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Python学习之旅(三十二)
Python基础知识(31):图形界面(Ⅱ) Python内置了turtle库,可以在计算机上绘图 运动控制: 1.画笔定位到坐标(x,y):turtle.goto(x,y) 2.向正方向运动 dis ...
- python语法_注释
#加需要注释的内容,#号后面的单行注释 #这一段注释 左右各三个注释单引号或者双引号 中间的内容为注释,可以包含多行 '''这一段注释''' """这一段注释" ...
- 怎么将APE转MP3,APE转MP3的方法
怎样实现APE转MP3的问题呢?很多时候我们从网上所下载的音乐格式,可能并不是我们所需要的音乐格式.如APE音乐格式,那么当我们下载了自己并不需要的APE音乐格式我们应该如何将其转换为自己需要的MP3 ...
- linux--- python3环境部署篇
环境部署 我们在pycharm上都是自己设置的python3解释器的环境变量,使得代码能够正常执行!可是怎么能让我们的python代码在LINUX上跑起来呢? linux是内置python,可是内置的 ...