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 |
本文由華為雲釋出。