一個簡單的consistent hashing的樣例,非常easy了解。
首先有一個裝置類,定義了機器名和ip:
public class Cache
{
public String name;
public String ipAddress;
}
然後是基本的實作:
public class Shard<T> {
//hash 算法并非保證絕對的平衡,假設 cache 較少的話,對象并不能被均勻的映射到 cache 上,
//是以添加虛拟節點
private TreeMap<Long, T> nodes;
private List<T> shards; //節點碎片
private final int NODE_NUM = 10; // 每一個機器節點關聯的虛拟節點個數
public Shard(List<T> shards) {
this.shards = shards;
init();
}
private void init() {
nodes = new TreeMap<Long, T>();
for (int i = 0; i < shards.size(); i++)
{ // 周遊真實節點
final T shardInfo = shards.get(i);
for (int n = 0; n < NODE_NUM; n++)
{
// 真實節點關聯虛拟節點,真實節點是VALUE;
nodes.put((long) Hash("SHARD-" + i + "-NODE-" + n), shardInfo);
}
System.out.println(shardInfo);
}
}
public T getShardInfo(String key) {
SortedMap<Long, T> tail = nodes.tailMap((long) Hash(key));
if (tail.size() == 0) {
return nodes.get(nodes.firstKey());
}
//找到近期的虛拟節點
return tail.get(tail.firstKey());
}
/**
* 改進的32位FNV算法,高離散
*
* @param string
* 字元串
* @return int值
*/
public static int Hash(String str)
{
final int p = 16777619;
int hash = (int) 2166136261L;
for (byte b : str.getBytes())
hash = (hash ^ b) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
}
到這裡就完了,是不是非常easy,以下來測試下:
public class Test
{
/**
* @param args
*/
public static void main(String[] args)
{
List<Cache> myCaches=new ArrayList<Cache>();
Cache cache1=new Cache();
cache1.name="COMPUTER1";
Cache cache2=new Cache();
cache2.name="COMPUTER2";
myCaches.add(cache1);
myCaches.add(cache2);
Shard<Cache> myShard=new Shard<Cache>(myCaches);
Cache currentCache=myShard.getShardInfo("info1");
System.out.println(currentCache.name);
// for(int i=0;i<20;i++)
// {
// String object=getRandomString(20);//産生20位長度的随機字元串
// Cache currentCache=myShard.getShardInfo(object);
// System.out.println(currentCache.name);
// }
}
public static String getRandomString(int length) { //length表示生成字元串的長度
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
我們有兩台裝置,computer1和computer2,第一次初始化要建構一個2的32次方的環,并往上面放裝置。這個環由改進的FNV算法實作。位置也由hash算法确定。
但我們僅僅有兩台裝置,非常明顯在環上會分布不均勻(這個就不解釋了,網上非常多資料)。于是我們每台裝置添加10個虛拟裝置。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN0LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90zZNhXVU9EeRRkT4FEVkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DOxIzN0MjM5AzMxUDM0EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
最後分布例如以下:
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected]
-2147483648到2147483647之間是不是比較均勻,這是java的,假設是c#的就是0~2的32次方。我們hash計算出KEY值為2049553054,然後順時針找到近期的位置,即為
結果我們定位到了COMPUTER1
最好我們要看看平衡性怎樣:取消上面凝視的代碼,循環20次,得到結果例如以下:
COMPUTER1
COMPUTER2
COMPUTER1
COMPUTER2
COMPUTER1
COMPUTER2
COMPUTER1
COMPUTER1
COMPUTER1
COMPUTER2
COMPUTER2
COMPUTER2
COMPUTER1
COMPUTER2
COMPUTER1
COMPUTER1
COMPUTER1
COMPUTER2
COMPUTER1
COMPUTER2
大家能夠自己取試試,
FNV雜湊演算法是一種高離散性的雜湊演算法,特别适用于哈希很相似的字元串,比如:URL,IP,主機名,檔案名稱等。
下面服務使用了FNV:
1、calc
2、DNS
3、mdbm key/value查詢函數
4、資料庫索引hash
5、主流web查詢/索引引擎
6、高性能email服務
7、基于消息ID查詢函數
8、auti-spam反垃圾郵件過濾器
9、NFS實作(比方freebsd 4.3, linux NFS v4)
10、Cohesia MASS project
11、Ada 95的spellchecker
12、開源x86彙編器:flatassembler user-defined symbol hashtree
13、PowerBASIC
14、PS2、XBOX上的文本資源
15、非加密圖形檔案指紋
16、FRET
17、Symbian DASM
18、VC++ 2005的hash_map實作
19、memcache中的libketama
20、 PHP 5.x
21、twitter中用于改進cache碎片
22、BSD IDE project
23、deliantra game server
24、 Leprechaun
25、IPv6流标簽