共计 3669 个字符,预计需要花费 10 分钟才能阅读完成。
Hash 算法相干内容
⾸先有⼀条直线,直线结尾和结尾别离定为为 1 和 2 的 32 次⽅减 1,这相当于⼀个地址,对于这样⼀条
线,弯过去形成⼀个圆环造成闭环,这样的⼀个圆环称为 hash 环。咱们把服务器的 ip 或者主机名求
hash 值而后对应到 hash 环上,那么针对客户端⽤户,也依据它的 ip 进⾏ hash 求值,对应到环上某个位
置,而后如何确定⼀个客户端路由到哪个服务器解决呢?依照顺时针⽅向找最近的服务器节点
如果将服务器 3 下线,服务器 3 下线后,原来路由到 3 的客户端从新路由到服务器 4,对于其余客户端没有
影响只是这⼀⼩局部受影响(申请的迁徙达到了最⼩,这样的算法对分布式集群来说⾮常适合的,防止
了⼤量申请迁徙)
减少服务器 5 之后,原来路由到 3 的局部客户端路由到新增服务器 5 上,对于其余客户端没有影响只是这
⼀⼩局部受影响(申请的迁徙达到了最⼩,这样的算法对分布式集群来说⾮常适合的,防止了⼤量申请
迁徙)
1)如前所述,每⼀台服务器负责⼀段,⼀致性哈希算法对于节点的增减都只需重定位环空间中的⼀⼩
局部数据,具备较好的容错性和可扩展性。
然而,⼀致性哈希算法在服务节点太少时,容易因为节点分部不平均⽽造成数据歪斜问题。例如零碎中
只有两台服务器,其环散布如下,节点 2 只能负责⾮常⼩的⼀段,⼤量的客户端
申请落在了节点 1 上,这就是数据(申请)歪斜问题
2)为了解决这种数据歪斜问题,⼀致性哈希算法引⼊了虚构节点机制,即对每⼀个服务节点计算多个
哈希,每个计算结果地位都搁置⼀个此服务节点,称为虚构节点。
具体做法能够在服务器 ip 或主机名的后⾯减少编号来实现。⽐如,能够为每台服务器计算三个虚构节
点,于是能够别离计算“节点 1 的 ip#1”、“节点 1 的 ip#2”、“节点 1 的 ip#3”、“节点 2 的 ip#1”、“节点 2 的
ip#2”、“节点 2 的 ip#3”的哈希值,于是造成六个虚构节点,当客户端被路由到虚构节点的时候其实是被
路由到该虚构节点所对应的实在节点
一致性 Hash 算法的代码
一般 hash 算法
/**
* 一般 Hash 算法实现
*/
public class GeneralHash {public static void main(String[] args) {
// 定义客户端 IP
String[] clients = new String[]
{"10.78.12.3","113.25.63.1","126.12.3.8"};
// 定义服务器数量
int serverCount = 5;// (编号对应 0,1,2)
// hash(ip)%node_counts=index
// 依据 index 锁定应该路由到的 tomcat 服务器
for(String client: clients) {int hash = Math.abs(client.hashCode());
int index = hash%serverCount;
System.out.println("客户端:" + client + "被路由到服务器编号为:" + index);
}
}
}
一致性 hash 算法不带虚构节点
public class ConsistentHashNoVirtual {public static void main(String[] args) {
//step1 初始化:把服务器节点 IP 的哈希值对应到哈希环上
// 定义服务器 ip
String[] tomcatServers = new String[]
{"123.111.0.0","123.101.3.1","111.20.35.2","123.98.26.3"};
SortedMap<Integer,String> hashServerMap = new TreeMap<>();
for(String tomcatServer: tomcatServers) {
// 求出每⼀个 ip 的 hash 值,对应到 hash 环上,存储 hash 值与 ip 的对应关系
int serverHash = Math.abs(tomcatServer.hashCode());
// 存储 hash 值与 ip 的对应关系
hashServerMap.put(serverHash,tomcatServer);
}
//step2 针对客户端 IP 求出 hash 值
// 定义客户端 IP
String[] clients = new String[]
{"10.78.12.3","113.25.63.1","126.12.3.8"};
for(String client : clients) {int clientHash = Math.abs(client.hashCode());
//step3 针对客户端, 找到可能解决以后客户端申请的服务器(哈希环上顺时针最
近)// 依据客户端 ip 的哈希值去找出哪⼀个服务器节点可能解决()SortedMap<Integer, String> integerStringSortedMap =
hashServerMap.tailMap(clientHash);
if(integerStringSortedMap.isEmpty()) {
// 取哈希环上的顺时针第⼀台服务器
Integer firstKey = hashServerMap.firstKey();
System.out.println("==========>>>> 客户端:" + client + " 被
路由到服务器:" + hashServerMap.get(firstKey));
}else{Integer firstKey = integerStringSortedMap.firstKey();
System.out.println("==========>>>> 客户端:" + client + " 被
路由到服务器:" + hashServerMap.get(firstKey));
}
}
}
}
一致性 hash 算法带虚构节点
public class ConsistentHashWithVirtual {public static void main(String[] args) {
//step1 初始化:把服务器节点 IP 的哈希值对应到哈希环上
// 定义服务器 ip
String[] tomcatServers = new String[]
{"123.111.0.0","123.101.3.1","111.20.35.2","123.98.26.3"};
SortedMap<Integer,String> hashServerMap = new TreeMap<>();
// 定义针对每个实在服务器虚构进去⼏个节点
int virtaulCount = 3;
for(String tomcatServer: tomcatServers) {
// 求出每⼀个 ip 的 hash 值,对应到 hash 环上,存储 hash 值与 ip 的对应关系
int serverHash = Math.abs(tomcatServer.hashCode());
// 存储 hash 值与 ip 的对应关系
hashServerMap.put(serverHash,tomcatServer);
// 解决虚构节点
for(int i = 0; i < virtaulCount; i++) {int virtualHash = Math.abs((tomcatServer + "#" + i).hashCode());
hashServerMap.put(virtualHash,"---- 由虚构节点"+ i + " 映射过
来的申请:"+ tomcatServer);
}
}
//step2 针对客户端 IP 求出 hash 值
// 定义客户端 IP
String[] clients = new String[]
{"10.78.12.3","113.25.63.1","126.12.3.8"};
for(String client : clients) {int clientHash = Math.abs(client.hashCode());
//step3 针对客户端, 找到可能解决以后客户端申请的服务器(哈希环上顺时针最
近)// 依据客户端 ip 的哈希值去找出哪⼀个服务器节点可能解决()SortedMap<Integer, String> integerStringSortedMap =
hashServerMap.tailMap(clientHash);
if(integerStringSortedMap.isEmpty()) {
// 取哈希环上的顺时针第⼀台服务器
Integer firstKey = hashServerMap.firstKey();
System.out.println("==========>>>> 客户端:" + client + " 被
路由到服务器:" + hashServerMap.get(firstKey));
}else{Integer firstKey = integerStringSortedMap.firstKey();
System.out.println("==========>>>> 客户端:" + client + " 被
路由到服务器:" + hashServerMap.get(firstKey));
}
}
}
}
欢送搜寻关注自己与敌人共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】