古詩詞大全網 - 字典詞典 - 六、HBase寫入流程

六、HBase寫入流程

1、HBase寫入流程

HBase服務端沒有提供update,delete接口,HBase中對數據的更新、刪除操作都認為是寫入操作,更新操作會寫入壹個最小版本數據,刪除操作寫寫入壹條標記為deleted的KV數據

1.1、寫入流程三個階段概況

1)客戶端處理階段:客戶端將用戶請求進行預處理,並根據集群元數據定位寫入數據所在的RegionServer,將請求發送給RS

2)Region寫入階段:RS收到請求之後解析數據,首先把數據寫入WAL,再寫入對應Region對應的MemStore

3)MemStore Flush階段:當Region中MemStore容量達到壹定閾值之後,系統異步執行flush操作,將內存寫入文件,形成HFile

1.2、用戶寫入請求在完成寫入MemStore之後就會返回成功。MemStore Flush是壹個異步執行的過程。

1.3、客戶端處理階段步驟詳解:

1)客戶端可以設置批量提交,如果設置了批量提交(autoflush=false)客戶端會先將數據寫入本地緩沖區等達到壹定閾值之後才會提交。否則put請求直接會提交給服務端進行處理。

2)RS尋址,在提交之前HBase會在元數據表hbase:meta中根據rowkey找到她們歸屬的RS

2.1)客戶端根據寫入的表和rowkey在元數據中查找,如果能夠查找出該rowkey所在的RS及Region,就直接發送寫入請求

2.2)如果客戶端沒有找到rowkey信息,需要首先到zk上找到hbase:meta表所在的RS,向那RS發送查詢請求獲取元數據,然後在元數據中查找rowkey所在的RS,並將元數據緩存在本地,以備下次使用。

3)客戶端發送遠程RPC請求給RS,將數據寫入目標Region的MemStore中

1.4、Region寫入階段步驟詳解:

1)獲取行鎖,HBase中使用行鎖保證對同壹行數據的更新是互斥操作,用以保證更新的原子性,要麽成功要麽失敗

2)更新所有待寫入keyValue的時間戳為當前系統時間

3)對壹次寫入同壹個Region的壹個或多個KeyValue構建壹條WALEdit記錄,這樣做的目的是保證Region級別事務的寫入原子性

4)把WALEdit寫入HLog,HLog是存儲在HDFS上需要sync操作把HLog真正落地到HDFS,在這壹部暫時不用執行sync,HBase使用了disruptor實現了高效的生產者消費者隊列,來異步實現WAL的追加寫入操縱

5)寫入WAL之後再將數據寫入MemStore

6)釋放行鎖

7)sync WAL:將HLog真正sync到HDFS,如果sync失敗,執行回滾操作將MemStore數據移除

8)結束寫事務。更新對外可見,更新生效

1.5、MemStore Flush階段詳解:

1.5.1、觸發flush條件

1.5.1.1、MemStore級別限制,當Rgion中任意壹個MemStore大小達到閾值(hbase.hrgion.memstore.flush.size)默認128M

1.5.1.2、Region級別限制:當Region所有MemStore的大小達到了上限(hbase.hregion.memstore.block.multiplier * hbase.hrgion.memstore.flush.size)超過memstore大小的倍數達到該值則阻塞所有寫入請求進行flush,自我保護默認是2.

1.5.1.3、RegionServer級別限制:當RS中MemStore的總大小超過低水位閾值hbase.regionserver.global.memstore.size.lower.limit * hbase.reagionserver.global.memstore.size RS則開始強制執行flush,按Region中MemStore大小從大到小進行flush,直到總MemStore大小下降到低水位。

1.5.1.4、當壹個RegionServer中HLog數量達到壹定上限(hbase.regionserver.maxlogs),系統選擇最早的HLog對應的Rgion進行Flush

1.5.1.5、HBase定期Flush,默認是1小時確保MemStore不會長時間沒有持久化。為了避免同壹時間所有都進行flush,定期的flush操作有壹定時間的隨機延遲

1.5.1.6、手動flush,用戶可以通過flush 'tablename'或者 flush 'regionname'對壹個表或者Region進行flush

1.5.2、flush執行步驟

1.5.2.1、prepare階段

遍歷當前region下的MemStore做壹個快照,然後新壹個ConcurrentSkipListMap接受新的數據請求。此階段需要通過鎖來阻塞寫請求,結束後釋放鎖,此過程持鎖時間很短

1.5.2.2、flush階段

對快照數據按照特定格式生成HFile持久化為臨時文件放在.tmp目錄下。這個過程涉及到磁盤IO操作,相對比較耗時

1.5.2.3、commit階段

把臨時文件移動到指定的CF目錄下。再清空快照數據。

1.5.3、MemStore Flush對業務的影響

1.5.3.1、大部分MemStore Flush操作都不會對業務讀寫產生太大影響,

1.5.3.2、Region Server級別呆滯的flush,會對用戶請求產生較大影響,會阻塞落在該RS上的寫入操作。

1.6、HLog寫入模型

1.6.1、HLog持久化級別

SKIP_WAL:只寫緩存,不寫HLog,不可取

ASYNC_WAL:異步寫入HLog

SYNC_WAL:同步寫入日誌文件,數據只是被寫入文件系統緩存中並沒有真正落盤。默認是此級別

FSYNC_WAL:同步將數據寫入日誌文件並強制落盤,這是最嚴格的寫入級別,保證數據不丟失,性能相對較差

USER_DEFAULT:如果用戶沒有指定持久化級別,默認HBase使用SYN_WAL等級持久化數據put.setDurability(Durability.SYNC_WAL);

1.6.2、HLog寫入模型

1、HLog寫入需要經過3個階段:手寫將數據寫入本地緩存,然後將本地緩存寫入文件系統,最後執行syn操作同步到磁盤

2、HBase使用LMAX Disruptor框架實現了無鎖有界隊列操作,寫入模型如下圖

2、BulkLoad 流程

2.1、BulkLoad使用場景:用戶數據位於HDFS中,業務需要定期將這部分海量數據導入HBase系統.

2.2、核心流程分兩步

2.2.1、HFile生成階段:運行壹個MapReduce任務,map需要自己實現,將HDFS文件中的數據讀取出來組裝壹個復合KV,其中Key是rowkey,Value可以是KeyValue對象、Put對象甚至Delete對象;reduce由HBase負責,他會根據表信息配置壹個全局有序的partitioner,將partitioner文件上傳到HDFS集群,設置reduce task個數為目標表的Region個數。為每個Region生成壹個對應的HFile文件

2.2.2、HFile導入階段:HFile主備就緒後,將HFile加載到在線集群。

2.3、Bulkload遇到的壹些常見問題

2.3.1、設置正確的權限

2.3.1、BulkLoad操作過程涉及到的用戶:

第壹步,通過MapReduce任務生成HFile。假設這個過程使用的HDFS賬號為:u_mapreduce.

第二步,將HFile加載到HBase集群,假設這個步驟使用的賬號為:u_load。

壹般地:HBase集群由壹個專門的賬號用來管理HBase數據,該賬號擁有HBase集群的所有表的最高權限,

同時可以讀寫HBase root目錄下的所有文件,假設這個賬號為:hbase_srv

2.3.2、權限設置

2.3.2.1、通過MapReduce任務生成HFile,HFile文件的owner為u_mapreduce。

2.3.2.2、u_load需要HFile文件以及目錄的讀、寫權限。寫的權限是因為在HFile跨越多個Region時,需要對HFile進行split操作。

另外u_load賬號需要HBase表的Create權限

2.3.2.3、hbase_srv賬號把HFile文件從用戶的數據目錄rename到HBase的數據目錄,所以hbase_sHrv需要有用戶數據目錄及HFile的讀取

權限,但事實上僅讀取權限還不夠,應為加載到HBase數據目錄的HFile目錄的owner仍為u_mapreduce。壹旦執行完compaction操作

之後,這些文件無法挪動到archive目錄,導致文件越來越多。這個問題在HBase 2.x 上修復。

2.3.2、影響Locality

如果生成HFile都在的HDFS集群和HBase所在HDFS集群時同壹個,則MapReduce生成HFile,能夠保證HFile與目標Region落在同壹個機器上。這樣就保證了Locality。由hbase.bulkload.locality.sensitive.enabled的參數控制整個邏輯,默認是true.所以默認保證locality的。

如果用戶MapReduce在A集群上生成HFile,通過distcp拷貝到集群B.這樣BulkLoad到HBase集群數據是沒法保證Locality的。需要跑完BulkLoad之後再手動執行major compact,來提升loaclity。

2.3.3、BulkLoad數據復制

在1.3之前版本中,BulkLoad到HBase集群的數據並不會復制到備集群,這樣可能無意識的導致備集群比主集群少了很多數據。在HBase1.3版本之後開始支持BulkLoad數據復制。需要開啟開關:hbase.replicatition.bulkload.enabled=true。