beansdb 分析

(看完這個文章,想對源碼有進一步瞭解,可以到我的git裏面看註釋,或者郵件我討論。附上地址:https://github.com/PhoneLi/beansdb)

在開始看這篇文章之前,建議花幾分鐘看下beansdb的結構分析。

             beansdb的結構分析:http://blog.csdn.net/l402398703/article/details/19371515


簡述:

         1:數據存儲實現。bitcask儲存模型,HashTree 實現數據索引。

         2:協議實現。使用memcached的代碼;修改redis的AE事件異步驅動庫;多worker線程, leader/follower 模式;

(leader/follower模式介紹:http://www.habadog.com/2012/01/11/leader-follower-thread-model

    bitcask模型介紹:http://blog.nosqlfan.com/html/955.html)

    

                                        

(由上圖看出,數據冗餘直接在服務server之間實現。採用3爲冗餘數量。)

--------------------------==============水平分割線=================------------------------------

運行流程:

     1:beansdb.c的main函數啓動;

     2:getopt處理各參數;

     3:一些資源的初始化,例如 getrlimit() ,  item_init();    stats_init();   conn_init();(資源參數很多,建議不要花事件耗在這裏。等看完後面的函數代碼,便會自然理解參數的含義。);

     4:hs_open函數 {

          打開數據目錄(沒有則創建),hstore的初始化。函數結尾調用parallelize函數;
          parallelize函數:啓動一些線程運行scan_thread,每個scan_thread 運行對應的bc_scan。
          bc_scan:加載目錄裏面的 XXX.[data|hint.qlz|htree]文件。(ht_open 加載HTREE_FILE 文件,sanHintFile 加載 hintpath文件)
     };

     5:server_socket:socket的初始化。
     6:loop_run:{
          創建子線程,各線程進入worker_main函數。
          worker_main裏面實現了leader/follwer模式。當有conn的網絡事件,調用driver_machine函數。
          driver_machine:{
               (c-state default is conn_listening;)
               switch:
                    conn_listening: accept client socket ,and new std conn.
                    conn_read:{
                         try_read_network讀取命令,try_read_command處理命令。
                         如果是set命令,process_update_command函數處理,則將狀態轉入conn_nread,從而接受二進制數據;
                         如果是get命令,process_get_command函數處理,則從beansdb中提取key對應的value,並將狀態轉入conn_mwrite,從而發送查詢結果數據;
                         如果是其他的命令,例如delete,version,stats等,由於迴應消息都比較簡單,都是直接調用out_string,跳轉到conn_write狀態。
                    }
                    conn_nread:conn_nread標誌着正在從客戶端讀取二進制數據。這種情況發生在客戶端發送set命令的時候。如果全部二進制數據讀取完成,則將
                                其存儲到beansdb中,並調用  out_string將存儲結果返回給客戶。
                    conn_write. 當服務器需要發送一些簡單的迴應的時候(out_string函數),會將連接的狀態設置爲conn_write. conn_write狀態的處理機制就是
                                首先調用add_iov來將對應的迴應消息添      加到msghdr中的iov中,然後調用transmit函數將未發送的數據發送出去,最後全部數據傳輸完成時,將狀態置爲conn_read。
                    conn_mwrite. 這種情況一般是發生在需要向用戶返回大量的二進制查詢結果時。處理動作也是調用transmit將緩存的數據發送出去。
                    conn_closing. 對應的動作就是清除連接。
          }
     } 

--------------------------==============水平分割線=================------------------------------

主要文件的作用:
htree.c , htree.h      : hash樹的結構
hint.c , hint.h            :hash init。重建hash tree時的根據
bitcask.c , bitcask.h : bitcask 模型。定義BitCask的基本操作
record.c , record.h   : 用來實現對datafile和hintfile的操作

thread.c , ae_epoll.c , ae_kqueue.c , ae_select.c : 作者基於redis的ae代碼修改實現的,thread.c 裏面有部分beansdb的業務。
quicklz.c , quicklz.h qicklz壓縮算法
crc32.c   :  CRC-32校驗

--------------------------==============水平分割線=================------------------------------

總結:

      1:Key-Value 數據庫(CAP理論)
                   分佈式的,伸縮性比較好(P):性能和容量
                   最終一致的(C):可能出現短時間內的數據不一致
                   高可用的(A):部分節點出現故障不影響服務

       beansdb的數據路由和服務端是分開的。這樣的設計,也是一個好的亮點。對於CAP理論,作者根據使用場景,採用最終一致性的實現:多機冗餘(N=3) , 同步寫(W=1), 依次讀(R=1)

       

       2:典型用法

                   圖片文件,小媒體文件(mp3); 大文本字段(通常> 1kb); profile , properties

       

       3:網上有關beansdb源碼分析的文章不多。而且那些文章對應的beansdb的版本不是最新的。

      所以。如果想了解最新版本beansdb(0.6.0)的源碼,可以看我的git。裏面有一定數量的註釋。日後有時間,我會規範整理的。

      我的git項目地址:https://github.com/PhoneLi/beansdb

--------------------------==============水平分割線=================------------------------------

美圖欣賞:


一個bitcast最多有MAX_BUCKET_COUNT個bucket:


hashtree的結構:


舉例一個查找流程:
    hs_get先對key做hash,決定value是在哪個bitcast。然後調用bitcast模塊的bc_get
    bc_get先調用htree模塊的ht_get,找到對應的Item。
    Item中有版本信息ver,位置信息pos。pos是bucket的id和偏移量拼成的一個uint32,於是得到了bucket和offset然後就可以讀出數據了。

 (讀取的行爲默認是隨機選一個節點讀到一個有效的版本就返回。讀不到的話會重試其它節點。 )



線程模型:



Bitcask0~F爲16個桶,每個桶有一個HashTree做索引:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章