memcache proxy之memagent介紹分析

1、和每個memcache server保持多個長連接,效果是減少memcache server保持的連接數量及創建銷燬連接的開銷。不過,memcache本身就支持大併發連接,這個功能也就沒什麼特別的說道。

2、支持memcache的binary協議命令,實現請求的轉發。

3、和memcache一樣,基於libevent的事件驅動來處理IO。

4、支持ketama 的一致性hash算法。

5、支持memcache backup集羣,當memcache集羣有機器掛了,memagent會將get請求轉向memcache backup集羣。這個功能對於cache的穩定性要求高的場景下會有用武之地。

就提供的功能而言,memagent是個很簡單的東西。對於較大的memcache集羣,可以考慮搭一套memagent作爲proxy使用。

實現分析
1、我得到memagent版本是0.5。除去一致性hash算法ketama的代碼,memagent的代碼都在magent.c文件中,代碼總行數2000多行。稍微拿出半個晚上,就能把這份代碼分析得差不多了。

2、memagent像memcache一樣,使用了libevent來驅動狀態及處理。Libevent是個很適合於事件驅動(最典型的就是網絡 IO事件)的場景。像memagent,對於client端的一個請求,它既要處理client端的網絡IO,又要處理server端的網絡IO,還有可 能處理back server的網絡IO,一個流程下來就觸發了多達6、7次的網絡IO事件。

3、memagent是單進程單線程程序,因爲它的工作主要就是接受請求、對請求稍作解析後轉發請求,所以邏輯上較爲簡單,最多的也就是內存拷貝工作,採用單進程單線程也就足夠了。

4、memagent的事件回調函數分別是server_accept、drive_client、 drive_memcached_server、drive_backup_server。這4個回調函數的功能也很明顯,在drive_client、 drive_memcached_server和drive_backup_server也分別涉及到讀寫處理的狀態機機制,這部分代碼涉及到協議解析及 IO處理,代碼細節也是瑣碎繁雜的很。 基本的過程是:

1)memagent解析出client端的數據(主要是命令類型和key),向映射到的memcache server發送數據,如果memcache server連接不上,memagent會向backup集羣(如果設置的話)發送數據。

2)在得到memcache server返回的數據後,memagent還是需要解析,如果這段時間memcache server返回失敗,memagent還會再向backup集羣請求數據。

3)最後,memagent將數據返回給client。

5、對於backup集羣,如果配置了,memagent每次提交操作都會發給backup集羣。在get某個memcache server失敗時會將向backup集羣再請求一遍。

6、對於gets命令,memagent對批量的每個key是單獨和memcache server交互的。這塊我覺得還可優化,可以合併映射到同一個memcache server的key在發往server的一個請求中批量處理。

7、無論是讀client數據還是讀server端數據,memagent都是不知道這個請求中到底有多少字節的數據,所以讀時首先調用 ioctl(fd, FIONREAD, &toread)函數計算出IO buffer中已經收到的網絡字節數據,再對收到的數據做分析確定是否需要繼續read。這個技巧在不知道數據包頭大小的情況下采用的手段。

8、再說一個實現的小細節。對於event_set的回調函數原型,對於不使用的參數可以通過調用宏#define UNUSED(x) ( (void)(x) )來解決gcc在開-Wall時的報錯,我之前看到有文章說是用#pragma也行,不過我沒試成功

一致性hash算法
對於memcache客戶端就Cache key映射到哪個memcache server的選擇算法,最簡單的莫過於根據key計算出的hash值取count(memcache server)的餘數。對於小的memcache集羣或者cache集羣整體掛掉不會對服務產生嚴重影響的情況,這種映射方法就簡單實用。

當然,更好的選擇是一致性hash算法。該算法的效果是減少或增加一個memcache節點,只會影響到整個集羣的1/n的數據。在實現方法上,主要有兩種:

1、將memcache物理節點均勻地分佈在整數範圍構成的hash環。當增加一個節點時,可以將該節點插入環上的兩個節點之間,這樣只會失效 1/2n的數據,但會使hash環變得不均衡;另一種方法是,重新分佈memcache節點在hash環的位置,這樣每個節點的數據都會有些缺失,但缺失 的總和是一個節點的數據範圍。

2、引入虛擬節點的思想,將一個memcache物理節點散落在hash環上的多個虛擬節點,這在均衡性方法效果會更好些。當然,查找的算法複雜度也由O(1)提高到log(N)。Ketama 算法是實現這個思想的第一個也是用得很多的實現,可以從
[url]http://www.last.fm/user/RJ/journal/2007/04/10/rz_libketama_-_a_consistent_hashing_algo_for_memcache_clients [/url]
得到這個算法的多語言版本實現。

Memagent使用的一致性hash算法實現就是Ketama,但Memagent在代碼方面做了簡化修改。Ketama的兩個核心數據結構是:

struct dot {   

unsigned int point;// unsigned int範圍內的某個點

int srvid;//memcache server id

};

struct ketama {

unsigned int numpoints;// 一致性hash的虛擬節點數

struct dot *dot;//一致性hash的虛擬節點列表

int count;//memcache server個數

char **name;// 各memcache server名稱數組

int *weight;// 各memcache server權重,實際都是一樣的

int totalweight;//權重總和

};

struct dot結構表示hash環上一個虛擬節點,struct ketama是算法的全局性數據結構。Ketama 算法涉及到兩個函數是:
int create_ketama(struct ketama *ring, int step) 

Ring由Memagent之前根據memcache server集羣信息構造而來,step取值爲500,函數內部再乘以4,表示一個memcache server在hash環上有2000個虛擬節點。
計算虛擬節點的取值及對應的server id的方法如下:

for (i = 0; i < ring->count; i ++) {   
pct = (float) ring->weight[i] / (float) ring->totalweight;
ks = (int) floorf(pct * step *(float) ring->count); /* divide by 4 for 4 part */
for (k = 0; k < ks; k ++) {
snprintf(temp, 255, "%s-%d", ring->name[i], k);
ketama_md5_digest(temp, digest);
for (h = 0; h < 4; h ++) {
dot[cont].point = ( digest[3+h*4] << 24 ) | ( digest[2+h*4] << 16 )
| ( digest[1+h*4] << 8 ) | digest[h*4];
dot[cont].srvid = i;
cont ++;
}
}
}


最後會對得到的dot列表針對point大小做排序處理,以便get_server時的二分查找。

源碼copy to clipboard打印?
int get_server(struct ketama *, const char *);

int get_server(struct ketama *, const char *);這個函數就是根據key從struct ketama結構中找到對應的memcache server index。Cache key的hash值計算使用的是16位的md5算法。根據key的hash值查找對應在hash環上的位置,採用的是二分查找。
小結
如果你只想要個簡單實用的memcache proxy,memagent是個不錯的選擇。當然,memcache proxy可以做的工作也可以更多,就像另一個memcache proxy實現moxi(http://labs.northscale.com/moxi/)提供了更爲豐富的功能,我會在接下來的文章中繼續介紹moxi。

轉帖自:
[url]http://www.kafka0102.com/2010/01/9.html[/url]
發佈了32 篇原創文章 · 獲贊 0 · 訪問量 8670
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章