一致性hash算法的实现

来源:互联网 发布:淘宝指纹支付设置没了 编辑:程序博客网 时间:2024/04/20 04:43
一致性hash算法的实现
2014-01-21      0 个评论    来源:只是希望编程越来越有趣  
收藏    我要投稿

1.hashCode的计算,字符串hash算法

有很多hash算法,字符串hash需要达到的两个目标就是冲突要少,也就是分散和考虑到每个字符

参考:字符串hash分析

JDK中使用的累乘因子为31的BKDRHash算法,这是一个经验数字,具有相对比较好的效率和分散。暴雪使用的hash算法主要是针对效率的。

为了尽量发散,使用JDK中HashMap的方法。

    public int hash(String str) {        if(str == null)        return 0;        int h = 0;        h ^= str.hashCode();        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }
2.一致性Hash的思想

假如现在是客户需要服务器来服务,但是有多个服务器,需要选择一个,客户hash后得到一个int型的数h,但是现在只有n个服务器,怎么来选择服务器呢?

传统的取余方法是:h%n 得到一个小于n的数,再对应是那一个服务器就行。

但是这样带来一个很严重的问题,扩展性。当需要添加一个服务器时(或者崩溃),重新计算h%(n+1),其中有些客户端就需要变更服务器。这将会给系统带来很多不必要的损失。

所以一致性Hash就是为了生存在动态服务器内的。

首先求出服务器的哈希值, 并将其配置到0~2^32的圆上。 然后用同样的方法求出客户端的哈希值,并映射到圆上。 然后从数据映射到的位置开始顺时针查找,第一个服务器服务它。 如果超过2^32找不到服务器,就会保存到第一台服务器上。

使用虚拟节点的思想,为每个服务器在圆上分配100~200个点。这样就能抑制分布不均匀, 最大限度地减小服务器增减时的缓存重新分布。

//C为client客户端,S为service服务器public class ConsistentHash {//虚拟节点的个数,默认200private int virtualNum;private long unit;//移动//存储服务器的容器private TreeMap map = new TreeMap<>();public ConsistentHash() {this(200);}public ConsistentHash(int virtualNum) {this.virtualNum = virtualNum;unit = ((long)(Integer.MAX_VALUE/virtualNum)<<1)-2;}//添加服务器结点public void add(S s){int hash = hash(s);//保证分散到Integer的范围内for (int i = 0; i < virtualNum; i++) map.put((int)(hash+i*unit), s);}//删除服务器结点public void remove(S s){int hash = hash(s);//保证分散到Integer的范围内,先转换为int再转换为Integerfor (int i = 0; i < virtualNum; i++) map.remove((Integer)(int)(hash+i*unit));}//获取服务器public S get(C c){if(map.isEmpty())return null;int hash = hash(c);//TreeMap独有的取上和取下方法//ceiling 和 floor (Math中是ceil)Entry entry = map.ceilingEntry(hash);if(entry == null) //空就代表需要回环了return map.firstEntry().getValue();elsereturn entry.getValue();}//再次分散的hash方法private int hash(Object o) {        if(o == null)        return 0;        int h = 0;        h ^= o.hashCode();        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }}
0 0
原创粉丝点击