Kyoto Cabinet 實現原理

       由於最近在做分佈式存儲系統,需要一個小、性能好、靠譜的存儲引擎,我們瞄準了Kyoto Cabinet,希望通過分析源碼能對它進行改造成我們需要的引擎,這一工作落在我身上,於是我花了一星期時間徹底地分析了Kyoto Cabinet源碼,下面將分享下由Kyoto Cabinet源碼分析出的實現原理。

       下面主要分析hashdb和treedb這兩種存儲結構,其他的要麼簡單,要麼類似,就不分析了。

一、hashdb

      hashdb,顧名思義就是哈希表,只是哈希表存放在文件系統而不是內存,複雜度比存在內存大多了,衝突採用鏈表或二叉樹解決。

      大家對哈希表應該都比較熟悉,它由三要素組成:哈希函數,哈希表和衝突解決方法。在無衝突情況下,查找、插入和更新複雜度爲O(1);有衝突情況下的複雜度就視衝突情況來定複雜度了。增加哈希表的桶數,可以減少衝突,但會犧牲空間,所以具體應用時,需要權衡衝突和空間。

     下面分別對上面介紹的三要素是如何hashdb實現的。

(1)哈希函數

      hashdb的哈希函數是採用MurMur算法。具體可以看維基百科的介紹:http://zh.wikipedia.org/wiki/Murmur%E5%93%88%E5%B8%8C,實現函數是hashmurmur,這裏就不貼代碼了。

(2)哈希表

     hashdb的哈希表是文件系統裏一個文件,它的結構由下面圖所示:

                                         
                                                      圖1 哈希表結構
                                        
                                                圖2 bucket section內部結構 
 
                                        
                                               圖3 record section內部結構
 
                                        
                                                圖4  record 內部結構                                    
                                            
         由圖1-圖4可知哈希表是如何在文件系統裏實現了,其中圖1的meta data是哈希表的屬性,圖4的right address只有衝突方法是二叉樹時纔有,鏈表方式不需要。
 
(3)衝突解決方法
          hashdb有兩種衝突方案:鏈表和二叉樹,是可選的。衝突較少時用鏈表好,多時用二叉樹。
 
        下面分析下hashdb裏較難理解或需注意的技術細節。
(1)碎片整理
        a.  首然找到一個free block
        b.   然後將後面的記錄的padding縮小,然後將記錄緊湊地前移,在有限步下完成後,會空出一大塊空間塊
        c.   最後將該大塊空間加入free block pool

(2)文件恢復

        觸發條件:沒有調用close而非正常關閉db。

        恢復思想:遍歷舊hashdb文件裏的record,然後將合法的record插入新hashdb,最後替換舊文件。

(3)非法close數據庫,可能產生數據丟失或數據被認爲合法但不正確

         a. 寫padding size的時,成功寫入第一個字節,寫入第二字節失敗,可能引起不可回收的文件碎片,或認爲該記錄不合法;
         b. 寫key size或value size寫一半,可能引起該記錄的邊界到了第二個記錄上,這就爲什麼恢復DB時,需要順利正確能讀出兩個記錄的第一個記錄才認爲是合法的; 

         c.  寫data寫一半,只會引起數據不正確;
         d. 寫Address寫一半,可通過自動恢復dB恢復,而且數據沒有丟失或不正確。

(4)Free block pool大小超過最大值時,會有free block無法放入Free block pool,導致該free block無法利用,直到碎片整理到它。

(5)事務

        hashdb是採用預寫日誌方式來實現事務的,它的事務隔離級別是可序列化的,事務的最高隔離級別,粒度最大。

        日誌文件格式如下圖所示:

                        
                                              圖5 日誌格式

 

(6)hashdb的鎖粒度是record級別,但又不完全是,它是分配一定數量的鎖放到內存級哈希表,通過哈希的方式去獲取鎖。

 

二、treedb

        treedb的數據結構是採用最小B+樹,B+持久化到磁盤方式是採用hashdb,我感覺該持久化方式是比較偷懶的,性能沒有直接將B+樹保持到磁盤好,因爲通過hashdb會產生較多的磁盤IO,但作者爲彌補這一點,treedb內部實現了一級lru的index page node cache和二級lru的leaf page node cache來減少讀寫磁盤。

         treedb主要內部數據結構由下圖所示: 

         
                                                  圖6  Index node結構
 
          
                                                圖7 Link node結構
 
        

                                               圖8 Leaf node結構

        
                                              圖9 recode結構 

        上面說了,treedb持久化方式是採用hashdb,上圖的index node和leaf node對應hashdb的value,key是node id。

        另外,如果不設autsyn,treedb不會該更新立即寫入磁盤,而是寫在cache裏,後面某個時間再刷到磁盤上。

        treedb的鎖粒度是node,即page。

       treedb裏的lru cache是採用一般的實現方式:哈希表+雙向鏈表。

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