自己動手寫緩衝系統 - tmcache
作者:heiyeluren
時間:2008-10-24
部落格:http://blog.csdn.net/heiyeshuwu
【 原理介紹 】
tmcache 大致就是一個類似於Memcache的快取服務器,用過的應該都大致瞭解它的執行過程,為了便於理解,我簡單描述一下。
發送請求過程:
用戶端(PHP/Java/C++) --> 快取服務器 --> 記憶體(共用記憶體)
接收資料過程:
記憶體(共用記憶體) --> 快取服務器 --> 用戶端
大致描述就是:用戶端(任何能夠訪問Socket的用戶端語言或工具) 訪問快取服務器的指定連接埠,進行 儲存/讀取/刪除 資料的操作,快取服務器接收到指令後進行記憶體操作,操作結束後回寫結果給用戶端。所以快取服務器端包含這些模組:Socket通訊、協議解析、資料存放區、資料有效期間控制
以下代碼就是按照這些模組來進行描述的,下面的代碼取自於 tmcache - TieMa(Tiny&Mini) Memory Cache,tmcache 目前支援的功能包括:
* Based memory data storage
* Compatible memcached communication protocol
* Few operation interface, The use of simple
* Support custom port,max_clients,memory use control
tmcache下載(Windows版可直接運行):
Windows版本:http://heiyeluren.googlecode.com/files/tmcache-1.0.0_alpha-win32.zip
Unix/Linux版: http://heiyeluren.googlecode.com/files/tmcache-1.0.0_alpha.tar.gz
【 系統實現 】
一、通訊協定處理模組
這個主要是包含一方面是監聽處理Socket,tmcache裡主要是依靠 init_server_listen() 函數進行監聽操作,同時並發接受串連是程式裡很重要的一塊,可以選擇方式有 select/poll 多路IO的方式,epoll/kqueue 的事件方式,另外還可以使用線程(thread)的方式,tmcache為了相容性和簡單起見,使用了線程的方式。
線程相關核心處理代碼:
- void tm_thread( int serversock, unsigned int max_client ){
- int clientsock, *arg;
- struct sockaddr_in client_addr;
- char currtime[32];
- unsigned clientlen;
- pthread_attr_t thread_attr;
- void *thread_result;
-
- /* Setting pthread attribute */
- pthread_attr_init(&thread_attr);
- pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
- /* Run until cancelled */
- while (1){
- pthread_t thread;
- unsigned int clientlen = sizeof(client_addr);
- memset(currtime, 0, sizeof(currtime));
- getdate(currtime);
- /* Wait for client connection */
- if ((clientsock = accept(serversock, (struct sockaddr *) &client_addr, &clientlen)) < 0){
- die("Failed to accept client connection");
- }
- /* Use thread process new connection */
- arg = &clientsock;
- if (pthread_create(thread, &thread_attr, tm_thread_callback, (void *)arg) != 0){
- die("Create new thread failed");
- }
- }
- /* Destory pthread attribute */
- (void)pthread_attr_destroy(&thread_attr);
- }
協議處理是很核心的,主要是包括儲存資料的 set/add/replace/append,還有提取資料的 get/gets,刪除資料的 delete/remove,擷取狀態 stats/stat 等指令的各種操作,主要操作處理函數是 proc_request(),它負責協議的分析很調用相關的介面來進行處理。
二、資料處理模組
這是資料存放區處理的核心,主要是通過使用雜湊表來儲存資料,使用隊列來記錄資料的儲存順序並且為記憶體不夠用時的處理資料結構,還有使用機率處理演算法來不定期清除到期資料等等。
1. 雜湊表資料存放區
資料是採用雜湊表的儲存方式,儲存速度簡單快速,演算法效率是 O(1),非常適合這種 Key => Value 的儲存場合,核心的雜湊演算法是經典的Times33演算法:
- unsigned tm_hash( const char *str, unsigned table_size ){
- unsigned long hash = 5381;
- int c;
- while (c = *str++) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
- hash = table_size > 0 ? hash % table_size : hash;
- return hash;
- }
同時如果存在一個資料節點衝突的情況,則採用開拉鏈法來解決,一個雜湊儲存節點的資料結構,next程式用於儲存下一個相同雜湊映射結果的值:
- /* Hash data item struct */
- struct tm_hash_entry_t {
- char *key; /* data key string */
- char *data; /* data value string */
- size_t length; /* data length */
- unsigned created; /* data create time (Unix Timestamp) */
- unsigned expired; /* data expire time (Unix Timestamp) */
- struct tm_hash_entry_t *next; /* key conflict link next data node pointer */
- };
2. 資料失效處理
目前主要是兩種方法處理時效,一種是當訪問某個資料節點的時候,如果發現該資料的 expired 欄位已經超過目前時間,那麼將remove該節點。另外一種方法是在進行資料操作的時候,按照機率計算演算法,不週期性清除掉已經到期的演算法,看看機率演算法實現:
- status get_gc_probability(unsigned probaility, unsigned divisor){
- int n;
- struct timeval tv;
- gettimeofday(&tv , (struct timezone *)NULL);
- srand((int)(tv.tv_usec + tv.tv_sec));
- n = 1 + (int)( (float)divisor * rand() / (RAND_MAX+1.0) );
- return (n <= probaility ? TRUE : FALSE);
- }
機率的幾率百分比是通過 probaility 和 divisor 來確定的,預設是 1/100 的幾率,就是一百次操作裡,有一次是可能執行清除到期資料操作的,這樣做便於減輕程式操作的壓力。
3. 記憶體使用量完了的操作
如果tmcache啟動的時候,設定了16MB的記憶體使用量空間,但是最後記憶體不夠用了,那麼就只有通過清除前面插入的快取資料來空出空間來進行儲存新資料,這裡主要是使用了隊列,因為隊列是使用先進先出(First in first out) 的原則的,代碼:
- /* current memory use size exceed MAX_MEM_SIZE, remove last node from queue, remove key from hash table */
- if ( (get_mem_used() + length) > g_max_mem_size ){
- struct tm_queue_node_t *qnode;
- while ( (get_mem_used() + length) > g_max_mem_size ){
- qnode = tm_qremove( g_qlist );
- remove_data( qnode->key );
- }
- }
這樣做的缺點很明顯,就是明明資料沒有失效期,確被刪除了,所以,緩衝工具並不能作為持久化資料一樣的對待方式,必須確保每次查詢快取的時候都進行了相應的儲存操作,因為無法保證資料是還在記憶體中的。
【 結束語 】
基本可以確定 tmcache 是一個非常簡單的緩衝系統,比Memcache差距很遠,更多來說 tmcache 只是一個學習的作品,同時也是做了一些簡單的引導思路,希望對真正要做一個成型複雜穩定的緩衝系統做一個拋磚引玉的簡單參考,所以,tmcache 並不是一個穩定可靠的緩衝系統,也不適合用於生產環境,更適合作為一個學習參考的小東西。
關於其他上面沒有描述的內容,建議閱讀tmcache的代碼來獲得更多相關知識。
:http://code.google.com/p/heiyeluren/downloads