1. 程式人生 > >LevelDB的源碼閱讀(一)

LevelDB的源碼閱讀(一)

問題: 重寫 文件 相同 ping 因此 存儲 選擇 leveldb

源碼下載

git clone https://github.com/google/leveldb.git

項目結構

  • db/, 數據庫邏輯
  • doc/, MD文檔
  • helpers/, LevelDB內存版, 通過namespace覆蓋
  • port/, 平臺相關代碼
  • table/, LSM有關的

主要模塊 

Log 文件

客戶端的寫請求會先 append 到 Log 文件,成功後再寫入到 Memtable。如果宕機可以通過 Log 文件來恢復 Memtable。

Memtable 和 Immutable Memtable

內存數據結構,基於跳表。客戶端的讀寫請求都會由 Memtable 處理。 當 Memtable 占用的內存達到一定閾值,重新生成新的 Memtable 處理客戶端請求。原來的 Memtable 轉成 Immutable Memtable,等待歸並到 SST 文件中。

SST 文件

落地到磁盤的存儲文件。SST 分為不同的 level,具體參考文檔。

Manifest 文件

Manifest 記錄不同 level 的 SST 文件,包括每個 SST 文件的 key range、大小等 metadata。

Current 文件

Current 記錄了最新的 Manifest 文件。

LSMtree的核心思想以及問題

在LSM Tree中,所有數據直接寫入memtable並打log, 當memtable足夠大的時候, 變為immemtable, 開始往硬盤挪, 成為SSTable. 你可以用任何有道理的數據結構來表示memtable, immemtable和SSTable. LevelDB選擇用跳躍表(skiplist)實現memtable和immemtable, 用有序行組來實現SSTable。

LSM Tree存在如下問題:

1.適用於插入多而查找少的情況。在查找key時,最壞情況要從memtable讀到immemtable, 再到所有SSTable.

2.SSTable要怎麽有效merge(major compaction)? 如果只有一個SSTable, 我要把新immemtable歸並進去, 就要重寫這個SSTable. 數據有多大, 這個SSTable也會有多大.那麽把SSTable分成若幹份, 每份2MB呢?在最壞的情況下,比如,當前這個immemtable恰好永遠有一個key與任意SSTable中至少一個key重復,就回到剛剛重寫全庫的情況了.

針對以上問題,LevelDB打了兩個增強補丁:

1. 添加BloomFilter, 這樣可以提升全庫掃描的速度, 直接跳過沒有這個key的SSTable.

2. leveled compaction, 把SSTable分成不同的等級. 除等級0以外, 其余各等級的SSTable不會有重復的key.

LevelDB的做法讓每次compaction波及到的範圍是可預期的. 官方文檔的說法是"The compaction picks a file from level L and all overlapping files from the next level L+1". 只按等級延遲合並,沒有任何隨機讀寫操作, 機制上簡單, 而且不需要bookkeeping,可以優雅得釋放被刪除記錄的空間。

需要註意的是:因為下級可能還有相同key的數據,因此,compaction不一定會清空所有deletion maker.

參考文獻:

1.https://zhuanlan.zhihu.com/p/27329248

2.http://masutangu.com/2017/06/leveldb_1/

LevelDB的源碼閱讀(一)