這幾天看了幾遍一致性雜湊的文章,但是都沒有比較完整的實現,因此試著實現了一下,這裡我就不講一致性雜湊的原理了,網上很多,以一致性雜湊用在負載均衡的例項來說,一致性雜湊就是先把主機ip從小大到全部放到乙個環內,然後客戶端ip來連線的時候,把客戶端ip連線到大小最接近客戶端ip且大於客戶端ip的主機。當然,這裡的ip一般都是要先hash一下的。我的程式執行結果如下:
新增客戶端,一開始有4個主機,分別為s1,s2,s3,s4,每個主機有100個虛擬主機:
101客戶端(hash:-3872430075274208315)連線到主機->s2-192.168.1.2
102客戶端(hash:-6461488502093916753)連線到主機->s1-192.168.1.1
103客戶端(hash:-3272337528088901176)連線到主機->s3-192.168.1.3
104客戶端(hash:7274050343425899995)連線到主機->s2-192.168.1.2
105客戶端(hash:6218187750346216421)連線到主機->s1-192.168.1.1
106客戶端(hash:-8497989778066313989)連線到主機->s2-192.168.1.2
107客戶端(hash:2219601794372203979)連線到主機->s3-192.168.1.3
108客戶端(hash:1903054837754071260)連線到主機->s3-192.168.1.3
109客戶端(hash:-2425484502654523425)連線到主機->s1-192.168.1.1
刪除主機s2-192.168.1.2的變化:
hash(-8497989778066313989)改變到->s4-192.168.1.4
hash(7274050343425899995)改變到->s2-192.168.1.2
hash(-3872430075274208315)改變到->s4-192.168.1.4
hash(7274050343425899995)改變到->s1-192.168.1.1
增加主機s5-192.168.1.5的變化:
hash(1903054837754071260)改變到->s5-192.168.1.5
hash(1903054837754071260)改變到->s5-192.168.1.5
hash(-3272337528088901176)改變到->s5-192.168.1.5
最後的客戶端到主機的對映為:
hash(-8497989778066313989)連線到主機->s4-192.168.1.4
hash(-6461488502093916753)連線到主機->s1-192.168.1.1
hash(-3872430075274208315)連線到主機->s4-192.168.1.4
hash(-3272337528088901176)連線到主機->s5-192.168.1.5
hash(-2425484502654523425)連線到主機->s1-192.168.1.1
hash(1903054837754071260)連線到主機->s5-192.168.1.5
hash(2219601794372203979)連線到主機->s3-192.168.1.3
hash(6218187750346216421)連線到主機->s1-192.168.1.1
hash(7274050343425899995)連線到主機->s1-192.168.1.1
看結果可知:一開始新增到9個客戶端,連線到主機s1,s2,s3,s4的客戶端分別有3,3,3,0個,經過刪除主機s2,新增主機s5,最後9個客戶端分別連線到主機s1,s2,s3,s4,s5的個數為4,0,1,2,2.這裡要說明一下刪除主機s2的情況,hash尾號為9995的客戶端先連線到s2,再連線到s1,為什麼會出現這種情況呢?因為每乙個真實主機有n個虛擬主機,刪除s2卻列印「hash(7274050343425899995)改變到->s2-192.168.1.2」是因為刪除了s2的其中乙個虛擬主機,跳轉到另乙個虛擬主機,但還是在s2上,當然,這裡是列印中間情況,以便了解,真實的環境是刪除了s2後,所有他的虛擬節點都會馬上被刪除,虛擬節點上的連線也會重新連線到另乙個主機的虛擬節點,不會存在這種中間情況。
public class shard
public static void main(string args)
public static void printkeytree()
}private void init()
} //增加乙個主機
private void adds(node s)
//新增乙個虛擬節點進環形結構,lg為虛擬節點的hash值
public void adds(long lg,node s)else
nodes.put(lg, s);
for(iteratorit=between.keyset().iterator();it.hasnext();)else
} }//刪除真實節點是s
public void deletes(node s)
system.out.println("刪除主機"+s+"的變化:");
for(int i=0;itail = nodes.tailmap(hash("shard-" + s.name + "-node-" + i));
sortedmaphead = nodes.headmap(hash("shard-" + s.name + "-node-" + i));
long begin = 0l;
long end = 0l;
sortedmapbetween;
if(head.size()==0)else
for(iteratorit = between.keyset().iterator();it.hasnext();)else
}}
} //對映key到真實節點
public void keytonode(string key)
treekey.put(hash(key), tail.get(tail.firstkey()));
system.out.println(key+"(hash:"+hash(key)+")連線到主機->"+tail.get(tail.firstkey())); }
/*** murmurhash演算法,是非加密hash演算法,效能很高,
* 比傳統的crc32,md5,sha-1(這兩個演算法都是加密hash演算法,複雜度本身就很高,帶來的效能上的損害也不可避免)
* 等hash演算法要快很多,而且據說這個演算法的碰撞率很低.
* */
private static long hash(string key)
if (buf.remaining() > 0)
h ^= h >>> r;
h *= m;
h ^= h >>> r;
buf.order(byteorder);
return h; }
static class node
@override
public string tostring()
}}
參考:
應用負載均衡(輪詢 一致性雜湊)
今天看書看到了應用負載均衡的輪詢與一致性雜湊,其中說到,一致性雜湊可以根據應用請求的url或者url引數將系統的請求 到同一節點,而輪詢是將請求均勻地 到每個伺服器。1 輪詢 1 2 3 優點 到後端應用的請求更加均勻,使得每個伺服器基本均衡 缺點 隨著後端應用伺服器的增加,快取的命中率為下降,這種...
負載均衡與一致性雜湊
一 負載均衡 1.應用場景 假設有三颱快取伺服器s0,s1,s2,同時有三萬張需要快取,最好可以均勻的快取到伺服器上,這樣可以分擔快取的壓力。2.解決方法 對快取下的鍵進行hash計算,雜湊後的值是個整數,再用快取伺服器的數量對這個值進行取模計算,餘數決定資料應該快取到哪台伺服器上。hash 名稱 ...
Nginx負載均衡之一致性雜湊演算法
nginx提供了多種負載均衡演算法,ip hash是其中的一種,但是通常情況下不用他而用第三方的演算法,為什麼?因為ip hash在nginx是第一層 時才有效果,如果在經過nginx前經過了其他 時,會造成獲取的ip不正確。upstream web server常用的一致性雜湊演算法 ngx ht...