面试经常问到的一致hash算法
那到底hash一致算法是什么?
这里以缓存为例,它是保证部署redis集群的时候,可以在不同的机器上准确定位到自己存放的缓存机器。
在什么地方用到?
缓存 ES Handoop 分布式数据库
为什么这些场景用到?
以缓存为例,缓存可以提升数据访问性能,可以缓解数据库压力。但是集群部署的话,会导致不同机器存储的数据很难稳定寻找同一个缓存机器。所以这里就需要一致性hash算法,来确保每个服务器都可以寻找相对应的缓存机器。
hash一致性算法原理

但是这种方式有2个问题:

所以下面我们需要解决这两个问题
提出虚拟节点概念,虚拟节点用其他hash算法实现,使虚拟节点均衡分布。

新增服务器到集群时 也是均衡分布

hash算法有以下几种

存储的结构

这里我们根据需求选择最合适的红黑树实现环存储
好的,上面的理论我们已经清楚了,那下面就用代码来实现一把。
FNV1_32_HASH
public class FNV1_32_HASH {
public 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;
}
}
ConsistencyHash
package com.study.xuy.hash;
import com.study.mike.consistence.hash.FNV1_32_HASH;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class ConsistencyHash {
//物理节点集合 用String 类型表示
private List<String> physicalIps = new ArrayList<String>();
//每个物理ip 对应 实现的虚拟节点数
private Map<String, List<Integer>> physicalIp2Virtuals = new HashMap<>();
//每个物理ip分配的虚拟节点数量 默认100
private int virtualsNum = 100;
//虚拟节点对应的物理节点 相当于环 用TreeMap实现红黑树存储
private SortedMap<Integer, String> sortedMap = new TreeMap<>();
public ConsistencyHash(int virtualsNum) {
super();
this.virtualsNum = virtualsNum;
}
public ConsistencyHash() {
super();
}
/**
* 增加物理ip 到环
*
* @param physicalIp
*/
public void addServer(String physicalIp) {
this.physicalIps.add(physicalIp);
//加入物理ip对应的虚拟集合
ArrayList<Integer> virtuals = new ArrayList<>();
this.physicalIp2Virtuals.put(physicalIp, virtuals);
int count = 0, i = 0;
while (count < this.virtualsNum) {
i++;
int hash = FNV1_32_HASH.getHash(physicalIp+"&&v-"+i);
//解决hash碰撞问题
if (!sortedMap.containsKey(hash)) {
virtuals.add(hash);
this.sortedMap.put(hash, physicalIp);
count ++;
}
System.out.println(count);
}
}
/**
* 获取物理ip
* @param key
* @return
*/
public String getServer(String key){
int hash = FNV1_32_HASH.getHash(key);
//获取大于环上大于key hash的所有虚拟对应 物理ip
SortedMap<Integer, String> integerStringSortedMap = this.sortedMap.tailMap(hash);
if (!integerStringSortedMap.isEmpty()){
return integerStringSortedMap.get(integerStringSortedMap.firstKey());
}else { //没有数据时 取第一个虚拟节点上的 物理ip 顺时针取值
return this.sortedMap.get(sortedMap.firstKey());
}
}
/**
* 移除物理ip
* @param physicalIp
*/
public void remoceServer(String physicalIp){
//获得此物理ip 对应所有虚拟节点
List<Integer> integers = this.physicalIp2Virtuals.get(physicalIp);
if (!integers.isEmpty()) {
for (Integer integer : integers) {
this.sortedMap.remove(integer);
}
}
this.physicalIps.remove(physicalIp);
this.physicalIp2Virtuals.remove(physicalIp);
}
public static void main(String[] args) {
ConsistencyHash consistencyHash = new ConsistencyHash();
consistencyHash.addServer("192.168.0.10");
consistencyHash.addServer("192.168.0.11");
consistencyHash.addServer("192.168.0.12");
System.out.println(1111);
for (int i=0; i <10 ; i++){
System.out.println("ab"+i+"服务器物理ip:"+consistencyHash.getServer("ab"+i));
}
}
}

1349

被折叠的 条评论
为什么被折叠?



