Apache HBase MTTR 優化實踐

華為雲官方部落格發表於2022-03-26

HBase介紹

HBase是Hadoop Database的簡稱,是建立在Hadoop檔案系統之上的分散式面向列的資料庫,它具有高可靠、高效能、面向列和可伸縮的特性,提供快速隨機訪問海量資料能力。

HBase採用Master/Slave架構,由HMaster節點、RegionServer節點、ZooKeeper叢集組成,底層資料儲存在HDFS上。

整體架構如圖所示:

HMaster主要負責:

  • 在HA模式下,包含主用Master和備用Master。
  • 主用Master:負責HBase中RegionServer的管理,包括表的增刪改查;RegionServer的負載均衡,Region分佈調整;Region分裂以及分裂後的Region分配;RegionServer失效後的Region遷移等。
  • 備用Master:當主用Master故障時,備用Master將取代主用Master對外提供服務。故障恢復後,原主用Master降為備用。

RegionServer主要負責:

  • 存放和管理本地HRegion。
  • RegionServer負責提供表資料讀寫等服務,是HBase的資料處理和計算單元,直接與Client互動。
  • RegionServer一般與HDFS叢集的DataNode部署在一起,實現資料的儲存功能。讀寫HDFS,管理Table中的資料。

ZooKeeper叢集主要負責:

  • 存放整個 HBase叢集的後設資料以及叢集的狀態資訊。
  • 實現HMaster主從節點的Failover。

HDFS叢集主要負責:

  • HDFS為HBase提供高可靠的檔案儲存服務,HBase的資料全部儲存在HDFS中。

結構說明:

Store

  • 一個Region由一個或多個Store組成,每個Store對應圖中的一個Column Family。

MemStore

  • 一個Store包含一個MemStore,MemStore快取客戶端向Region插入的資料,當RegionServer中的MemStore大小達到配置的容量上限時,RegionServer會將MemStore中的資料“flush”到HDFS中。

StoreFile

  • MemStore的資料flush到HDFS後成為StoreFile,隨著資料的插入,一個Store會產生多個StoreFile,當StoreFile的個數達到配置的閾值時,RegionServer會將多個StoreFile合併為一個大的StoreFile。

HFile

  • HFile定義了StoreFile在檔案系統中的儲存格式,它是當前HBase系統中StoreFile的具體實現。

HLog(WAL)

  • HLog日誌保證了當RegionServer故障的情況下使用者寫入的資料不丟失,RegionServer的多個Region共享一個相同的HLog。

HBase提供兩種API來寫入資料。

  • Put:資料直接傳送給RegionServer。
  • BulkLoad:直接將HFile載入到表儲存路徑。

HBase為了保證資料可靠性,使用WAL(Write Ahead Log)來保證資料可靠性。它是HDFS上的一個檔案,記錄HBase中資料的所有更改。所有的寫操作都會先保證將資料寫入這個檔案後,才會真正更新MemStore,最後寫入HFile中。如果寫WAL檔案失敗,則操作會失敗。在正常情況下,不需要讀取WAL檔案,因為資料會從MemStore中持久化為HFile檔案。但是如果RegionServer在持久化MemStore之前崩潰或者不可用,系統仍然可以從WAL檔案中讀取資料,回放所有操作,從而保證資料不丟失。

寫入流程如圖所示:

預設情況下RegionServer上管理的所有HRegion共享同一個WAL檔案。WAL檔案中每個記錄都包括相關Region的資訊。當開啟Region時,需要回放WAL檔案中屬於該Region的記錄資訊。因此,WAL檔案中的記錄資訊必須按Region進行分組,以便可以回放特定Region的記錄。按Region分組WAL的過程稱為WAL Split。

WAL Split由HMaster在叢集啟動時完成或者在RegionServer關閉時由ServershutdownHandler完成。在給定的Region再次可用之前,需要恢復和回放所有的WAL檔案。因此在資料恢復之前,對應的Region無法對外服務。

HBase啟動時,Region分配簡要分配流程如下:

  • HMaster啟動時初始化AssignmentManager。
  • AssignmentManager通過hbase:meta表檢視當前Region分配資訊。
  • 如果Region分配依然有效(Region所在RegionServer依然線上),則保留分配資訊。
  • 如果Region分配無效,呼叫LoadBalancer來進行重分配。
  • 分配完成後更新hbase:meta表。

本文主要關注叢集重新啟動和恢復相關內容,著重描述相關優化,減少HBase恢復時長。

RegionServer故障恢復流程

當HMaster檢測到故障時,會觸發SCP(Server Crash Procedure)流程。SCP流程包括以下主要步驟:

  • HMaster建立WAL Split任務,用於對屬於崩潰RegionServer上Region進行記錄分組。
  • 將原屬於崩潰RegionServer上Region進行重分配,分配給正常RegionServer。
  • 正常RegionServer執行Region上線操作,對需要恢復資料進行回放。

故障恢復常見問題

HMaster等待Namespace表超時終止

當叢集進行重啟時,HMaster進行初始化會找到所有的異常RegionServer(Dead RegionServer)並開始SCP流程,並繼續初始化Namespace表。

如果SCP列表中存在大量的RegionServer,那麼Namespace表的分配將可能被延遲並超過配置的超時時間(預設5分鐘),而這種情況在大叢集場景下是最常見的。為臨時解決該問題,常常將預設值改大,但是必不能保證一定會成功。

另外一種方式是在HMaster上啟用表來避免此問題(hbase.balancer.tablesOnMaster=hbase:namespace),HMaster會優先將這些表進行分配。但是如果配置了其它表也可以分配到HMaster或者由於HMaster效能問題,這將無法做到100%解決此問題。此外在HBase 2.X版本中也不推薦使用HMaster來啟用表。解決這個問題的最佳方法是支援優先表和優先節點,當HMaster觸發SCP流程時,優先將這些表分配到優先節點上,確保分配的優先順序,從而完全消除此問題。

批量分配時RPC超時

HBase專門線性可擴充套件性而設計。如果叢集中的資料隨著表增加而增多,叢集可以很容易擴充套件新增RegionServer來管理表和資料。例如:如果一個叢集從10個RegionServer擴充套件到20個RegionServer,它在儲存和處理能力方面將會增加。

隨著RegionServer上Region數量的增加,批量分配RPC呼叫將會出現超時(預設60秒)。這將導致重新進行分配並最終對分配上線時間產生嚴重影響。

在10個RegionServer節點和20個RegionServer節點的測試中,RPC呼叫分別花費了約60秒和116秒。對於更大的叢集來說,批量分配無法一次成功。主要原因在於對ZooKeeper進行大量的讀寫操作和RPC呼叫,用來建立OFFLINE ZNode節點,建立正在恢復的Region ZNode節點資訊等。

恢復可擴充套件性測試

在10到100個節點的叢集測試中,我們觀察到恢復時間隨著叢集規模的增大而線性增加。這意味著叢集越大,恢復所需的時間就越多。特別是當要恢復WAL檔案時,恢復時間將會非常大。在100個節點的叢集中,通過Put請求寫入資料的情況下,恢復需要進行WAL Split操作,發現需要100分鐘才能從叢集崩潰中完全恢復。而在相同規模的叢集中,如果不寫入任何資料大約需要15分鐘。這意味著85%以上的時間用於WAL Split操作和回放用於恢復。

Cluster Size Recovered edit files count Total No. Of regions [2k per RS] Region Assignment (with WAL split) Empty Region Assignment
10 Node 4,00,000 20,000 7.5 Mins 4 Min
20 Node 8,00,000 40,000 12 Mins 6 Mins
40 Node 1.6 Million 80,000 42 Mins 7 Mins
100 Nodes 4 Million 0.2 Million 106 Mins 15 Mins

下面我們將分析測試過程中發現的瓶頸在哪裡?

恢復耗時分析

HDFS負載

在10個節點的HBase叢集上,通過JMX來獲取HDFS的RPC請求監控資訊,發現在啟動階段有1200萬讀取RPC呼叫。

其中GetBlockLocationNumOps:380萬、GetListingNumOps:13萬、GetFileInfoNumOps:840萬。

當叢集規模達到100個時,RPC呼叫和檔案操作將會非常大,從而對HDFS負載造成很大壓力,成為瓶頸。可能由於以下原因導致HDFS寫入失敗、WAL Split和Region上線緩慢超時重試。

  • 巨大的預留磁碟空間。
  • 併發訪問達到DataNode的xceiver的限制。

HMaster負載

HMaster使用基於ZooKeeper的分配機制時,在Region上線過程中HMaster會建立一個OFFLINE ZNode節點,RegionServer會將該ZNode更新為OPENING和OPENED狀態。對於每個狀態變化,HMaster都會進行監聽並處理。

對於100個節點的HBase叢集,大概將會有6,000,000個ZNode建立和更新操作和4,000,000個監聽事件要進行處理。

ZooKeeper的監聽事件通知處理是順序的,旨在保證事件的順序。這種設計在Region鎖獲取階段將會導致延遲。在10個節點的叢集中發現等待時間為64秒,而20節點的叢集中等待時間為111秒。

GeneralBulkAssigner 在批量傳送OPEN RPC請求到RegionServer之前會獲取相關Region的鎖,再收到RegionServer的OPEN RPC請求響應時才會釋放該鎖。如果RegionServer再處理批量OPEN RPC請求時需要時間,那麼在收到確認響應之前GeneralBulkAssigner將不會釋放鎖,其實部分Region已經上線,也不會單獨處理這些Region。

HMaster按照順序建立OFFLINE ZNode節點。觀察發現在執行批量分配Region到RegionServer之前將會有35秒的延遲來建立ZNode。

採用不依賴ZooKeeper的分配機制將會減少ZooKeeper的操作,可以有50%左右的優化。HMaster依然會協調和處理Region的分配。

提升WAL Split效能

持久化FlushedSequenceId來加速叢集重啟WAL Split效能(HBASE-20727)

ServerManager有每個Region的flushedSequenceId資訊,這些資訊被儲存在一個Map結構中。我們可以利用這些資訊來過濾不需要進行回放的記錄。但是這個Map結構並沒有被持久化,當叢集重啟或者HMaster重啟後,每個Region的flushedSequenceId資訊將會丟失。

如果這些資訊被持久化那麼即使HMaster重啟,這些依然存在可用於過濾WAL記錄,加快恢復記錄和回放。hbase.master.persist.flushedsequenceid.enabled 可用於配置是否開啟此功能。flushedSequenceId資訊將會定時持久化到如下目錄 < habse root dir >/.lastflushedseqids。可以通過引數 hbase.master.flushedsequenceid.flusher.interval 來配置持久化間隔,預設為3小時。

注意:此特性在HBase 1.X版本不可用。

改善WAL Split在故障切換時穩定性(HBASE-19358)

在WAL記錄恢復期間,WAL Split任務將會將RegionServer上的所有待恢復記錄輸出檔案開啟。當RegionServer上管理的Region數量較多時將會影響HDFS,需要大量的磁碟保留空間但是磁碟寫入非常小。

當叢集中所有RegionServer節點都重啟進行恢復時,情況將變得非常糟糕。如果一個RegionServer上有2000個Region,每個HDFS檔案為3副本,那麼將會導致每個WAL Splitter開啟6000個檔案。

通過啟用hbase.split.writer.creation.bounded可以限制每個WAL Splitter開啟的檔案。當設定為true時,不會開啟任何recovered.edits的寫入直到在記憶體積累的記錄已經達到 hbase.regionserver.hlog.splitlog.buffersize(預設128M),然後一次性寫入並關閉檔案,而不是一直處於開啟狀態。這樣會減少開啟檔案流數量,從hbase.regionserver.wal.max.splitters * the number of region the hlog contains減少為hbase.regionserver.wal.max.splitters * hbase.regionserver.hlog.splitlog.writer.threads。

通過測試發現在3節點叢集中,擁有15GB WAL檔案和20K Region的情況下,叢集整體重啟時間從23分鐘縮短為11分鐘,減少50%。

hbase.regionserver.wal.max.splitters = 5

hbase.regionserver.hlog.splitlog.writer.threads= 50

WAL Split為HFile(HBASE-23286)

WAL恢復時使用HFile檔案替換Edits檔案這樣可以避免在Region上線過程中寫入。Region上線過程中需要完成HFile檔案校驗、執行bulkload載入並觸發Compaction來合併小檔案。此優化可以避免讀取Edits檔案和持久化記憶體帶來的IO開銷。當叢集中的Region數量較少時(例如50個Region)觀察發現效能有顯著提升。

當叢集中有更多的Region時,測試發現由於大量的HFile寫入和合並將會導致CPU和IO的增加。可以通過如下額外的措施來減少IO。

  • 將故障RegionServer作為首選WAL Splitter,減少遠端讀取。
  • 將Compaction延遲後臺執行,加快region上線處理。

Observer NameNode(HDFS-12943)

當HBase叢集規模變大時,重啟會觸發大量的RPC請求,使得HDFS可能成為瓶頸,可以通過使用Observer NameNode負擔讀請求來降低HDFS的負載。

總結

通過上述分析,可以配置如下引數來提升HBase MTTR,尤其是在叢集整體從崩潰中恢復的情況。

Configuration Recommendation Remarks
HMaster hbase.master.executor.openregion.thread 2 * no. of cores Opened region thread to process OPENED ZK events. Can increase based on the cores in large cluster.
HMaster hbase.assignment.zkevent.workers 2 * no. of cores ZK event worker thread to process RIT ZK notification, can be tuned based on cores
HMaster hbase.master.skip.log.split.task true Master participate in WAL split as namespace region is assigned to Hmaster. Hmaster may be overloaded during MTTR
HMaster hbase.balancer.tablesOnMaster hbase:namespace Assign namespace region to Hmaster, so that HM WAL will be split first to recover namespace region and there wont be any Hmaster abort due to Namespace init timeout Note: Later this will be replaced with Assign system tables to specified RS Group
RegionServer hbase.regionserver.executor.openregion.threads 2 * no. of cores Handlers to process Open region requests
RegionServer hbase.regionserver.metahandler.count 5 * no. of cores Meta operation handlers. During full cluster restart, all RSs are opening the region concurrently, so we need more handlers. We observed better perf upto 400 handlers.
RegionServer hbase.regionserver.wal.max.splitters Same as hbase.regionserver.maxlogs To perform WAL split concurrently and avoid overlap with assignment region cycle. If SCP is blocked for assignment which takes more time, WAL split would be delayed.
RegionServer hbase.regionserver.hlog.splitlog.writer.threads 50 Works in combination with hbase.split.writer.creation.bounded Writer thread to flush the recovered edits region wise. , can be reduced when active regions are less
RegionServer hbase.split.writer.creation.bounded true To control the number of open files in HDFS for writing recovered edits. If true, edits are cached and flushed once the buffer is full.
RegionServer hbase.wal.split.to.hfile true When the active regions are less per RS, can use this configurations to reduce IO. But if the active regions are high, this feature may not have impact.
RegionServer hbase.regionserver.maxlogs 20 Lesser the logs, lesser the time for wal split & recovering edits
HMaster hbase.master.persist.flushedsequenceid.enabled true Skip WAL edits which are already flushed into Hfile
HMaster hbase.rpc.timeout 120000 Bulk assignment RPC gets timed out due to slow processing by RS if there are many regions in RS

本文由華為雲釋出。

相關文章