LevelDB簡介

是在抱歉, 最近工作比較忙(比較懶), 文章好久沒更新了. 思索了5分鐘, 還是決定好好寫.
(文章主要內容是自己通過看源碼瞭解的, 寫的不好多多包涵)

背景介紹

LSM算法全稱是Log-Structure Merge Tree, 日誌結構化合並樹.
該算法起源於谷歌發表的 “BigTable”論文, 爲了解決寫多讀少場景(比如消息隊列消息落盤)
levelDB是基於LSM算法實現的一個數據庫. levelDB提供了更好的操作吞吐量, 因爲它通過消去隨機的本地更新操作 , 以文件順序讀寫來實現快速寫入的.(新增/刪除/修改操作都是一條新增記錄)

當然, 隨機讀寫慢的另外一個原因跟硬盤有關, 如果線上機器都使用SSD, 隨機讀寫也會很快…(只要你有錢)
(SSD內部維護了一個映射表, 所以搜索數據很快, 但SSD比較貴, 相對容量低,硬盤壞了數據難以恢復)
(普通硬盤HDD隨機操作慢(尋道時間/延遲時間) , 順序讀寫快 , 便宜, 適合線上大規模部署)
固態硬盤內部結構
普通磁盤結構
一般線上使用的都是普通硬盤, 好了, 對於寫多讀少並且數據量比較大的情況, 技術選型時可以考慮levelDB(博主並不是DBA ,沒有對比過與mongoDB的區別)

levelDB整體數據流圖

能上圖我就不逼逼了
levelDB存儲的是非結構化的數據.
數據寫入流程如下:

  1. 業務代碼調用api將key-value 數據寫入到levelDB中.
  2. levelDB先使用memTable接收(memTable使用ConcurrentSkipListMap實現(自行百度))
  3. 當memTable的數據達到一定的閾值時, memTable指針會指向一塊新的數據, 然後將immutableMemTable指針指向舊的那塊內存. (避免影響客戶端寫入數據)
  4. immuTableMemTable指向的內存數據不爲空時, 就會觸發內存數據寫入到文件中.(Sorted Strings Table文件, 簡稱SSTable文件)
    SSTable文件時分層的, 內存數據寫入到低level文件, 低層ssTable文件達到一定條件時, 會被壓縮到高層level的ssTable文件中.

查詢數據時訪問流程(記住要考): memTable-> immuTableMemTable -> level文件(低層level0 層文件-> level N層文件)
ssTable文件壓縮過程

數據寫入內存:

levelDB數據寫入內存流程圖
流程圖中有幾個關鍵點:
1.判斷level0文件是否達到軟限制是判斷文件數量是否等於8.當達到該文件數量時, 每次數據寫入都會sleep 1ms(每次寫入只sleep一次)
2.“levelDB文件達到最大限制?” 是判斷level0文件數是否達到12 , 如果達到12, 說明文件壓縮已經跟不上數據接收了. 這個時候接收外部數據的線程就被sleep了.

內存數據寫入文件流程

數據寫入文件時並不一定就寫到level0層的文件.會有條件判斷來決定能寫到第幾層的ssTable文件.(交叉: 某塊數據的最小值和最大值, 跟另一塊數據的最小最大值是否有交集, 有交集則稱爲交叉)
內存數據寫入文件java版的選擇內存數據可以寫到哪一層的代碼
流程圖和代碼都是用來描述內存數據應該寫入到哪個level的.(剛寫了一堆廢話, 最終還是決定刪掉一坨文字, 畫個流程圖吧…)
一圖勝千言
按照上圖挑選出將要寫入的level後 , 將數據寫入到對應的level文件中, 並將immutableMemTable引用置空.

ssTable文件滿足壓縮的條件

1.針對level0層, 總文件數/ 4 >=1
2.針對其他level層, 每層總size/每層的限定總size >= 1 則滿足壓縮條件
3.某個文件被查詢一定次數後, 則滿足壓縮條件(每個ssTable文件在創建時會設定查詢次數, 當達到查詢次數時滿足壓縮條件)

滿足壓縮條件並不一定就會被壓縮, 還要比較緊急程度.最緊急的層級會被先壓縮. (下面代碼的score最大則最緊急)
在這裏插入圖片描述

壓縮文件的篩選

在這裏插入圖片描述
(流程圖也很複雜, 心累 , 慢慢理解吧, 我已經儘自己努力講的通俗些了)
要點:

  1. level1及以上的層次, 每次被壓縮後, db會標記一個壓縮點levelPoint, 避免每次壓縮該層次的時候壓縮重複的文件.
  2. 如果是壓縮level0 , 則選擇level0層的交叉文件進行壓縮.
  3. 如果是壓縮level1或者以上level , 則選擇壓縮點levelPoint後的第一個文件.
  4. 選中待壓縮的level的文件後, 就選擇level +1 層的交叉的文件.然後level層文件和level+1層的被選中文件一起壓縮並在level+1層生成新的被壓縮文件.
    下面介紹如何選擇文件(貪心):
    1.(如下圖)如果待壓縮的level層只有一個文件, 但level+1層重疊的文件有兩個, 那麼這三個文件會被選中壓縮, 生成新的文件會放在level+1層(但壓縮後的文件不一定只有一個)(數據從左到右依次增大)
    在這裏插入圖片描述
    2.(如下圖)待壓縮的是level層.如果被選中的是2號文件, 選擇level+1層交叉文件時就會選中4/5兩個文件(這三個文件時必選的了), (貪心時刻)db會嘗試固定level+1文件數情況下, 儘可能多地選擇level層文件. (然而, 如果將1號文件選擇進來了, 那麼3號文件又要被選中了 , 這樣將導致無窮無盡的文件被選中…), 所以這種情況下就只能選擇2/4/5這三個文件進行壓縮了.
    在這裏插入圖片描述
    1. 如果level層選中的是1號文件, 在選擇level +1層時根據交叉選中3和4文件, 這個時候會貪心地儘可能多選level層文件, 就會選到2號, 因爲level層被選文件是1,2, 跟level+1層交叉的文件還是3, 4.level+1層被選的文件不變. 那麼1/2/3/4號文件都會被選中.
      在這裏插入圖片描述

壓縮–簡單易懂

  1. 偶爾會遇到level層只有一個文件並且被選中, 但是level+1層卻沒有文件, 並且level+2層的文件總size < 20M時. 則直接將level層文件移動到level+1層了事…

壓縮–正常壓縮

有點小複雜
將已選中的文件進行壓縮, 相同key時保留最新的key(因爲level和level+1層文件有交叉, 就會有相同key的情況, level層的key比level+1層的key更新) .
按照key進行排序. 寫到文件中, 當文件大小達到一定限制時, 結束該文件並寫到一個新的文件(但是都寫到level+1層)

好了. levelDB的文件寫入到壓縮過程都在這裏了. 寫了2個小時…(如果看到這裏了. 順手點個贊? )
(與mysql不同, levelDB的索引數據是放在level的每個文件的後面的. 就是數據和文件合併在一起的.)

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