分佈式服務器佈置須要使用到hash算法,設節點有N個,普通的哈希算法:key%N,在遇到節點增長和減小的狀況下,對於單純的邏輯計算hash是沒有問題的,但若是節點集羣提供存儲功能,那效果就不理想了。這時候咱們的想法是在增長節點時之前的節點不受影響,在減小節點時只有與減小節點相關的受影響。那麼咱們不能單純的使用%的方式,有個解決方案是將對象key和服務器節點key抽象出來,間隔排布在一個圓環上面,安裝順時針的方式對象key取的最近的服務器節點。這個方法就是ConsistentHash,下面貼出算法的Java版本: java
import java.util.Collection; import java.util.SortedMap; import java.util.TreeMap; public class ConsistentHash<T> { private final HashFunction hashFunction;// hash算法 private final int numberOfReplicas;// 虛擬節點數目 private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>(); public ConsistentHash(HashFunction hashFunction, int numberOfReplicas, Collection<T> nodes){ // 物理節點 this.hashFunction = hashFunction; this.numberOfReplicas = numberOfReplicas; for (T node : nodes) { add(node); } } public void add(T node) { for (int i = 0; i < numberOfReplicas; i++) { circle.put(hashFunction.hash(node.toString() + i), node); } } public void remove(T node) { for (int i = 0; i < numberOfReplicas; i++) { circle.remove(hashFunction.hash(node.toString() + i)); } } public T get(Object key) {// 關鍵算法 if (circle.isEmpty()) { return null; } // 計算hash值 int hash = hashFunction.hash(key); // 若是不包括這個hash值 if (!circle.containsKey(hash)) { SortedMap<Integer, T> tailMap = circle.tailMap(hash); hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey(); } return circle.get(hash); } }
一種實現方案: node
使用tree管理服務器節點,每一個服務器節點保存一份能索引到它的hash key列表(實際應用以分佈式IP哈希爲居多),訪問的時候計算key的hash值與tree管理的列表進行對比查找,找到對應的映射服務器。tree管理的服務器節點不太好決定的話只能是根據keyhash值和服務器數量進行虛擬節點擴展。 算法