简单解释:

简单解释一致性hash的原理:网上通篇都是用服务器做的举例,我这里也如此,主要是便于理解。

通常:有N个客户端请求服务器,假设有M台web服务器,通常为了均衡访问会进行N%M的取模,然后分配到不同的缓存服务器访问。问题是一旦缓存服务器增加或减少时缓存的命中率被打乱,因为取模发生了变化。例A的访问分配到了M1上,假设服务器增减则有可能会被分配到M3上(M3为举例),那么M1上的原有缓存失效,M3需要重新建立A访问的缓存。

一致性Hash:有N个客户端请求服务器,假设有M台web服务器,把其中一个请求做HASH,M台服务器也做HASH,采用Sortedmap的tailMap特性,检索顺时针最近的一台服务器作为缓存服务器;

例:其中一个请求HASHCODE=254,M台服务器HASH后分别为1、58、648...(数字为举例),那么通过Sortedmap的tailMap特性可以找到648以及后面的服务器,则把最近的648作为缓存服务器。当然 如果tailMap找到的为NULL,则从Sortedmap的第一条key作为缓存服务器(保证map是一个环装)

简单代码:

完整代码示意-摘自互联网的代码(整理后),可以参考。

package com.yiibai;

import java.util.*;

public class TreeMapDemo {
public static void main(String[] args) {
// creating maps
TreeMap<Integer, String> treemap = new TreeMap<Integer, String>();
SortedMap<Integer, String> treemapincl = new TreeMap<Integer, String>(); // populating tree map
treemap.put(2, "two");
treemap.put(1, "one");
treemap.put(3, "three");
treemap.put(6, "six");
treemap.put(5, "five"); System.out.println("Getting tail map");
treemapincl=treemap.tailMap(3);
System.out.println("Tail map values: "+treemapincl);
}
}

完整代码示意-摘自互联网的代码(整理后),可以参考。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap; import org.apache.commons.codec.digest.DigestUtils; public class VNode {
private SortedMap<Integer, String> serverNodeMap = null; private final static int VIRTUAL_NODE_NUMBER = 5; public void getServerNodeWithoutVirtualNode(List<String> servers)
{
serverNodeMap = new TreeMap<Integer, String>();
for (String string : servers)
{
serverNodeMap.put(hash(string), string);
}
} public void getServerNodeWithVirtualNode(List<String> servers)
{
serverNodeMap = new TreeMap<Integer, String>();
for (String string : servers)
{
for (int i = 0; i < VIRTUAL_NODE_NUMBER; i++)
{
String virtualNodeName = string + ":" + i;
serverNodeMap.put(hash(virtualNodeName), string);
}
}
} public String getServerName(String data)
{
int dataHash = hash(data);
SortedMap<Integer, String> subMap = serverNodeMap.tailMap(dataHash);
int serverHash = 0;
if (subMap == null || subMap.size() == 0)
{
serverHash = serverNodeMap.firstKey();
}
else
{
serverHash = subMap.firstKey();
} String serverName = serverNodeMap.get(serverHash);
return serverName; } /**
* hash计算,这里使用md5后取hashcode,这个md5需要依赖apache的codec包
* @param str
* @return
*/
public int hash(String str)
{
//System.out.println(str+"的hashcode="+DigestUtils.md5Hex(str).hashCode());
return DigestUtils.md5Hex(str).hashCode();
} public static void main(String[] args)
{
List<String> servers = new ArrayList<String>();
servers.add("192.168.1.1");
servers.add("192.168.1.2");
servers.add("192.168.1.3");
servers.add("192.168.1.4");
servers.add("192.168.1.5");
servers.add("192.168.1.6"); List<String> datas = new ArrayList<String>();
datas.add("A");
datas.add("B");
datas.add("C");
datas.add("D");
datas.add("E");
datas.add("F");
datas.add("G");
datas.add("H");
datas.add("I"); VNode consistentHash = new VNode();
System.out.println("没有虚拟节点的情况:");
consistentHash.getServerNodeWithoutVirtualNode(servers);
consistentHash.printDataAndServerNode(servers, datas, consistentHash);
System.out.println("有虚拟节点的情况:");
consistentHash.getServerNodeWithVirtualNode(servers);
consistentHash.printDataAndServerNode(servers, datas, consistentHash); servers.add("192.168.1.7");
System.out.println("增加第一个一个节点后:");
System.out.println("没有虚拟节点的情况:");
consistentHash.getServerNodeWithoutVirtualNode(servers);
consistentHash.printDataAndServerNode(servers, datas, consistentHash);
System.out.println("有虚拟节点的情况:");
consistentHash.getServerNodeWithVirtualNode(servers);
consistentHash.printDataAndServerNode(servers, datas, consistentHash); servers.remove(0);
System.out.println("移除第一个一个节点后:");
System.out.println("没有虚拟节点的情况:");
consistentHash.getServerNodeWithoutVirtualNode(servers);
consistentHash.printDataAndServerNode(servers, datas, consistentHash);
System.out.println("有虚拟节点的情况:");
consistentHash.getServerNodeWithVirtualNode(servers);
consistentHash.printDataAndServerNode(servers, datas, consistentHash); } public void printDataAndServerNode(List<String> servers, List<String> datas,VNode consistentHash)
{
Map<String, String> result = new HashMap<String, String>();
for (String data : datas)
{
String serverName = consistentHash.getServerName(data);
if (!result.containsKey(serverName))
{
result.put(serverName, data);
}
else
{
result.put(serverName, result.get(serverName) + "," + data);
}
} for (Entry<String, String> entry : result.entrySet())
{
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}

一致性hash(整理版)的更多相关文章

  1. 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用

    一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...

  2. 一致性 hash 算法( consistent hashing )a

    一致性 hash 算法( consistent hashing ) 张亮 consistent hashing 算法早在 1997 年就在论文 Consistent hashing and rando ...

  3. 一致性Hash算法在Redis分布式中的使用

    由于redis是单点,但是项目中不可避免的会使用多台Redis缓存服务器,那么怎么把缓存的Key均匀的映射到多台Redis服务器上,且随着缓存服务器的增加或减少时做到最小化的减少缓存Key的命中率呢? ...

  4. 一致性hash和solr千万级数据分布式搜索引擎中的应用

    互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中 获得成功,这个和当前的开源技术.海量数据架构有着必不可分的关 ...

  5. python -- 一致性Hash

    python有一个python模块--hash_ring,即python中的一致性hash,使用起来也挺简单. 可以参考下官方例子:https://pypi.python.org/pypi/hash_ ...

  6. 一致性 Hash 学习与实现

    普通的 Hash 解决的是什么问题? 下图是一个普通的余数法构造的哈希表. 一般在编程中使用哈希表,某个 bucket 突然就没了的概率比较小,常见的是因为负载因子太大需要增加 bucket,然后 r ...

  7. memcached 一致性hash原理

    memcache 是一个分布式的缓存系统,但是本身没有提供集群功能,在大型应用的情况下容易成为瓶颈.但是客户端这个时候可以自由扩展,分两阶段实现.第一阶段:key 要先根据一定的算法映射到一台memc ...

  8. 一致性 hash 算法(转)

    add by zhj:介绍了什么是一致性hash,以及实现一致性hash的一种算法. 原文:http://my.oschina.net/u/195065/blog/193614 目录[-] 一致性 h ...

  9. 一致性Hash算法(KetamaHash)的c#实现

    Consistent Hashing最大限度地抑制了hash键的重新分布.另外要取得比较好的负载均衡的效果,往往在服务器数量比较少的时候需要增加虚拟节点来保证服务器能均匀的分布在圆环上.因为使用一般的 ...

随机推荐

  1. A面&B面

    难难难.道是玄,不遇知音不可谈.遇了知音聊两句,免教那枉费舌尖.难得今天心情不错,反思毕业这五年的种种,有浑噩.迷茫.彷徨.莽撞.执着.困顿.不惧,走到今天迈过了几道坎早已忘却,同时也还在询问自己值不 ...

  2. Servlet会话管理一(URL重写和表单隐藏域)

    会话可以简单的理解为客户端用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器的整个过程称为一个会话.即一个客户端用户和服务器端进行通讯的过程,也是客户端和服务器端之间的数据传 ...

  3. 【Selenium】通过xpath定位svg元素

    SVG 意为可缩放矢量图形(Scalable Vector Graphics)定位svg元素要用xpath的name()函数,比如//svg/line[2],要用//*[name()='svg']/* ...

  4. 模态框MODAL的一些事件捕捉

    下表列出了模态框中要用到事件.这些事件可在函数中当钩子使用. 事件 描述 实例 show.bs.modal 在调用 show 方法后触发. $('#identifier').on('show.bs.m ...

  5. jedis常用API

    一.Redis Client介绍 1.1.简介 Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现了对各类API进行封装调用. Jedis源码工程地址:https://g ...

  6. js之function

    function* function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个  Generator  对象. 你 ...

  7. 安装crf++

    在这里就不提心酸的安装过程了,就把成功安装及部分问题整理出来,以供参考: 安装环境:ubuntu14 1.安装ruby包  sudo apt-get install ruby2.安装zlib包  su ...

  8. 在 Anaconda下解决国内安装tensorflow等下载慢和中断,出错,异常问题的一点思路

    把镜像地址改为清华大学开源软件镜像站,打开 管理员身份打开cmd 输入conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/ ...

  9. 2018.11.04 洛谷P2679 子串(线性dp)

    传送门 为什么前几年的noipnoipnoip总是出这种送分题啊? 这个直接线性dpdpdp不就完了吗? f[i][j][k][0/1]f[i][j][k][0/1]f[i][j][k][0/1]表示 ...

  10. 2018.10.27 loj#2292. 「THUSC 2016」成绩单(区间dp)

    传送门 g[i][j][k][l]g[i][j][k][l]g[i][j][k][l]表示将区间l,rl,rl,r变成最小值等于kkk,最大值等于lll时的花费的最优值. f[i][j]f[i][j] ...