一致性hash算法Consistent Hashing

对于原有hash算法hash%n



so...

1.话不多说直接上代码,原理或详解自行百度即可

import cn.pheker.utils.UtilElapsedTime;
import cn.pheker.utils.UtilLogger;
import cn.pheker.utils.UtilMD5; import java.util.*; /**
* <pre>
* author cn.pheker
* date 2018/3/19 10:20
* email 1176479642@qq.com
* desc 一致性哈希算法
*
* </pre>
*/
public class ConsistentHashing { private static final long MIN_NODE_NUMBER = 0;
private static final int MAX_NODE_NUMBER = Integer.MAX_VALUE;
private static int VIRTUAL_NODE_NUMBER; //真实节点
private List<Node> realNodes = new LinkedList<Node>();
//虚拟节点,hash环
private SortedMap<Integer, VNode> circle = new TreeMap<Integer, VNode>(); private ConsistentHashing(int vnNumber) {
VIRTUAL_NODE_NUMBER = vnNumber;
} public static ConsistentHashing build(int vnNumber) {
return new ConsistentHashing(vnNumber);
} public ConsistentHashing addNode(Map<String,String> ipPorts) {
Set<String> ips = ipPorts.keySet();
Iterator<String> ipite = ips.iterator();
while(ipite.hasNext()){
String ip = ipite.next();
addNode(ip, ipPorts.get(ip));
}
return this;
} public ConsistentHashing addNode(String ip, int port) {
addNode(ip, String.valueOf(port));
return this;
} public ConsistentHashing addNode(String ip, String port) {
Node node = new Node(ip, port);
if (!realNodes.contains(node)) {
realNodes.add(node);
UtilLogger.println("[Node]:"+node.toString()+" Hash:"+node.hashFNV1_32());
//生成VIRTUAL_NODE_NUMBER个虚拟节点
for (int i = 0; i < VIRTUAL_NODE_NUMBER; i++) {
VNode vNode = node.createVNode(i);
circle.put(vNode.hashFNV1_32(), vNode);
UtilLogger.println("\t[VNode]:"+vNode.toString()+" Hash:"+vNode.hashFNV1_32());
}
}
return this;
} public void removeNode(String ip,String port) {
Node node = new Node(ip, port);
for(int i = 0;i<VIRTUAL_NODE_NUMBER;i++) {
VNode vNode = node.createVNode(i);
circle.remove(vNode.hashFNV1_32());
}
circle.remove(node.hashFNV1_32());
} public VNode getNode(String ip, int port) {
return getNode(ip, String.valueOf(port));
} public VNode getNode(String ip, String port) {
Node node = new Node(ip, port);
int hash = node.hashFNV1_32();
if(circle.isEmpty()) return null;
SortedMap<Integer, VNode> tailMap = circle.tailMap(hash);
int hashKey;
if (tailMap.isEmpty()) {
hashKey = circle.firstKey();
}else {
hashKey = tailMap.firstKey();
}//顺时针最近节点
VNode vNode = circle.get(hashKey);
UtilLogger.println(String.format("[%s]:%s ==> [%s]:%s",
node.hashFNV1_32(),node,vNode.hashFNV1_32(),vNode));
return vNode;
} /**
* 第个节点都是一个服务器主机
*/
public class Node {
String ip;
String port; public Node(String ip, String port) {
this.ip = ip;
this.port = port;
} public String getIp() {
return ip;
} public void setIp(String ip) {
this.ip = ip;
} public String getPort() {
return port;
} public void setPort(String port) {
this.port = port;
} public VNode createVNode(int vnNumber) {
return new VNode(ip, port, vnNumber);
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node vNode = (Node) o;
return Objects.equals(ip, vNode.ip) &&
Objects.equals(port, vNode.port);
} @Override
public String toString() {
return ip + ":" + port;
} /**
*使用FNV1_32_HASH算法计算服务器的Hash值,这里不能重写hashCode的方法
*/
public int hashFNV1_32(){
String str = UtilMD5.MD5(this.toString());
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 class VNode extends Node{
int number; public VNode(String ip, String port,int number) {
super(ip, port);
this.number = number;
} public Node toNode() {
return new Node(ip,port);
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
VNode vNode = (VNode) o;
return number == vNode.number;
} @Override
public int hashCode() {
return Objects.hash(number);
} @Override
public String toString() {
return ip + ":" + port+"#"+number;
}
} /**
* 校验hash分布均匀性
* @return
*/
public float check() {
Set<Integer> ks = circle.keySet();
int size = ks.size();
long sum = 0L;
for (int hash : ks) {
sum += hash;
}
double percent = size == MIN_NODE_NUMBER ? MIN_NODE_NUMBER :
(100*2*sum/size)/MAX_NODE_NUMBER;
return Float.valueOf(String.format("%.2f", percent));
} public static void main(String[] args) {
UtilElapsedTime.test(() -> {
ConsistentHashing ch = ConsistentHashing.build(3);
//添加节点
UtilLogger.println("------------添加节点----------------");
ch.addNode("10.96.74.187", 80);
ch.addNode("127.0.0.1", 8080);
ch.addNode("243.15.155.0", 2150);
ch.addNode("243.15.155.1", 2150); UtilLogger.println("------------是否均匀----------------");
UtilLogger.println(ch.check() + "%"); //获取节点
UtilLogger.println("------------获取节点----------------");
ch.getNode("10.96.74.187", 80);
ch.getNode("123.1.122.253", 44);
ch.getNode("234.67.80.219", 3306);
return "耗时计算完成";
});
} }

2.结果

------------添加节点----------------
[Node]:10.96.74.187:80 Hash:1695118842
[VNode]:10.96.74.187:80#0 Hash:1661313686
[VNode]:10.96.74.187:80#1 Hash:1283046442
[VNode]:10.96.74.187:80#2 Hash:564332117
[Node]:127.0.0.1:8080 Hash:678080562
[VNode]:127.0.0.1:8080#0 Hash:1731933288
[VNode]:127.0.0.1:8080#1 Hash:1369405387
[VNode]:127.0.0.1:8080#2 Hash:200594664
[Node]:243.15.155.0:2150 Hash:1175061629
[VNode]:243.15.155.0:2150#0 Hash:134880260
[VNode]:243.15.155.0:2150#1 Hash:1677894747
[VNode]:243.15.155.0:2150#2 Hash:522817245
[Node]:243.15.155.1:2150 Hash:1305999210
[VNode]:243.15.155.1:2150#0 Hash:1193457699
[VNode]:243.15.155.1:2150#1 Hash:279279823
[VNode]:243.15.155.1:2150#2 Hash:2115663065
------------是否均匀----------------
98.0%
------------获取节点----------------
[1695118842]:10.96.74.187:80 ==> [1731933288]:127.0.0.1:8080#0
[601034131]:123.1.122.253:44 ==> [1193457699]:243.15.155.1:2150#0
[508181784]:234.67.80.219:3306 ==> [522817245]:243.15.155.0:2150#2
[23.104187ms] 耗时计算完成 Process finished with exit code 0

3.注意事项

代码中用到了几个工具类UtilMD5,UtilLogger换成自己的即可,UtilElapsedTime用于计算耗时,可以直接去掉。

4.参考链接

对一致性Hash算法,Java代码实现的深入研究

白话解析:一致性哈希算法 consistent hashing

一致性hash算法Consistent Hashing的更多相关文章

  1. 【转】一致性hash算法(consistent hashing)

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在 cache 系统中应用越来越广泛: 1  ...

  2. 一致性hash算法 - consistent hashing

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在 cache 系统中应用越来越广泛: 1 ...

  3. [转]一致性hash算法 - consistent hashing

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在 cache 系统中应用越来越广泛: 1  ...

  4. 一致性Hash算法(分布式算法)

    一致性哈希算法是分布式系统中常用的算法,为什么要用这个算法? 比如:一个分布式存储系统,要将数据存储到具体的节点(服务器)上, 在服务器数量不发生改变的情况下,如果采用普通的hash再对服务器总数量取 ...

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

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

  6. 一致性 hash 算法( consistent hashing )

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在cache 系统中应用越来越广泛: 1 基 ...

  7. 一致性 hash 算法( consistent hashing )(转)

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在 cache系统中应用越来越广泛: 1 基 ...

  8. 一致性 hash 算法( consistent hashing )及java实现

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在cache 系统中应用越来越广泛: 1 基 ...

  9. hash环/consistent hashing一致性哈希算法

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

随机推荐

  1. 初相识|performance_schema全方位介绍

    初相识|performance_schema全方位介绍 |导 语 很久之前,当我还在尝试着系统地学习performance_schema的时候,通过在网上各种搜索资料进行学习,但很遗憾,学习的效果并不 ...

  2. Vuejs——slot内容分发

    ①概述: 简单来说,假如父组件需要在子组件内放一些DOM,那么这些DOM是显示.不显示.在哪个地方显示.如何显示,就是slot分发负责的活. ②默认情况下父组件在子组件内套的内容,是不显示的. 例如代 ...

  3. VeryNginx中文文档

    VeryNginx VeryNginx 是一个功能强大而对人类友好的 Nginx 扩展程序. 提示 v0.2` 版本之后,控制台入口被移动到了 `/verynginx/index.html 中文控制台 ...

  4. luogu P2481 [SDOI2010]代码拍卖会

    luogu 题目中的那个大数一定是若干个1+若干个2+若干个3...+若干个9组成的,显然可以转化成9个\(\underbrace {111...1}_{a_i个1}(0\le a_1\le a_2\ ...

  5. springmvc中的数据传递

    import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; impo ...

  6. 使用git配置ssh的文章推荐

    https://blog.51cto.com/sgk2011/1925922 https://www.cnblogs.com/superGG1990/p/6844952.html https://bl ...

  7. 阅读脚本控制pwm代码

    在现有的项目上通过SoC的EHRPWM3B管脚产生PWM脉冲做为摄像头的framsync信号. datasheet描述: PWMSS:PWM Subsystem Resources eHRPWM: E ...

  8. RubyGems 库发现了后门版本的网站开发工具 bootstrap-sass

    安全研究人员在官方的 RubyGems 库发现了后门版本的网站开发工具 bootstrap-sass.该工具的下载量高达 2800 万次,但这并不意味着下载的所有版本都存在后门,受影响的版本是 v3. ...

  9. 脚本_查看当前系统每个IP的连接数

    #!bin/bash#作者:liusingbon#功能:查看当前系统每个IP的连接数netstat -n | awk '/^tcp/ {print $5}'| awk -F: '{print $1}' ...

  10. Nagios-Nagios-Nagios系统监控(centos7部署源码)

    一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...