bitcask是一個使用Erlang寫的key-value存儲引擎。Bitcask的起源和一個分佈式key-value數據庫 Riak有很密切的關係。在Riak的集羣裏,每一個node使用插件式的存儲引擎,幾乎全部key-value類型的存儲引擎均可以做爲單個node節點的存儲引擎。關於Riak的詳細介紹,有機會後面再講。node
在MySQL和postgresql中,除了保存在disk上的真正的數據庫數據外,還有額外的日誌文件,MySQL中是binlog,pg中是wal 文件。這些日誌文件在備份、還原、創建從庫的時候很是有用。redis
在bitcask中的設計中,相對就比較簡單,日誌文件自己就是數據庫。備份起來也至關簡單,只要把數據目錄的全部文件拷貝一份,在另外一個服務器上重建索引就好了。簡要提及來有下面幾點:sql
如下內容幾乎所有來自bitcask的paper,很易讀,地址爲:basho.com/wp-content/…數據庫
一個bitcask實例就是一個目錄,在設計上強制在任意時刻,只有一個操做系統進程能夠打開bitcask進行寫操做,這個進程就能夠看做是bitcask服務。在任意時刻,這個目錄中只有一個文件是active的,只有這個文件是能夠被寫入的。當這個active的文件大小達到一個臨界值的時候,bitcask就會建立一個新的文件,用來取代當前的active文件。被取代的文件被稱爲老文件,以後永遠都是不可變的,不會再有任何進程往裏面寫入數據。緩存
Active文件寫操做全是append,意味着順序寫入操做不須要disk seeking。每個記錄的格式以下圖:bash
須要注意的是,刪除操做,不過是插入一條value爲某個特殊值的記錄。服務器
這些記錄組合起來,就構成了一個bitcask文件:微信
當append操做完成時,內存裏的一個叫作keydir的數據結構就會被更新。一個keydir就是一個簡單的哈希表,key就是插入數據的key,value指向了插入數據value在文件系統中的具體位置。數據結構
寫入發生時,原來的老數據依然仍是保存在磁盤上,可是新的讀取這個key的請求都會使用keydir上最新的數據。後面會說到,有一個合併進程,最終會刪除不會再使用到的老數據。app
讀取操做是很簡單的,根本不須要操做一次的disk seek。從內存中的keydir查詢key,從這裏知道了value所在的file_id,位置,大小,而後只要調用系統的讀取接口就好了。通常操做系統都還會有本身獨立的disk讀緩存,因此這個操做實際上能夠更快。
如今來講說前面提到的合併操做。其實很簡單,**合併進程遍歷全部的老文件,產生一個只包含當前最新版本數據的文件。**這部分完成的時候,還會產生一個hint file,這個文件本質上和data 文件同樣,只不過他們保存的是value所在文件上的位置,而不是value自己。這個文件能夠加速從目錄文件重建keydir的過程。
當bitcask被一個Erlang進程打開時,它會檢查同一個VM裏,是否是有另外一個Erlang進程在使用這個bitcask,若是是的話,就會和那個進程共享同一個keydir。若是沒有的話,它就會掃描全部的數據文件,構建一個新的keydir,對於那些有hint file的文件,這個構建過程會有顯著提升。
我接觸的第一個key-value存儲引擎是redis。redis的全部數據都是裝在內存的(每隔一段時間會把數據持久化保存到磁盤),這意味着redis的讀寫速度都很是快。可是這有一個限制,那就是單機redis存儲的數據不能大於內存自己。而bitcask的最大限制是內存必須裝得下全部的key,由於bitcask的value是存在磁盤上的。因此相比redis,bitcask的存在乎義不是和redis比速度,而是當你的數據用redis存不下的時候,能夠考慮稍微損失一丟丟速度,試試bitcask。
關注個人微信公衆號