Apache HBase MTTR 優化實踐
- 2022 年 3 月 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 |
本文由華為雲發布。