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) {// 定义客户端IPString[] 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的哈希值对应到哈希环上// 定义服务器ipString[] 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值// 定义客户端IPString[] 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的哈希值对应到哈希环上// 定义服务器ipString[] 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值// 定义客户端IPString[] 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)); } } }}
欢送搜寻关注自己与敌人共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】