负载均衡-基础-一致性哈希算法及java实现
一致性hash算法,参考:
http://www.blogjava.net/hello-yun/archive/2012/10/10/389289.html
针对这篇文章,加入了自己的理解,在原有的代码上进行了修改。
https://github.com/luoqg/my-code/blob/master/j-algorithm/src/main/java/com/luoq/algorithm/consistencyhash/ConsistencyHash.java
/**
* 一致性hash 的java 实现
* @author luoqiang
* @data 2016/11/08
*/
public class ConsistencyHash { public ConsistencyHash(List<Node> shards){
shards = shards;
init();
} private static class Node{
private String name;
private String ip; public Node(String name, String ip) {
this.name = name;
this.ip = ip;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getIp() {
return ip;
} public void setIp(String ip) {
this.ip = ip;
} @Override
public String toString() {
return "Node{" +
"ip='" + ip + '\'' +
", name='" + name + '\'' +
'}';
}
} private static class Client{
public Client(String name, Long hashCode) {
this.name = name;
this.hashCode = hashCode;
} public Client(String name) {
this.name = name;
} private String name;
private Long hashCode; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Long getHashCode() {
return hashCode;
} public void setHashCode(Long hashCode) {
this.hashCode = hashCode;
}
} private static TreeMap<Long,Node> nodes;//虚拟节点hash值 到 真实主机 的映射 private static TreeMap<Long,Node> treeKey;//客户端hash值 到 真实节点 的映射 private static List<Node> shards = new ArrayList<Node>();//真实主机 private static List<Client> cliends = new ArrayList<Client>();//客户端 private static TreeMap<Long,Client> clientTree;//客户端自己hash 和客户端的映射 private static final int NODE_NUM = 100;//每个机器节点关联的虚拟节点个数 private void init(){
nodes = new TreeMap<Long, Node>();
treeKey = new TreeMap<Long, Node>();
clientTree = new TreeMap<Long, Client>();
for (int i = 0; i < shards.size(); i++) {
final Node shardInfo = shards.get(i);
for (int n = 0; n < NODE_NUM; n++) {
Long key = hash("SHARD-"+shardInfo.name+"-NODE-"+n);
nodes.put(key,shardInfo);
}
}
} /**
* 添加一个真实主机
*/
private void addNode(Node n){
System.out.println("添加主机"+n+"的变化:");
for (int i = 0; i < NODE_NUM; i++) {
Long lg = hash("SHARD-"+n.name+"-NODE-"+i);
SortedMap<Long,Node> head = nodes.headMap(lg);
SortedMap<Long,Node> between;
if(head.size() == 0){
between = treeKey.tailMap(nodes.lastKey());//建立在 最后一个虚拟主机的hash值 不和 客户端的hash值相等。
}else{
Long begin = head.lastKey();
between = treeKey.subMap(begin,lg);
}
nodes.put(lg,n);
for(Iterator<Long> it=between.keySet().iterator();it.hasNext();){
Long lo = it.next();
treeKey.put(lo, nodes.get(lg));
}
}
} /**
* 删除一个真实主机
* @param n
*/
private void deleteNode(Node n){
System.out.println("删除主机"+n+"的变化:");
for (int i = 0; i < NODE_NUM; i++) {
Long virturalHashCode = hash("SHARD-" + n.name + "-NODE-" + i);
SortedMap<Long,Node> tail = nodes.tailMap(virturalHashCode);// 等于和大于 此值 == 顺时针 环形此值后面
SortedMap<Long,Node> head = nodes.headMap(virturalHashCode);// 严格小于 此值(不等于) == 顺时针 环形此值前面
SortedMap<Long, Node> between;
if(head.size() == 0){
between = treeKey.tailMap(nodes.lastKey());
}else{
Long begin = head.lastKey();
Long end = tail.firstKey();
/**
* 方法用于返回此映射的键值从fromKey(包括)到toKey(不包括)的部分视图。
* (如果fromKey和toKey相等,则返回映射为空)返回的映射受此映射支持,
* 因此改变返回映射反映在此映射中,反之亦然。
*/
between = treeKey.subMap(begin,end);//在n节点的第i个虚拟节点的所有key的集合
}
nodes.remove(virturalHashCode);//从nodes中删除n节点的第i个虚拟节点
for(Iterator<Long> it = between.keySet().iterator();it.hasNext();){
Long lo = it.next();
treeKey.put(lo, nodes.get(tail.firstKey()));
}
}
} /**
* 客户端hash值 映射 到 真实主机
*/
private void keyToNode(List<Client> clients){
for (Client client : clients) {
Long hashCode = hash(client.getName());
SortedMap<Long, Node> tail = nodes.tailMap(hashCode); // 沿环的顺时针找到一个虚拟节点
Node node = tail.size() == 0 ? nodes.get(nodes.firstKey()) : nodes.get(tail.firstKey());
treeKey.put(hashCode,node);
client.setHashCode(hashCode);
clientTree.put(hashCode,client);
}
} /**
* 输出客户端 映射到 真实主机
*/
private void printKeyTree(){
for(Iterator<Long> it = treeKey.keySet().iterator();it.hasNext();){
Long lo = it.next();
System.out.println(clientTree.get(lo).name+"(hash:"+lo+")连接到主机->"+treeKey.get(lo));
}
} /**
* MurMurHash算法,是非加密HASH算法,性能很高,
* 比传统的CRC32,MD5,SHA-1
* (这两个算法都是加密HASH算法,复杂度本身就很高,带来的性能上的损害也不可避免)
* 等HASH算法要快很多,而且据说这个算法的碰撞率很低.
* http://murmurhash.googlepages.com/
*/
private Long hash(String key){ ByteBuffer buf = ByteBuffer.wrap(key.getBytes());
int seed = 0x1234ABCD; ByteOrder byteOrder = buf.order();
buf.order(ByteOrder.LITTLE_ENDIAN); long m = 0xc6a4a7935bd1e995L;
int r = 47; long h = seed ^ (buf.remaining() * m); long k;
while (buf.remaining() >= 8) {
k = buf.getLong(); k *= m;
k ^= k >>> r;
k *= m; h ^= k;
h *= m;
} if (buf.remaining() > 0) {
ByteBuffer finish = ByteBuffer.allocate(8).order(
ByteOrder.LITTLE_ENDIAN);
// for big-endian version, do this first:
// finish.position(8-buf.remaining());
finish.put(buf).rewind();
h ^= finish.getLong();
h *= m;
} h ^= h >>> r;
h *= m;
h ^= h >>> r; buf.order(byteOrder);
return h;
} public static void main(String[] args) {
/**
* 客户端的hash值 和 真实主机的100个虚拟节点的hash值
*
* 一起均匀地分布在顺时针由小到大这个环上。(0 - 2^32 )
*
* 具体 客户端 最终 连接到 哪个主机,
*
* 原则是:将客户端hash值,顺时针往后 最近的 虚拟节点hash值。
*
*/
Node s1 = new Node("s1", "192.168.1.1");
Node s2 = new Node("s2", "192.168.1.2");
Node s3 = new Node("s3", "192.168.1.3");
Node s4 = new Node("s4", "192.168.1.4");
Node s5 = new Node("s5", "192.168.1.5");
shards.add(s1);
shards.add(s2);
shards.add(s3);
shards.add(s4);
ConsistencyHash sh = new ConsistencyHash(shards);
System.out.println("添加客户端,一开始有4个主机,分别为s1,s2,s3,s4,每个主机有100个虚拟主机:");
for (int i = 1; i <= 9; i++) {
String name = "10"+i+"客户端";
cliends.add(new Client(name));
}
sh.keyToNode(cliends);
sh.printKeyTree();
sh.deleteNode(s2);
sh.printKeyTree();
sh.addNode(s5);
sh.printKeyTree();
}
}
控制台输出结果:
负载均衡-基础-一致性哈希算法及java实现的更多相关文章
- 一致性哈希算法与Java实现
原文:http://blog.csdn.net/wuhuan_wp/article/details/7010071 一致性哈希算法是分布式系统中常用的算法.比如,一个分布式的存储系统,要将数据存储到具 ...
- Java_一致性哈希算法与Java实现
摘自:http://blog.csdn.net/wuhuan_wp/article/details/7010071 一致性哈希算法是分布式系统中常用的算法.比如,一个分布式的存储系统,要将数据存储到具 ...
- [转载] 应用于负载均衡的一致性哈希及java实现
转载自http://blog.csdn.net/haitao111313/article/details/7537799 这几天看了几遍一致性哈希的文章,但是都没有比较完整的实现,因此试着实现了一下, ...
- 阿里巴巴的分布式应用框架-dubbo负载均衡策略--- 一致哈希算法
dubbo是阿里巴巴公司开发的一个开源分布式应用框架,基于服务的发布者和订阅者,服务者启动服务向注册中心发布自己的服务:消费者(订阅者)启动服务器向注册中心订阅所需要的服务.注册中心将订阅的服务注册列 ...
- 一致性哈希算法(consistent hashing)(转)
原文链接:每天进步一点点——五分钟理解一致性哈希算法(consistent hashing) 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网 ...
- memcached 一致性哈希算法
本文转载自:http://blog.csdn.net/kongqz/article/details/6695417 一.概述 1.我们的memcache客户端使用了一致性hash算法ketama进行数 ...
- 7月目标 socket , 一致性哈希算法 ; mongodb分片; 分布式消息队列; 中间件的使用场景
分布式的基础:一致性哈希 路由算法的一致性hash http://www.jiacheo.org/blog/174 http://www.tuicool.com/articles/vQVbmai ...
- 一致性哈希算法(Consistent Hashing) .
应用场景 这里我先描述一个极其简单的业务场景:用4台Cache服务器缓存所有Object. 那么我将如何把一个Object映射至对应的Cache服务器呢?最简单的方法设置缓存规则:object.has ...
- 五分钟理解一致性哈希算法(consistent hashing)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法 ...
随机推荐
- [LeetCode] Majority Element 求众数
Given an array of size n, find the majority element. The majority element is the element that appear ...
- 编写轻量ajax组件01-对比webform平台上的各种实现方式
前言 Asp.net WebForm 和 Asp.net MVC(简称MVC) 都是基于Asp.net的web开发框架,两者有很大的区别,其中一个就是MVC更加注重http本质,而WebForm试图屏 ...
- 【MySQL】花10分钟阅读下MySQL数据库优化总结
1.花10分钟阅读下MySQL数据库优化总结http://www.kuqin.com2.扩展阅读:数据库三范式http://www.cnblogs.com3.my.ini--->C:\Progr ...
- 上传和设置Mime类型
这两天一直在忙把主页上传的事,幸亏不久前花七块钱买了一年的数据库和虚拟主机,昨天上传了自己的个人主页,发现很多问题要改,因为代码一直没整理就那么放着了,大部分东西都要重新弄,然后把本地数据库的数据迁移 ...
- ASP.NET-DataList控件-DataList嵌套
DataList是ASP.NET的数据控件之一,在使用时要对其进行数据绑定.但是使用过程中难免会出现需要根据已绑定表中的某列数据来作进一步的查询和显示,就需要使用DataList嵌套来解决此类问题. ...
- 给空签名包进行签名以及找不到keystore证书链问题的解决方案
转 http://blog.csdn.net/u011106842/article/details/49683865
- 文件共享锁定数溢出-IWorkspaceEdit.StopEditing
在批量保存Feature至本地mdb的时候,当Feature的数量超过一定的值(该值不确定是不是Access文件的MaxLocksPerFile值,因为当MaxLocksPerFile为9500时,F ...
- Android stdio Apktool源码编译
Android Apktool源码编译 标签(空格分隔): Android Apktool 源码编译 需求 习惯NetBeans调试smali需要用Apktool反编译apk,需要用-d的参数才能生成 ...
- linux的用户与用户组
1.上面这个花花绿绿的图片,来自linxu 下etc/passwd文件. 我们来详细的看下这些都值得是什么东西,这些内容都是用冒号来分割的. 2.etc/shadow 3.对比一下这两个文件的权限,为 ...
- HDU 4006The kth great number(K大数 +小顶堆)
The kth great number Time Limit:1000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64 ...