BeansDB學習筆記

BeansDB是豆瓣的劉洪清大哥寫的一個分佈式存儲系統。關於它的詳細介紹可以參看
http://www.douban.com/note/122507891/ 
同時InfoQ中還有劉洪清大哥的演講視頻及資料:http://www.infoq.com/cn/presentations/lhq-beansdb-design-implementation


BeansDB是一個簡化了的Dynamo系統,適合存儲多個小文件。它的結構個人認爲可以分成下面的部分:一致性協議,同步算法,客戶端代理,底層存儲。


BeansDB實現的是弱一致——豆瓣的用戶上傳照片後一般不會做改動,弱一致就夠了,所以不看它的一致性協議;同樣的原因,不看它的sync流程(沒時間看。。。),不看Proxy部分(只有100多行吧,對異常處理應該不是太完善),個人感覺應該是類似於ClientManager之類的東西,在弱一致性下實現的應該對最終一致的實現沒有多大的啓發。這樣,到頭來對BeansDB的研讀就退化成爲對底層存儲——仍舊是KV數據存儲的研究。


BeansDB的存儲使用了BitCask算法。關於BitCask的詳細介紹可以參看這裏: http://blog.nosqlfan.com/html/955.html 


BitCask可以分爲三部分:存儲在內存中的索引,持久化的數據——包括多個已經被持久化不會改變的數據文件和一個當前將內存中數據內容flush的文件,然後,根據原論文的推薦,還需要一個狀態文件——用於實現內存索引的序列化,使得重啓時可以使用反序列化的功能迅速構建原索引。

BitCask與GDBM的數據存儲方式最大的不同就是它採用日誌型日誌,這樣對數據的刪除可以看做是對數據的插入——諸如GDBM中對文件空白處的處理可以留給以後一起處理,或者不做處理。這種lazy的思想採用以空間換時間的策略,從而可以避免隨機寫帶來的性能上的損耗。


BitCask中內存索引在BeansDB中被實現爲一個HashTree。使用HashTree有以下的幾點好處:
1.HashTree實現簡單,查找高效,而且BeansDB加入了對HashNode的merge和split的伸縮策略,是查找更快速。
2.HashTree的狀態節點類似於二次哈希對dir的擴充,一個數據節點的分裂不會影響其它數據節點的查找
3.HashTree採用分節點存儲使得整個索引存儲形成一種分層結構,這有助於在sync時快速定位到不同的數據節點,同時也避免了對無關節點的sync,節約了時間,值得借鑑。

BeansDB使用了Leader/Follower的線程模型替代以往的生產者消費者模型,也是需要學習的。

對BitCask的實現分別被存放在htree.c——用來實現內存索引HashTree,record.c——用來實現對datafile和hintfile的操作,bitcask.c——用來定義BitCask的基本操作。


下面詳細講述一下BitCask的工作流程,其中用到的組件有:多個older datafile,及其對應的hintfile,還有一個active datafile,以及存儲其中鍵值的cur_tree,最後還有一個tree,用來存儲所有的鍵值,包括older datafile和cur_tree中的所有鍵值。
1.首先需要打開BitCask。
    1.1掃描目錄下的所有older datafile(打開時不存在active datafile)
        1.1.1如果它有對應的hintfile,那麼掃描這個hintfile中的鍵值,加入到tree中
        1.2.1否則掃描datafile生成一棵HTree,根據這棵HTree生成hintfile文件,並把HTree中的鍵值存入tree中
    1.2datafile是按照序號遞增的方式命名的,這樣掃描結束後,我們就會記錄下總共有多少個datafile,並將最後一
個datafile設置成爲active datafile。新建一個HTree——curr_tree,作爲active datafile的內存索引。
2.首先應該介紹查找的流程,直接從tree中查找,如果這個value存在的話,我們可以得到這個value所在的文件名和它在文件中的偏移。這時需要根據這兩個信息分情況查找,具體步驟在bitcask.c的bc_get函數中。
3.然後是插入,刪除和更新操作。這三種操作都被看做是插入操作,放到active datafile中。但是由於我們使用了version,所以需要先在tree中查找這個key對應的version,然後根據特定的version比較原則來判斷下一步到底如何處理。詳細的比較情形可以參見源碼剖析對bitcask.c的剖析。
4.在3中的刪除和更新操作都有可能造成older datafile中一些value值過期無用。爲了節省文件空間,我們需要進行定期的GC,將原來文件中無效的數據清除掉。這通過比較tree和hintfile的HTree來決定。如果hintfile中的鍵值跟tree中的鍵值不同,那麼認定value值被更改——或者被刪除,或者被重新安排到了其它文件的其它地方。如果滿足一定的條件,則根據tree中對value的記錄重新建立datafile文件以及與之對應的hintfile文件。
5.使用完後對BitCask進行close操作,一般需要GC。

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