1. 程式人生 > 實用技巧 >總結《HBase原理與實踐》第六章

總結《HBase原理與實踐》第六章

目錄

1. HBase寫入流程

1.1 寫入流程的三個階段

1.1.1 客戶端請求階段

1.1.2Region寫入階段

1.1.3MemStore Flush階段

1.1.3.1 Flush觸發條件

1.1.3.2 flush執行流程

1.1.3.3 生成HFile

1.1.3.4MemStore Flush對業務的影響

2. BulkLoad

2.1 核心功能

3. HBase讀取流程

3.1 Client-Server讀取互動邏輯

3.1.1構建Scanner Iterator體系

3.1.2 執行next函式獲取KeyValue並對其進行條件過濾

3.1.3從HFile中讀取待查詢Key

4.深入理解Coprocessor(協處理器)

4.1 Coprocessor的分類

4.2 coprocessor載入


1. HBase寫入流程

1.1 寫入流程的三個階段

從整體架構看,主要是分為三個階段:

  1. 客戶端將使用者的寫入請求進行預處理,並根據叢集元資料定位寫入資料所在的RegionServer,將請求傳送給對應的RegionServer。
  2. 客戶端將使用者的寫入請求進行預處理,並根據叢集元資料定位寫入資料所在的RegionServer,將請求傳送給對應的RegionServer。
  3. MemStore Flush階段:當Region中MemStore容量超過一定閾值,系統會非同步執行f lush操作,將記憶體中的資料寫入檔案,形成HFile。

使用者寫入請求在完成Region MemStore的寫入之後就會返回成功MemStore Flush是一個非同步執行的過程

1.1.1 客戶端請求階段

1. 在提交put請求前,客戶端會根據寫入的表和rowkey在快取的元資料中查詢,如果找到則直接傳送請求到該region所在regionServer上,如果傳送的請求失敗,說明元資料資訊發生變化,需要重新到zookeeper中/hbase-root/meta-region-server節點查詢HBase元資料表所在的RegionServer。然後到該RegionServer在元資料表中查詢rowkey所在的RegionServer以及Region資訊。客戶端接收到返回結果之後會將結果快取到本地,以備後續使用。

怎麼查詢region資訊,之前說過通過反向查詢rowkey,才能才能找到rowkey所在的真正的region。

為什麼? 因為hbase:meta表設計時,只有Region的StartRow。如果正向查詢rowkey所在的region,會找到下一個region上去。而且即使找到下一個region,也無法快速定位該目標region。

2. 客戶端根據rowkey相關元資料資訊將寫入請求傳送給目標RegionServer,Region Server接收到請求之後會解析出具體的Region資訊,查到對應的Region物件,並將資料寫入目標Region的MemStore中。

3. 客戶端將請求序列化,通過rpc將請求傳送到RegionServer上。

1.1.2Region寫入階段

1. 加行鎖,保證行級別的原子性,要麼成功,要麼失敗。

2. 更新key-value的實踐戳為當前系統時間。

3. 欲寫入機制WAL,先將資料寫入日誌。

4. 將資料寫入MemStore中。

5. 釋放鎖。

6. HLog真正同步到HDFS,如果HLog同步失敗,將MemStore中的資料擦除。

7. 結束寫事務。

1.1.3MemStore Flush階段

隨著資料的不斷寫入,會將Memstore中的資料flush寫入檔案形成HFile。

1.1.3.1 Flush觸發條件

  • MemStore級別,當region中任意一個MemStore達到128M(預設),會觸發flush。
  • Region級別,當Region所有的MemStore大小達到上限,會觸發flush。
  • RegionServer級別,當RegionServer中所有的MemStore大小總和超過低水位閾值,強制flush,先刷最大的Region,再刷次大的,如果此時寫入吞吐量依然很高,導致總MemStore大小超過高水位閾值hbase.regionserver.global.memstore.size,RegionServer會阻塞更新並強制執行flush直至總MemStore大小下降到低水位閾值。
  • 一個RegionServer中HLog數量達到上限。
  • HBase定期重新整理MemStore,預設1小時,最近的1小時沒有新資料寫入,觸發flush。
  • 手動flush, 使用者可以對錶 或 region 進行手動刷寫。

1.1.3.2 flush執行流程

為了減少flush過程對讀寫的影響,HBase採用了類似於兩階段提交的方式,將整個flush過程分為三個階段。

  • prepare階段:將concurrentSkipListMap做一個快照,然後在新建一個concurrentSkipListMapj接受新寫入MemStore的資料。
  • flush階段:遍歷所有MemStore,將prepare階段生成的snapshot持久化為臨時檔案,臨時檔案會統一放到目錄.tmp下。這個過程因為涉及磁碟IO操作,相對比較耗時。
  • commit階段:遍歷所有的MemStore,將f lush階段生成的臨時檔案移到指定的ColumnFamily目錄下。

1.1.3.3 生成HFile

MemStore中KV在flush成HFile時首先構建Scanned Block部分,即KV寫進來之後先構建Data Block並依次寫入檔案,在形成Data Block的過程中也會依次構建形成Leaf index Block、Bloom Block並依次寫入檔案。一旦MemStore中所有KV都寫入完成,Scanned Block部分就構建完成。

Non-scanned Block、Load-on-open以及Trailer這三部分是在所有KV資料完成寫入後再追加寫入的。

從上至下寫,沒有發生隨機寫入。

1.1.3.4MemStore Flush對業務的影響

大部分MemStore Flush操作都不會對業務讀寫產生太大影響。系統定期重新整理MemStore、手動執行f lush操作、觸發MemStore級別限制、觸發HLog數量限制以及觸發Region級別限制等,這幾種場景只會阻塞對應Region上的寫請求,且阻塞時間較短。

然而,一旦觸發RegionServer級別限制導致flush,就會對使用者請求產生較大的影響。系統會阻塞所有落在該RegionServer上的寫入操作直至MemStore中資料量降低到配置閾值內。

2. BulkLoad

BulkLoad首先使用MapReduce將待寫入叢集資料轉換為HFile檔案,再直接將這些HFile檔案載入到線上叢集中。

2.1 核心功能

  • HFile生成階段。這個階段會執行一個MapReduce任務,MapReduce的mapper需要自己實現,Reduce由Hbase實現。
  • HFile匯入階段。HFile準備就緒之後,就可以使用工具completebulkload將HFile載入到線上HBase叢集。

如果使用者生成HFile所在的HDFS叢集和HBase所在HDFS叢集是同一個,則MapReduce生成HFile時,能夠保證HFile與目標Region落在同一個機器上,這樣就保證了locality。但是有一些使用者會先通過MapReduce任務在HDFS叢集A上生成HFile,再通過distcp工具將資料拷貝到HDFS叢集B上去。這樣Bulkload到HBase叢集的資料是沒法保證locality的,因此需要跑完Bulkload之後再手動執行major compact,來提升locality。

3. HBase讀取流程

HBase查詢資料遇到的困難:

  1. 一次查詢可能涉及到多個region,多個BlockCache,多個Memstore,多個HFile。
  2. Hbase沒有實現真正的更新和刪除,而是使用多版本和新增‘delete’標籤

3.1 Client-Server讀取互動邏輯

從技術實現的角度來看,get請求也是一種scan請求(最簡單的scan請求,scan的條數為1)。從這個角度講,所有讀取操作都可以認為是一次scan操作。

scan以region為單位

RegionServer接收到請求做了兩件事:

3.1.1構建Scanner Iterator體系

Scanner的核心體系包括三層Scanner:RegionScannerStoreScannerMemStoreScannerStoreFileScanner

一個region有多個storeScanner,一個列簇對應一個storeScanner ,一個StoreScanner由MemStoreScanner和StoreFileScanner構成。一個HFile對應一個StoreFileScanner

注意點:RegionScanner以及StoreScanner 承擔排程任務,負責查詢的是MemStoreScanner和StoreFileScanner

  1. 過濾大部分不符合條件的HFile
  2. 每個scanner seek到startRow
  3. keyValueScanner 合併構建最小堆。按照key從小到大排序。(歸併排序)

3.1.2 執行next函式獲取KeyValue並對其進行條件過濾

經過Scanner體系的構建,KeyValue此時已經可以由小到大依次經過KeyValueScanner獲得,但這些KeyValue是否滿足使用者設定的TimeRange條件、版本號條件以及Filter條件還需要進一步的檢查

總結:第一步只是將Region所有的StoreFile 把不符合的HFile過濾掉,然後將多個檔案按照key從小到大歸併排序。第二部才會將真正符合要求的key過濾出來。如(time,版本,delete標識等)。

過濾HFile的幾種方法:

  1. 根據keyRanger過濾:因為StoreFile中所有KeyValue資料都是有序排列的,所以如果待檢索row範圍[ startrow,stoprow ]與檔案起始key範圍[ firstkey,lastkey]沒有交集,比如stoprow < f irstkey或者startrow > lastkey,就可以過濾掉該StoreFile。
  2. 根據TimeRange過濾:HFile的元資料有時間屬性,如果時間不符合,那麼也會過濾掉HFile。
  3. 根據布隆過濾器過濾:系統根據待檢索的rowkey獲取對應的Bloom Block並載入到記憶體(通常情況下,熱點Bloom Block會常駐記憶體的),再用hash函式對待檢索rowkey進行hash,根據hash後的結果在布隆過濾器資料中進行定址,即可確定待檢索rowkey是否一定不存在於該HFile。

3.1.3從HFile中讀取待查詢Key

1. 根據HFile索引樹定位目標Block,會將HFile的load-on-open和Trailer載入到記憶體,Load-on-open部分有個非常重要的Block——Root Index Block,即索引樹的根節點。HFile索引樹索引在資料量不大的時候只有最上面一層,隨著資料量增大開始分裂為多層,最多三層。

舉例:使用者輸入rowkey為'fb',通過二分查詢找到‘fb’是在‘a’和‘m’,將索引a的索引塊載入到記憶體中,通過二分查詢定位到fb在index 'd'和'h'之間,接下來訪問索引'd'指向的葉子節點。將索引'd'指向的中間節點索引塊載入到記憶體,通過二分查詢定位找到fb在index 'f'和'g'之間,最後需要訪問索引'f'指向的Data Block節點。將索引'f'指向的Data Block載入到記憶體,通過遍歷的方式找到對應KeyValue。所以一次查詢的IO正常為3次。

2. BlockCache中檢索目標Block

Block快取到Block Cache之後會構建一個Map,Map的Key是BlockKey,Value是Block在記憶體中的地址。

3. 從Block中讀取待查詢KeyValueHFile Block由KeyValue(由小到大依次儲存)構成,但這些KeyValue並不是固定長度的,只能遍歷掃描查詢。

4.深入理解Coprocessor(協處理器)

對於一些特殊業務,需要從Hbase中載入大量資料進行求和,求平均等聚合運算,會導致

  • 大量資料傳輸可能會成為瓶頸
  • 客戶端OOM
  • 大量資料傳輸可能將叢集頻寬耗盡,影響叢集讀寫

需要將客戶端計算程式碼遷移到RegionServer上執行。

4.1 Coprocessor的分類

HBase Coprocessor分為兩種:Observer和Endpoint

Observer Coprocessor類似於MySQL中的觸發器。ObserverCoprocessor提供鉤子使使用者程式碼在特定事件發生之前或者之後得到執行。

使用Observer Coprocessor的最典型案例是在執行put或者get等操作之前檢查使用者許可權。例如Ranger整合Hbase。Hbase中的配置檔案如下:

<property>

    <name>hbase.coprocessor.master.classes</name>

   <value>org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor</value>

</property>

<property>

    <name>hbase.coprocessor.region.classes</name>

    <value>org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor</value>

</property>

Endpoint Coprocessor類似於MySQL中的儲存過程。允許將使用者程式碼下推到資料層執行一個典型的例子就是上文提到的計算一張表(設計大量Region)的平均值或者求和,可以使用Endpoint Coprocessor將計算邏輯下推到RegionServer執行。

4.2 coprocessor載入

使用者定義的Coprocessor可以通過兩種方式載入到RegionServer :一種是通過配置檔案靜態載入;一種是動態載入。

1. 靜態載入 ---- 通過修改hbase-site.xml檔案,然後將jar放到hbase的lib檔案中,類似於ranger。

2. 動態載入 ---- 動態載入不需要重啟叢集,通過shell來載入,可以只對某一張表。