hbase數據寫入流程深度解析
hbase數據寫入流程深度解析
在看此鏈接之前,可以寫查看 hbase讀寫請求詳細解釋 中的寫請求流程 https://blog.51cto.com/12445535/2356085
簡介:
hbase設置之初就是為了應對大量的寫多讀少的應用,他出色的寫性能,在一個100臺RS的集群可以輕松地支撐每天10T的寫入量。
hbase的寫數據流程大體分為3部分
1、客戶端的寫入流程
2、服務端的寫入流程
3、wal的工作原理
我們先回顧一下hbase寫數據流程
寫請求處理過程小結
1 client 向region server 提交寫請求
2 region server 找到目標region
3 region 檢查數據是否與schema 一致
5 將更新寫入WAL log
6 將更新寫入Memstore
7 判斷Memstore 的是否需要flush 為Store 文件。
第一部分:客戶端的寫入流程
客戶端流程解析:
1、用戶提交put請求後,HBase客戶端會將put請求添加到本地buffer中,符合一定條件就會通過AsyncProcess異步批量提交。
HBase默認設置autoflush=true,表示put請求直接會提交給服務器進行處理;
2、用戶可以設置autoflush=false,這樣的話put請求會首先放到本地buffer,等到本地buffer大小超過一定閾值(默認為2M,可以通過配置文件配置)之後才會提交。很顯然,後者采用group commit機制提交請求,可以極大地提升寫入性能,但是因為沒有保護機制,如果客戶端崩潰的話會導致提交的請求丟失。
cdh集群中hbase默認是使用autoflush=false 也就是首先會把數據放在本地的buffer中
HBase 客戶端寫入緩沖
hbase.client.write.buffer = 2M //寫入緩沖區大小(以字節為單位)。較大緩沖區需要客戶端和服務器中有較大內存,因為服務器將實例化已通過的寫入緩沖區並進行處理,這會降低遠程過程調用 (RPC) 的數量。為了估計服務器已使用內存的數量,請用值“hbase.client.write.buffer”乘以“hbase.regionserver.handler.count”。
HBase Region Server 處理程序計數
hbase.regionserver.handler.count = 30 //RegionServer 中啟動的 RPC 服務器實例數量
4、HBase會為每個HRegionLocation構造一個遠程RPC請求MultiServerCallable<Row>,然後通過rpcCallerFactory.<MultiResponse> newCaller()執行調用,忽略掉失敗重新提交和錯誤處理,客戶端的提交操作到此結束。
第二部分:服務端寫入流程
服務端流程解析
(1)獲取行鎖、Region更新共享鎖 -》(2)開始寫事務 -》(3)寫緩存memstore -》(4)構造waledit並append hlog - 》 (5)
釋放行鎖,共享鎖 - 》 (6)sync hlog -》(7)結束寫事務 - 》(8) flush memstore
//解釋
(1)獲取行鎖、Region更新共享鎖: HBase中使用行鎖保證對同一行數據的更新都是互斥操作,用以保證更新的原子性,要麽更新成功,要麽失敗。
(2)開始寫事務:獲取write number,用於實現MVCC,實現數據的非鎖定讀,在保證讀寫一致性的前提下提高讀取性能。
(3)寫緩存memstore:HBase中每列族都會對應一個store,用來存儲該列數據。每個store都會有個寫緩存memstore,用於緩存寫入數據。HBase並不會直接將數據落盤,而是先寫入緩存,等緩存滿足一定大小之後再一起落盤。
(4)Append HLog:HBase使用WAL機制保證數據可靠性,即首先寫日誌再寫緩存,即使發生宕機,也可以通過恢復HLog還原出原始數據。該步驟就是將數據構造為WALEdit對象,然後順序寫入HLog中,此時不需要執行sync操作。0.98版本采用了新的寫線程模式實現HLog日誌的寫入,可以使得整個數據更新性能得到極大提升,具體原理見下一個章節。
(5)釋放行鎖以及共享鎖
(6)Sync HLog:HLog真正sync到HDFS,在釋放行鎖之後執行sync操作是為了盡量減少持鎖時間,提升寫性能。如果Sync失敗,執行回滾操作將memstore中已經寫入的數據移除。
(7)結束寫事務:此時該線程的更新操作才會對其他讀請求可見,更新才實際生效。具體分析見文章《數據庫事務系列-HBase行級事務模型》
(8)flush memstore:當寫緩存滿128M之後,會啟動flush線程將數據刷新到硬盤。刷新操作涉及到HFile相關結構,後面會詳細對此進行介紹。
//HBase Memstore 刷新大小
hbase.hregion.memstore.flush.size = 128M //如 memstore 大小超過此值(字節數),Memstore 將刷新到磁盤。通過運行由 hbase.server.thread.wakefrequency 指定的頻率的線程檢查此值。
//提示:
我們需要註意,在服務器端寫數據的時候,有很多資料是先寫到memstore中,再寫到wal log中,但是,這樣理解不是很準確,因為這好像,違背了wal log的容災機制,所有,我們可以理解為
先寫入到wal log中再寫入到memstore中的 //這一步源碼中並沒有完全的體現出來,可以理解為同步進行。
理論上應該是先寫wal log中,HBase這塊實現是先寫mem,後寫WAL,hbase能夠保證只有這兩個都寫完了用戶才會可見(mvcc機制),而且如果mem寫成功,wal寫失敗,mem會被回滾。
這樣做之所以it’s ok,是由於MVCC來保證的,在每個寫線程開啟事務的開頭就會創建全局遞增的write num,但是在HLog更新完畢之後才會去向前推進(roll forward)全局讀取點。
所以在此期間內,任何讀取線程采用MVCC機制根據讀取點讀取數據,任何寫入/更新操作在HLog未更新完畢之前是不會向前推進讀取點的,因此即使數據已經寫入memstore,對讀線程也是不可見的。
第三部分:WAL機制解析
1、WAL(Write-Ahead Logging)是一種高效的日誌算法,幾乎是所有非內存數據庫提升寫性能的不二法門,
2、基本原理是在數據寫入之前首先順序寫入日誌,然後再寫入緩存,等到緩存寫滿之後統一落盤。
3、之所以能夠提升寫性能,是因為WAL將一次隨機寫轉化為了一次順序寫加一次內存寫。
4、提升寫性能的同時,WAL可以保證數據的可靠性,即在任何情況下數據不丟失。
5、假如一次寫入完成之後發生了宕機,即使所有緩存中的數據丟失,也可以通過恢復日誌還原出丟失的數據。
WAL持久化等級
HBase中可以通過設置WAL的持久化等級決定是否開啟WAL機制、以及HLog的落盤方式。
WAL的持久化等級分為如下四個等級:
-
SKIP_WAL:只寫緩存,不寫HLog日誌。這種方式因為只寫內存,因此可以極大的提升寫入性能,但是數據有丟失的風險。在實際應用過程中並不建議設置此等級,除非確認不要求數據的可靠性。
-
ASYNC_WAL:異步將數據寫入HLog日誌中。
-
SYNC_WAL:同步將數據寫入日誌文件中,需要註意的是數據只是被寫入文件系統中,並沒有真正落盤。
-
FSYNC_WAL:同步將數據寫入日誌文件並強制落盤。最嚴格的日誌寫入等級,可以保證數據不會丟失,但是性能相對比較差。
- USER_DEFAULT:默認如果用戶沒有指定持久化等級,HBase使用SYNC_WAL等級持久化數據。
用戶可以通過客戶端設置WAL持久化等級,代碼:put.setDurability(Durability. SYNC_WAL );
//cdh中
WAL 提供程序
hbase.wal.provider = //可選項為: //RegionServer 應用於提前寫入日誌的實施。
RegionServer Default Group
多個 HDFS WAL
單個 HDFS WAL
HBase 默認設置(Single HDFS WAL)
WAL HSM 存儲策略
hbase.wal.storage.policy
RegionServer Default Group
所有副本都在 SSD 上
一個副本在 SSD 上,其他副本均在 HDD 上
無(全部在 HDD 上)
關於wal 和 hlog概念的的升入研究 見參考鏈接
//HLog的寫入模型。HLog的寫入可以分為三個階段,首先將數據對<HLogKey,WALEdit>寫入本地緩存,然後再將本地緩存寫入文件系統,最後執行sync操作同步到磁盤。
參考鏈接:
http://hbasefly.com/2016/03/23/hbase_writer/
hbase數據寫入流程深度解析