HBase 底層原理詳解(深度好文,建議收藏)

HBase簡介

HBase 是一個分佈式的、面向列的開源數據庫。創建在 HDFS 之上。Hbase的名字的來源是 Hadoop database,即 Hadoop 數據庫。HBase 的計算和存儲能力取決於 Hadoop 集羣。node

它介於 NoSql 和 RDBMS 之間,僅能經過主鍵(row key)和主鍵的 range 來檢索數據,僅支持單行事務(可經過 Hive 支持來實現多表 join 等複雜操做)。mysql

HBase中表的特色:sql

  1. 大:一個表能夠有上十億行,上百萬列
  2. 面向列:面向列(族)的存儲和權限控制,列(族)獨立檢索。
  3. 稀疏:對於爲空(null)的列,並不佔用存儲空間,所以,表能夠設計的很是稀疏

HBase底層原理

系統架構

HBase系統架構HBase系統架構

根據這幅圖,解釋下HBase中各個組件數據庫

Client

  1. 包含訪問hbase的接口,Client維護着一些cache來加快對hbase的訪問,好比regione的位置信息.

Zookeeper

HBase可使用內置的Zookeeper,也可使用外置的,在實際生產環境,爲了保持統一性,通常使用外置Zookeeper。數組

Zookeeper在HBase中的做用:緩存

  1. 保證任什麼時候候,集羣中只有一個master
  2. 存貯全部Region的尋址入口
  3. 實時監控Region Server的狀態,將Region server的上線和下線信息實時通知給Master

HMaster

  1. 爲Region server分配region
  2. 負責region server的負載均衡
  3. 發現失效的region server並從新分配其上的region
  4. HDFS上的垃圾文件回收
  5. 處理schema更新請求

HRegion Server

  1. HRegion server維護HMaster分配給它的region,處理對這些region的IO請求
  2. HRegion server負責切分在運行過程當中變得過大的region
    從圖中能夠看到,Client訪問HBase上數據的過程並不須要HMaster參與(尋址訪問Zookeeper和HRegion server,數據讀寫訪問HRegione server)

HMaster僅僅維護者table和HRegion的元數據信息,負載很低。安全

HBase的表數據模型

HBase的表結構HBase的表結構

行鍵 Row Key

與nosql數據庫同樣,row key是用來檢索記錄的主鍵。訪問hbase table中的行,只有三種方式:服務器

  1. 經過單個row key訪問
  2. 經過row key的range
  3. 全表掃描

Row Key 行鍵能夠是任意字符串(最大長度是 64KB,實際應用中長度通常爲 10-100bytes),在hbase內部,row key保存爲字節數組。網絡

Hbase會對錶中的數據按照rowkey排序(字典順序)架構

存儲時,數據按照Row key的字典序(byte order)排序存儲。設計key時,要充分排序存儲這個特性,將常常一塊兒讀取的行存儲放到一塊兒。(位置相關性)。

注意:
字典序對int排序的結果是
1,10,100,11,12,13,14,15,16,17,18,19,2,20,21 … 。要保持整形的天然序,行鍵必須用0做左填充。

行的一次讀寫是原子操做 (不論一次讀寫多少列)。這個設計決策可以使用戶很容易的理解程序在對同一個行進行併發更新操做時的行爲。

列族 Column Family

HBase表中的每一個列,都歸屬於某個列族。列族是表的schema的一部分(而列不是),必須在使用表以前定義

列名都以列族做爲前綴。例如 courses:history ,  courses:math 都屬於 courses 這個列族。

訪問控制、磁盤和內存的使用統計都是在列族層面進行的。 列族越多,在取一行數據時所要參與IO、搜尋的文件就越多,因此,若是沒有必要,不要設置太多的列族。

列 Column

列族下面的具體列,屬於某一個ColumnFamily,相似於在mysql當中建立的具體的列。

時間戳 Timestamp

HBase中經過row和columns肯定的爲一個存貯單元稱爲cell。每一個 cell都保存着同一份數據的多個版本。版本經過時間戳來索引。時間戳的類型是 64位整型。時間戳能夠由hbase(在數據寫入時自動 )賦值,此時時間戳是精確到毫秒的當前系統時間。時間戳也能夠由客戶顯式賦值。若是應用程序要避免數據版本衝突,就必須本身生成具備惟一性的時間戳。每一個 cell中,不一樣版本的數據按照時間倒序排序,即最新的數據排在最前面。

爲了不數據存在過多版本形成的的管理 (包括存貯和索引)負擔,hbase提供了兩種數據版本回收方式:

  1. 保存數據的最後n個版本
  2. 保存最近一段時間內的版本(設置數據的生命週期TTL)。

用戶能夠針對每一個列族進行設置。

單元 Cell

由{row key, column( =<family\> + <label\>), version} 惟一肯定的單元。
cell中的數據是沒有類型的,所有是字節碼形式存貯。

版本號 VersionNum

數據的版本號,每條數據能夠有多個版本號,默認值爲系統時間戳,類型爲Long。

物理存儲

1. 總體結構

HBase 總體結構HBase 總體結構
  1. Table 中的全部行都按照 Row Key 的字典序排列。

  2. Table 在行的方向上分割爲多個 HRegion。

  3. HRegion按大小分割的(默認10G),每一個表一開始只有一 個HRegion,隨着數據不斷插入表,HRegion不斷增大,當增大到一個閥值的時候,HRegion就會等分會兩個新的HRegion。當Table 中的行不斷增多,就會有愈來愈多的 HRegion。

  4. HRegion 是 HBase 中分佈式存儲和負載均衡的最小單元。最小單元就表示不一樣的 HRegion 能夠分佈在不一樣的 HRegion Server 上。但一個 HRegion 是不會拆分到多個 Server 上的。

  5. HRegion 雖然是負載均衡的最小單元,但並非物理存儲的最小單元。
    事實上,HRegion 由一個或者多個 Store 組成,每一個 Store 保存一個 Column Family。
    每一個 Strore 又由一個 MemStore 和0至多個 StoreFile 組成。如上圖。

2. StoreFile 和 HFile 結構

StoreFile以HFile格式保存在HDFS上。

HFile的格式爲:

HFile 格式HFile 格式

首先HFile文件是不定長的,長度固定的只有其中的兩塊:Trailer和FileInfo。正如圖中所示的,Trailer中有指針指向其餘數 據塊的起始點。

File Info中記錄了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。

Data Index和Meta Index塊記錄了每一個Data塊和Meta塊的起始點。

Data Block是HBase I/O的基本單元,爲了提升效率,HRegionServer中有基於LRU的Block Cache機制。每一個Data塊的大小能夠在建立一個Table的時候經過參數指定,大號的Block有利於順序Scan,小號Block利於隨機查詢。 每一個Data塊除了開頭的Magic之外就是一個個KeyValue對拼接而成, Magic內容就是一些隨機數字,目的是防止數據損壞。

HFile裏面的每一個KeyValue對就是一個簡單的byte數組。可是這個byte數組裏麪包含了不少項,而且有固定的結構。咱們來看看裏面的具體結構:

HFile 具體結構HFile 具體結構

開始是兩個固定長度的數值,分別表示Key的長度和Value的長度。緊接着是Key,開始是固定長度的數值,表示RowKey的長度,緊接着是 RowKey,而後是固定長度的數值,表示Family的長度,而後是Family,接着是Qualifier,而後是兩個固定長度的數值,表示Time Stamp和Key Type(Put/Delete)。Value部分沒有這麼複雜的結構,就是純粹的二進制數據了。

HFile分爲六個部分:

  1. Data Block 段–保存表中的數據,這部分能夠被壓縮.

  2. Meta Block 段 (可選的)–保存用戶自定義的kv對,能夠被壓縮。

  3. File Info 段–Hfile的元信息,不被壓縮,用戶也能夠在這一部分添加本身的元信息。

  4. Data Block Index 段–Data Block的索引。每條索引的key是被索引的block的第一條記錄的key。

  5. Meta Block Index段 (可選的)–Meta Block的索引。

  6. Trailer–這一段是定長的。保存了每一段的偏移量,讀取一個HFile時,會首先讀取Trailer,Trailer保存了每一個段的起始位置(段的Magic Number用來作安全check),而後,DataBlock Index會被讀取到內存中,這樣,當檢索某個key時,不須要掃描整個HFile,而只需從內存中找到key所在的block,經過一次磁盤io將整個 block讀取到內存中,再找到須要的key。DataBlock Index採用LRU機制淘汰。

HFile的Data Block,Meta Block一般採用壓縮方式存儲,壓縮以後能夠大大減小網絡IO和磁盤IO,隨之而來的開銷固然是須要花費cpu進行壓縮和解壓縮。
目前HFile的壓縮支持兩種方式:Gzip,Lzo。

3. Memstore與StoreFile

一個 HRegion 由多個 Store 組成,每一個 Store 包含一個列族的全部數據 Store 包括位於內存的 Memstore 和位於硬盤的 StoreFile。

寫操做先寫入 Memstore,當 Memstore 中的數據量達到某個閾值,HRegionServer 啓動 FlashCache 進程寫入 StoreFile,每次寫入造成單獨一個 StoreFile

當 StoreFile 大小超過必定閾值後,會把當前的 HRegion 分割成兩個,並由 HMaster 分配給相應的 HRegion 服務器,實現負載均衡

客戶端檢索數據時,先在memstore找,找不到再找storefile。

4. HLog(WAL log)

WAL 意爲Write ahead log,相似 mysql 中的 binlog,用來 作災難恢復時用,Hlog記錄數據的全部變動,一旦數據修改,就能夠從log中進行恢復。

每一個Region Server維護一個Hlog,而不是每一個Region一個。這樣不一樣region(來自不一樣table)的日誌會混在一塊兒,這樣作的目的是不斷追加單個文件相對於同時寫多個文件而言,能夠減小磁盤尋址次數,所以能夠提升對table的寫性能。帶來的麻煩是,若是一臺region server下線,爲了恢復其上的region,須要將region server上的log進行拆分,而後分發到其它region server上進行恢復。

HLog文件就是一個普通的Hadoop Sequence File:

  1. HLog Sequence File 的Key是HLogKey對象,HLogKey中記錄了寫入數據的歸屬信息,除了table和region名字外,同時還包括 sequence number和timestamp,timestamp是」寫入時間」,sequence number的起始值爲0,或者是最近一次存入文件系統中sequence number。
  2. HLog Sequece File的Value是HBase的KeyValue對象,即對應HFile中的KeyValue,可參見上文描述。

讀寫過程

1. 讀請求過程:

HRegionServer保存着meta表以及表數據,要訪問表數據,首先Client先去訪問zookeeper,從zookeeper裏面獲取meta表所在的位置信息,即找到這個meta表在哪一個HRegionServer上保存着。

接着Client經過剛纔獲取到的HRegionServer的IP來訪問Meta表所在的HRegionServer,從而讀取到Meta,進而獲取到Meta表中存放的元數據。

Client經過元數據中存儲的信息,訪問對應的HRegionServer,而後掃描所在HRegionServer的Memstore和Storefile來查詢數據。

最後HRegionServer把查詢到的數據響應給Client。

查看meta表信息

hbase(main):011:0> scan 'hbase:meta'

2. 寫請求過程:

Client也是先訪問zookeeper,找到Meta表,並獲取Meta表元數據。

肯定當前將要寫入的數據所對應的HRegion和HRegionServer服務器。

Client向該HRegionServer服務器發起寫入數據請求,而後HRegionServer收到請求並響應。

Client先把數據寫入到HLog,以防止數據丟失。

而後將數據寫入到Memstore。

若是HLog和Memstore均寫入成功,則這條數據寫入成功

若是Memstore達到閾值,會把Memstore中的數據flush到Storefile中。

當Storefile愈來愈多,會觸發Compact合併操做,把過多的Storefile合併成一個大的Storefile。

當Storefile愈來愈大,Region也會愈來愈大,達到閾值後,會觸發Split操做,將Region一分爲二。

細節描述:

HBase使用MemStore和StoreFile存儲對錶的更新。
數據在更新時首先寫入Log(WAL log)和內存(MemStore)中,MemStore中的數據是排序的,當MemStore累計到必定閾值時,就會建立一個新的MemStore,而且將老的MemStore添加到flush隊列,由單獨的線程flush到磁盤上,成爲一個StoreFile。於此同時,系統會在zookeeper中記錄一個redo point,表示這個時刻以前的變動已經持久化了。
當系統出現意外時,可能致使內存(MemStore)中的數據丟失,此時使用Log(WAL log)來恢復checkpoint以後的數據。

StoreFile是隻讀的,一旦建立後就不能夠再修改。所以HBase的更新實際上是不斷追加的操做。當一個Store中的StoreFile達到必定的閾值後,就會進行一次合併(minor_compact, major_compact),將對同一個key的修改合併到一塊兒,造成一個大的StoreFile,當StoreFile的大小達到必定閾值後,又會對 StoreFile進行split,等分爲兩個StoreFile。

因爲對錶的更新是不斷追加的,compact時,須要訪問Store中所有的 StoreFile和MemStore,將他們按row key進行合併,因爲StoreFile和MemStore都是通過排序的,而且StoreFile帶有內存中索引,合併的過程仍是比較快。

HRegion管理

HRegion分配

任什麼時候刻,一個HRegion只能分配給一個HRegion Server。HMaster記錄了當前有哪些可用的HRegion Server。以及當前哪些HRegion分配給了哪些HRegion Server,哪些HRegion尚未分配。當須要分配的新的HRegion,而且有一個HRegion Server上有可用空間時,HMaster就給這個HRegion Server發送一個裝載請求,把HRegion分配給這個HRegion Server。HRegion Server獲得請求後,就開始對此HRegion提供服務。

HRegion Server上線

HMaster使用zookeeper來跟蹤HRegion Server狀態。當某個HRegion Server啓動時,會首先在zookeeper上的server目錄下創建表明本身的znode。因爲HMaster訂閱了server目錄上的變動消息,當server目錄下的文件出現新增或刪除操做時,HMaster能夠獲得來自zookeeper的實時通知。所以一旦HRegion Server上線,HMaster能立刻獲得消息。

HRegion Server下線

當HRegion Server下線時,它和zookeeper的會話斷開,zookeeper而自動釋放表明這臺server的文件上的獨佔鎖。HMaster就能夠肯定:

  1. HRegion Server和zookeeper之間的網絡斷開了。
  2. HRegion Server掛了。

不管哪一種狀況,HRegion Server都沒法繼續爲它的HRegion提供服務了,此時HMaster會刪除server目錄下表明這臺HRegion Server的znode數據,並將這臺HRegion Server的HRegion分配給其它還活着的節點。

HMaster工做機制

master上線

master啓動進行如下步驟:

  1. 從zookeeper上獲取惟一一個表明active master的鎖,用來阻止其它HMaster成爲master。
  2. 掃描zookeeper上的server父節點,得到當前可用的HRegion Server列表。
  3. 和每一個HRegion Server通訊,得到當前已分配的HRegion和HRegion Server的對應關係。
  4. 掃描.META.region的集合,計算獲得當前還未分配的HRegion,將他們放入待分配HRegion列表。

master下線

因爲HMaster只維護表和region的元數據,而不參與表數據IO的過程,HMaster下線僅致使全部元數據的修改被凍結(沒法建立刪除表,沒法修改表的schema,沒法進行HRegion的負載均衡,沒法處理HRegion 上下線,沒法進行HRegion的合併,惟一例外的是HRegion的split能夠正常進行,由於只有HRegion Server參與),表的數據讀寫還能夠正常進行。所以HMaster下線短期內對整個HBase集羣沒有影響

從上線過程能夠看到,HMaster保存的信息全是能夠冗餘信息(均可以從系統其它地方收集到或者計算出來)

所以,通常HBase集羣中老是有一個HMaster在提供服務,還有一個以上的‘HMaster’在等待時機搶佔它的位置。

HBase三個重要機制

1. flush機制

1.(hbase.regionserver.global.memstore.size)默認;堆大小的40%
regionServer的全局memstore的大小,超過該大小會觸發flush到磁盤的操做,默認是堆大小的40%,並且regionserver級別的flush會阻塞客戶端讀寫

2.(hbase.hregion.memstore.flush.size)默認:128M
單個region裏memstore的緩存大小,超過那麼整個HRegion就會flush,

3.(hbase.regionserver.optionalcacheflushinterval)默認:1h
內存中的文件在自動刷新以前可以存活的最長時間

4.(hbase.regionserver.global.memstore.size.lower.limit)默認:堆大小 * 0.4 * 0.95
有時候集羣的「寫負載」很是高,寫入量一直超過flush的量,這時,咱們就但願memstore不要超過必定的安全設置。在這種狀況下,寫操做就要被阻塞一直到memstore恢復到一個「可管理」的大小, 這個大小就是默認值是堆大小 * 0.4 * 0.95,也就是當regionserver級別的flush操做發送後,會阻塞客戶端寫,一直阻塞到整個regionserver級別的memstore的大小爲 堆大小 * 0.4 *0.95爲止

5.(hbase.hregion.preclose.flush.size)默認爲:5M
當一個 region 中的 memstore 的大小大於這個值的時候,咱們又觸發了region的 close時,會先運行「pre-flush」操做,清理這個須要關閉的memstore,而後 將這個 region 下線。當一個 region 下線了,咱們沒法再進行任何寫操做。 若是一個 memstore 很大的時候,flush  操做會消耗不少時間。"pre-flush" 操做意味着在 region 下線以前,會先把 memstore 清空。這樣在最終執行 close 操做的時候,flush 操做會很快。

6.(hbase.hstore.compactionThreshold)默認:超過3個
一個store裏面容許存的hfile的個數,超過這個個數會被寫到新的一個hfile裏面 也便是每一個region的每一個列族對應的memstore在flush爲hfile的時候,默認狀況下當超過3個hfile的時候就會對這些文件進行合併重寫爲一個新文件,設置個數越大能夠減小觸發合併的時間,可是每次合併的時間就會越長

2. compact機制

把小的storeFile文件合併成大的HFile文件。
清理過時的數據,包括刪除的數據
將數據的版本號保存爲1個。

split機制

當HRegion達到閾值,會把過大的HRegion一分爲二。
默認一個HFile達到10Gb的時候就會進行切分。

搜索公衆號「五分鐘學大數據」,深刻鑽研大數據技術

相關文章
相關標籤/搜索