HBase存儲原理探究

我們知道RDBMS底層使用B樹、B+樹的存儲結構,hbase使用LSM樹(log-structured merge tree),對於單表存儲容量,hbase可以依託其平滑的擴展性,滿足RDBMS的瓶頸。他們的設計思想的差距體現在哪裏呢?本文將對其分析:

1.數據結構

  • B+樹

    保持數據穩定有序,自底向上插入(與二叉樹相反),通過最大化每個內部節點的子節點數目來減少樹的高度,不經常發生平衡操作(eg.2-3B樹,可能有2或3個子節點/內部節點,不像自平衡二叉樹經常重新平衡),增加效率。

  • LSM樹

    思想:劃分不同等級的樹。
    eg.二級樹,一份索引數據由2棵樹(內存,可能是B樹、AVL樹等+磁盤,是B樹)組成。數據先插入內存的樹,超閾值,從左至右遍歷,合併內存中葉子節點+磁盤中葉子節點,達到磁盤存儲頁大小,持久化到磁盤+更新父節點對葉子節點指針。磁盤的葉子節點(非葉子節點也被緩存到內存中)合併後,複製一份舊數據,與內存的數據一起順序寫到磁盤。 磁盤樹過大(數據量過大),合併會變慢。
    解決手段:建立層次。eg.內存的樹爲C0,磁盤的樹爲C1,C2,C3,…,Cn,合併順序(C0,C1),(C1,C2)……時間越長,flush越多,產生很多存儲文件,而所有數據按key排序,不用重排

  • 區別:

    使用硬件的方式,特別是磁盤。

    磁盤角度: RDBMS通常都是尋道型(尋道速度每年大概提升5%),由B或B+樹結構決定,log(N)。LSM-Tree是傳輸型(cpu、ram和磁盤空間每18~24個月翻番),在大規模下,傳輸比尋道高效。

  • 優缺點:

    無太多更新時,B+樹工作得很好,以較繁重的優化保證較低的訪問時間。數據被越快越多地放到隨機位置,頁面會變得越碎片化。最終,數據傳入速度可能超過優化進程重寫現存文件的速度。改刪以磁盤尋道速率級別進行,受限於最差的那個磁盤性能。
    LSM-Tree以磁盤傳輸速率級別進行,使用日誌文件和一個內存存儲結構把隨機寫轉換爲順序寫,且讀寫操作獨立,不產生競爭。可更好的擴展大規模數據,保證較一致的插入速率。

2. 底層持久化

  • 架構

    工作流程: 客戶端先連接zookeeper qurom(持有-ROOT-Region的服務器名,訪問擁有它的regionserver),得到持有對應行鍵的.META.表region的服務器名。兩個操作都會被緩存下來,最後根據.META.服務器檢索包含給定行鍵的region所在服務器。

    啓動hbase時,hmaster負責把region分配給每個hregionserver,包括-ROOT-和.META.表。

  • 結合經典的架構圖理解

    hregionserver打開region,創建對應的hregion對象。當hregion被打開,就會爲每個hcolumnfamily創建一個store實例(包含多個storefile實例(對hfile存儲文件的簡單封裝)+一個memstore+一個由hregionserver共享的hlog實例(WAL相關類))。

  • HDFS文件

    flush命令將內存數據寫入存儲文件,否則得等到超過配置的flush大小。

    • hbase文件:①hbase根目錄下;②表目錄下。
    • 表:每個表都有自己的目錄:/hbase/表名/.tableinfo(保存HTableDescriptor序列化後的內容+元數據信息,eg.查表定義時讀取)、/hbase/表名/.tmp(中間數據,eg.表被改動時)
    • region:region因容量大小需split,會創建與之對應的splits目錄(幾秒),創建成功後被移入表目錄下形成兩個新的region。WAL的splitting和region的splitting有明顯區別。
      eg.USER_TEST_TABLE,AAA-AAA11110UC1,1364437081331.68b8ad74920040ba9f39141e908c67.,其中USER_TEST_TABLE,AAA-AAA11110UC1,1364437081331是region前部分,.68b8ad74920040ba9f39141e908c67.是哈希)。
      .META.表的region命名規則和用戶表不同,它使用Jenkins hash對region名稱編碼,可保證其名稱總是合法。
      查看HBase表在HDFS中的文件結構
      HBase 在HDFS 上的目錄樹
  • region切分

當一個region內的存儲文件大於閾值時,該region會split成兩個。regionserver通過在父region內創建切分目錄,準備生成新的region(多線程)——包括新的region目錄+文件引用,完成後把兩新region目錄移到表目錄,然後更新.META.表,指明該region已被切分+子region名稱、位置等。 啓動合併,異步將存儲文件從原始region寫成兩半,原子性的取代引用文件。原始region最終被清除(.META.表+磁盤),master接到split通知,通過負載均衡將新region移動到其他服務器。split的步驟都會通過zookeeper追蹤,允許服務器出錯,其他進程知曉region狀態。

  • 合併

    memstore的flush操作逐步增加磁盤上的文件數目,足夠多時合併成規模更少但更大的文件。

    兩種類型:小合併(minor compaction,將一些小文件合併成更大的文件)和大合併(major compaction,將所有文件合併成一個)。
    ①所有小於最小合併閾值的都會被包含進合併列表(達到單次合併的文件數上限之前)。算法會保證老文件先被合併+確保總能夠選出足夠文件合併。
    ②當memstore被flush到磁盤或執行compact 或 major_compact 或 API調用,會觸發檢查。前兩者在服務端會先檢查是否應該大合併,後兩者會強制大合併。

  • hfile

    一種文件存儲格式的抽象,有v1和v2版,以下圍繞v1講解。

data data meta meta file info data index meta index trailer

一個data包含:magic、keyvalue、keyvalue …. 每個block包含一個magic頭和一系列序列化的keyvalue對象。文件是變長的,file info和trailer是定長的塊。trailer會被寫入文件末尾,包含指向其他block的指針,index block記錄了data和meta block的偏移。block大小通過HColumnDescriptor配置,默認64KB(官方推薦8KB-1MB)。

若主要順序訪問,應設大一點的block(會降低隨機訪問性能,有大量數據需解壓)。 若主要隨機訪問,應設小一點的block(需更多內存保存block index,創建文件變慢,因寫入block後需對壓縮編碼器flush)。
使用壓縮算法,block大小不可控。默認,HDFS的block有64MB,是hfile的1000倍。他們二者沒有關係,HDFS只看到hbase的二進制文件,不知道存儲了什麼。

  • keyvalue
    keyvalue結構-加粗爲key部分

    key length|value length |row length|row|column family length|column family|column qualifier|time stamp|key type| value

    標識key和value的長度,來保證數組可忽略key,直接訪問value。key包含了很多維度的信息,處理小value值時,要儘量讓key很小。選擇一個短的rowkey和column family(1字節的列族名稱,qualifier也要短)來控制二者大小比例。壓縮有助於緩解該問題,包含重複數據壓縮率會比較高,且存儲文件的keyvalue排好序,可讓類似的key靠在一起。

3 . 數據壓縮

  • 支持的壓縮算法

    LZO:速度快,無損算法,線程安全,基於GPL協議(hbase基於Apache協議),故需自行安裝。
    GZIP(GUNzip),相比LZO壓縮率更高但速度更慢。
    SNAPPY,高速壓縮速度和合理壓縮率,比ZLIB快,不兼容其他壓縮格式。

  • 配置

    先確保已安裝壓縮算法庫。建表默認不壓縮,值爲NONE。對已存在的表重設壓縮,需先下線表,修改壓縮算法,最後上線表。

describe 'test'
disable 'test'
alter 'test',{NAME=>'cf1',COMPRESSION=>'SNAPPY'}
describe 'test'
enable 'test'

4. 預寫日誌

爲避免產生過多小文件,regionserver在未收集到足夠數據flush到磁盤前,會一直把它保存在內存中(宕機丟失數據)。hbase採用WAL(write-ahead log)策略: 每次更新前,先寫到日誌中。類似MySQL的bin-log,WAL會記錄數據的所有變更,當內存產生問題,通過日誌恢復到宕機前的狀態。WAL失敗,則認爲整個操作失敗。

  • 流程

    ①客戶端發送更新操作,包裝keyvalue對象,通過RPC發送,到達具有對應region的某個hregionserver;
    ②keyvalue對象到達後,根據行鍵到達對應的hregion,數據先寫入WAL,再存入響應的memstore中;
    ③memstore達到一定大小或過了特定時段後,數據會異步持久化到文件系統。期間數據都存在內存,WAL可保證數據不丟失。
    日誌存在HDFS上,不需要失敗的服務器參與,其他服務器都能打開回放。

  • 日誌回放
    WAL保存各種操作日誌,當服務器出現錯誤進行恢復,其恢復過程稱爲日誌回放。

    • 公用日誌文件:每個regionserver的所有修改操作都寫入同一個HLog的日誌文件內(該設計源自底層文件系統:若每個region單獨保存日誌,同時併發寫入太多文件+日誌切換會降低可擴展性。master必須等待宕機機器的所有日誌都分離完畢纔可重新部署上面的region)
    • 日誌切分:master檢查.logs目錄是否存在日誌。日誌回放更新操作(put、delete、increment,其他操作不關心)。 回放前需按region剝離出來。
    • 切分過程: 讀取日誌,按記錄所屬region分組,將其(更新操作)保持在目標region附近的一個文件中,用於後續恢復。現有版本使用zookeeper,當master確認某日誌就緒,regionserver會進行競爭性選舉,選出一個讀取切分該日誌文件。切分成功後,對應的文件會被移入實際的region目錄中。
  • 日誌一致性
    日誌保證數據安全,最好能長時間處於打開狀態。爲能讀到服務器crash時最後寫入的位置或儘可能接近該位置,需要feature:append支持。

“盡信書不如無書”,堅持瞭解每個開源項目代碼邏輯的實現纔是王道。


參考:
《HBase企業應用開發實戰》


作者: @nanphonfy
轉載出處 : http://blog.csdn.net/nanphonfy


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