分佈式設計與開發 memcached分佈式

memcached是應用最廣的開源cache產品,它本身不提供分佈式的解決方案,我猜想一方面它想盡量保持產品簡單高效,另一方面cache的key-value的特性使得讓memcached分佈式起來比較簡單。memcached的分佈式主要在於客戶端,通過客戶端的路由處理來搭建memcached集羣環境,因此在服務端,memcached集羣環境實際上就是一個個memcached服務器的堆積品,環境的搭建比較簡單。下面從客戶端做路由和服務端集羣環境搭建兩方面來談如何讓memcached分佈式

客戶端做路由

客戶端做路由的原理非常簡單,應用服務器在每次存取某key的value時,通過某種算法把key映射到某臺memcached服務器nodeA上,因此這個key所有操作都在nodeA上,結構圖如下所示:

存儲某個key-value

取某個key-value

因此關鍵在於算法的選擇,最基本的要求就是能讓數據平均到所有服務器上。這自然而然讓我想到了hash算法,spymemcached是一個用得比較廣的java客戶端,它就提供了一種簡單的hash算法,實現類爲ArrayModNodeLocator,從key映射到node的源碼如下:

[java] view plaincopy
  1. public MemcachedNode getPrimary(String k) {  
  2.     return nodes[getServerForKey(k)];  
  3. }  
  4. private int getServerForKey(String key) {  
  5.     int rv=(int)(hashAlg.hash(key) % nodes.length);  
  6.     assert rv >= 0 : "Returned negative key for key " + key;  
  7.     assert rv < nodes.length  
  8.         : "Invalid server number " + rv + " for key " + key;  
  9.     return rv;  
  10. }  

從上面可知它是把所有node放在數組裏,通過hash算法把key映射到某index,然後通過這個index在數組裏取node

再則需要考慮如何容錯,比如當某個node當掉了,如何自動地轉到其他node上,上面的簡單hash路由策略採用的方法是在數據組裏順序向下輪詢node,找第一個工作正常的node即可。

最後要考慮當需要移除node或添加node的時候,如何有效地調整映射關係,這自然又讓我們想到一致性hash算法,關於一致性hash算法就不多說,博文分佈式設計與開發(二)------幾種必須瞭解的分佈式算法 有所涉及,這裏可以看看spymemcached是如何利用這個算法來做路由的,實現類爲KetamaNodeLocator,從key映射到node的源碼如下:

[java] view plaincopy
  1. public MemcachedNode getPrimary(final String k) {  
  2.     MemcachedNode rv=getNodeForKey(hashAlg.hash(k));  
  3.     assert rv != null : "Found no node for key " + k;  
  4.     return rv;  
  5. }  
  6. MemcachedNode getNodeForKey(long hash) {  
  7.     final MemcachedNode rv;  
  8.     if(!ketamaNodes.containsKey(hash)) {  
  9.         // Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5  
  10.         // in a lot of places, so I'm doing this myself.  
  11.         SortedMap<Long, MemcachedNode> tailMap=ketamaNodes.tailMap(hash);  
  12.         if(tailMap.isEmpty()) {  
  13.             hash=ketamaNodes.firstKey();  
  14.         } else {  
  15.             hash=tailMap.firstKey();  
  16.         }  
  17.     }  
  18.     rv=ketamaNodes.get(hash);  
  19.     return rv;  
  20. }  

這段代碼非常清晰,就是通過ketamaNodes這個數據結構按照一致性hash算法把node分區,每次都把映射到一個分區的key對於到負責這個分區的node上。

從上面幾段代碼和圖示,我們大致能弄明白在客戶端如何做路由來讓memcached分佈式,其實在大多數的項目中,以上這些簡單的處理辦法就足夠了

memcached服務端集羣

由上面可知一般的應用中memcached服務端集羣不用做太多工作,部署一堆memcached服務器就可以了,大不了就是要做好監控的工作,但像facebook這樣的大型互聯網應用,並且又是那麼依賴memcached,集羣的工作就很有學問了。今年Qcom的會議上facebook就介紹了是如何通過擴展memcached來應付這麼多數據量的,ppt可見Facebook的擴展Memcached實戰。這個PPT比較抽象,我沒看得太懂,並且facebook也只是蜻蜓點水,沒透露太多的細節,但公司的資深架構師陳大峯同學做了些解析,纔多多少少有點眉目。facebook所有數據的存取都基本上是在memcached上完成,後端的數據庫mysql僅僅只是做持久化的作用,由於數據量巨大,做了類似與mysql的讀寫分離的結構,結構圖如下所示:

其中非常重要的一點,當West的memcached要向East同步數據的時候,它沒有采取memcached之間的同步,而是走MySQL replication,如下圖所示:

這麼做的原因我沒法搞得太清楚,大概是比較信賴MySQL replication的簡單穩定吧,並且像sns這種應用本身就不需要即時一致性,只要最終一致就行了。

另外在數據分佈上是很有講究的,facebook上面有很多很熱的數據,比如LadyGaGa發佈一條消息,將會有千萬的人收到這個消息,如何把LadyGaGa和普通的用戶同等對待就很可能會把這個memcached節點搞垮,甚至訪問衝向後面的數據庫後會把數據搞垮,如下圖所示:

因此就需要一些策略來控制這些熱點數據和熱點訪問,這些策略細節是什麼facebook沒說太清楚,一般說來可以把熱點數據分佈到其他節點,另外對於數據庫可以加鎖控制流量,只有拿到鎖的訪問才能直接訪問數據庫,沒拿到的需要等候和競爭。

另外一個數據分佈的難題是每個用戶可能會有成百上千的好友,而這些好友的數據分佈在成百上千臺的memcached的節點,這樣一個客戶端就需要連接成千上萬的memcached的節點,如下圖所示:

這種問題一般說來可以採取數據重組,把有關聯的數據重組在一起,而不是分佈在n臺機器上。

以上的這些facebook的實踐只能說是走馬觀花地看看了,從我們可以看到一個簡簡單單memcached也能完成這麼多玩樣來,可以猜想到facebook的那些天才工程師們在億萬數據壓力下被逼出了多少創新的設計,這些設計不一定適用於我們,不瞭解情景也沒辦法深究裏面的細節,我們要做的是圍繞我們自己的應用,讓memcached玩出點味道來。

轉自:http://blog.csdn.net/cutesource/article/details/5848253

發佈了83 篇原創文章 · 獲贊 74 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章