1. 程式人生 > 其它 >HBase學習之深入理解Memstore-6

HBase學習之深入理解Memstore-6

HBase學習之深入理解Memstore-6

MemStore是HBase非常重要的組成部分,深入理解MemStore的執行機制、工作原理、相關配置,對HBase叢集管理以及效能調優有非常重要的幫助。

HBaseMemstore

首先通過簡單介紹HBase的讀寫過程來理解一下MemStore到底是什麼,在何處發揮作用,如何使用到以及為什麼要用MemStore。

圖一:Memstore Usage in HBase Read/Write Paths

當RegionServer(RS)收到寫請求的時候(write request),RS會將請求轉至相應的Region。每一個Region都儲存著一些列(a set of rows)。根據其列族的不同,將這些列資料儲存在相應的列族中(Column Family,簡寫CF)。不同的CFs中的資料儲存在各自的HStore中,HStore由一個Memstore及一系列HFile組成。Memstore位於RS的主記憶體中,而HFiles被寫入到HDFS中。當RS處理寫請求的時候,資料首先寫入到Memstore,然後當到達一定的閥值的時候,Memstore中的資料會被刷到HFile中。

用到Memstore最主要的原因是:儲存在HDFS上的資料需要按照row key 排序。而HDFS本身被設計為順序讀寫(sequential reads/writes),不允許修改。這樣的話,HBase就不能夠高效的寫資料,因為要寫入到HBase的資料不會被排序,這也就意味著沒有為將來的檢索優化。為了解決這個問題,HBase將最近接收到的資料快取在記憶體中(in Memstore),在持久化到HDFS之前完成排序,然後再快速的順序寫入HDFS。需要注意的一點是實際的HFile中,不僅僅只是簡單地排序的列資料的列表,詳見Apache HBase I/O – HFile

除了解決“無序”問題外,Memstore還有一些其他的好處,例如:

  • 作為一個記憶體級快取,快取最近增加資料。一種顯而易見的場合是,新插入資料總是比老資料頻繁使用。
  • 在持久化寫入之前,在記憶體中對Rows/Cells可以做某些優化。比如,當資料的version被設為1的時候,對於某些CF的一些資料,Memstore快取了數個對該Cell的更新,在寫入HFile的時候,僅需要儲存一個最新的版本就好了,其他的都可以直接拋棄。

有一點需要特別注意:每一次Memstore的flush,會為每一個CF建立一個新的HFile。在讀方面相對來說就會簡單一些:HBase首先檢查請求的資料是否在Memstore,不在的話就到HFile中查詢,最終返回merged的一個結果給使用者。

HBase Memstore關注要點

迫於以下幾個原因,HBase使用者或者管理員需要關注Memstore並且要熟悉它是如何被使用的:

  • Memstore有許多配置可以調整以取得好的效能和避免一些問題。HBase不會根據使用者自己的使用模式來調整這些配置,你需要自己來調整。
  • 頻繁的Memstore flush會嚴重影響HBase叢集讀效能,並有可能帶來一些額外的負載。
  • Memstore flush的方式有可能影響你的HBase schema設計

接下來詳細討論一下這些要點:

Configuring Memstore Flushes

對Memstore Flush來說,主要有兩組配置項:

  • 決定Flush觸發時機
  • 決定Flush何時觸發並且在Flush時候更新被阻斷(block)

第一組是關於觸發“普通”flush,這類flush發生時,並不影響並行的寫請求。該型別flush的配置項有:

  • hbase.hregion.memstore.flush.size
1 2 3 4 5 6 7 8 9 <property> <name>hbase.hregion.memstore.flush.size</name> <value>134217728</value> <description> Memstore will be flushed to disk if size of the memstore exceeds this number of bytes. Value is checked by a thread that runs every hbase.server.thread.wakefrequency. </description> </property>
  • base.regionserver.global.memstore.lowerLimit
1 2 3 4 5 6 7 8 9 10 <property> <name>hbase.regionserver.global.memstore.lowerLimit</name> <value>0.35</value> <description>Maximum size of all memstores in a region server before flushes are forced. Defaults to 35% of heap. This value equal to hbase.regionserver.global.memstore.upperLimit causes the minimum possible flushing to occur when updates are blocked due to memstore limiting. </description> </property>

需要注意的是第一個設定是每個Memstore的大小,當你設定該配置項時,你需要考慮一下每臺RS承載的region總量。可能一開始你設定的該值比較小,後來隨著region增多,那麼就有可能因為第二個設定原因Memstore的flush觸發會變早許多。

第二組設定主要是出於安全考慮:有時候叢集的“寫負載”非常高,寫入量一直超過flush的量,這時,我們就希望memstore不要超過一定的安全設定。在這種情況下,寫操作就要被阻止(blocked)一直到memstore恢復到一個“可管理”(manageable)的大小。該型別flush配置項有:

  • hbase.regionserver.global.memstore.upperLimit
1 2 3 4 5 6 7 8 9 <property> <name>hbase.regionserver.global.memstore.upperLimit</name> <value>0.4</value> <description>Maximum size of all memstores in a region server before new updates are blocked and flushes are forced. Defaults to 40% of heap. Updates are blocked and flushes are forced until size of all memstores in a region server hits hbase.regionserver.global.memstore.lowerLimit. </description> </property>
  • hbase.hregion.memstore.block.multiplier
1 2 3 4 5 6 7 8 9 10 11 12 <property> <name>hbase.hregion.memstore.block.multiplier</name> <value>2</value> <description> Block updates if memstore has hbase.hregion.block.memstore time hbase.hregion.flush.size bytes. Useful preventing runaway memstore during spikes in update traffic. Without an upper-bound, memstore fills such that when it flushes the resultant flush files take a long time to compact or split, or worse, we OOME. </description> </property>

某個節點“寫阻塞”對該節點來說影響很大,但是對於整個叢集的影響更大。HBase設計為:每個Region僅屬於一個RS但是“寫負載”是均勻分佈於整個叢集(所有Region上)。有一個如此“慢”的節點,將會使得整個叢集都會變慢(最明顯的是反映在速度上)。

提示:嚴重關切Memstore的大小和Memstore Flush Queue的大小。理想情況下,Memstore的大小不應該達到hbase.regionserver.global.memstore.upperLimit的設定,Memstore Flush Queue 的size不能持續增長。

頻繁的Memstore Flushes

要避免“寫阻塞”,貌似讓Flush操作儘量的早於達到觸發“寫操作”的閾值為宜。但是,這將導致頻繁的Flush操作,而由此帶來的後果便是讀效能下降以及額外的負載。

每次的Memstore Flush都會為每個CF建立一個HFile。頻繁的Flush就會建立大量的HFile。這樣HBase在檢索的時候,就不得不讀取大量的HFile,讀效能會受很大影響。

為預防開啟過多HFile及避免讀效能惡化,HBase有專門的HFile合併處理(HFile Compaction Process)。HBase會週期性的合併數個小HFile為一個大的HFile。明顯的,有Memstore Flush產生的HFile越多,集群系統就要做更多的合併操作(額外負載)。更糟糕的是:Compaction處理是跟叢集上的其他請求並行進行的。當HBase不能夠跟上Compaction的時候(同樣有閾值設定項),會在RS上出現“寫阻塞”。像上面說到的,這是最最不希望的。

提示:嚴重關切RS上Compaction Queue 的size。要在其引起問題前,阻止其持續增大。

想了解更多HFile 建立和合並,可參看Visualizing HBase Flushes And Compactions

理想情況下,在不超過hbase.regionserver.global.memstore.upperLimit的情況下,Memstore應該儘可能多的使用記憶體(配置給Memstore部分的,而不是真個Heap的)。下圖展示了一張“較好”的情況:

“Somewhat”, because we could configure lower limit to be closer to upper, since we barely ever go over it.

說是“較好”,是因為我們可以將“Lower limit”配置的更接近於“Upper limit”,我們幾乎很少有超過它。

Multiple Column Families & Memstore Flush

每次Memstore Flush,會為每個CF都建立一個新的HFile。這樣,不同CF中資料量的不均衡將會導致產生過多HFile:當其中一個CF的Memstore達到閾值flush時,所有其他CF的也會被flush。如上所述,太頻繁的flush以及過多的HFile將會影響叢集效能。

提示:很多情況下,一個CF是最好的設計。

HLog (WAL) Size & Memstore Flush

第一張HBase Read/Write path圖中,你可能已經注意到當資料被寫入時會預設先寫入Write-ahead Log(WAL)。WAL中包含了所有已經寫入Memstore但還未Flush到HFile的更改(edits)。在Memstore中資料還沒有持久化,當RegionSever宕掉的時候,可以使用WAL恢復資料。

當WAL(在HBase中成為HLog)變得很大的時候,在恢復的時候就需要很長的時間。因此,對WAL的大小也有一些限制,當達到這些限制的時候,就會觸發Memstore的flush。Memstore flush會使WAL 減少,因為資料持久化之後(寫入到HFile),就沒有必要在WAL中再儲存這些修改。有兩個屬性可以配置:

  • hbase.regionserver.hlog.blocksize
  • hbase.regionserver.maxlogs

你可能已經發現,WAL的最大值由hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize (2GB by default)決定。一旦達到這個值,Memstore flush就會被觸發。所以,當你增加Memstore的大小以及調整其他的Memstore的設定項時,你也需要去調整HLog的配置項。否則,WAL的大小限制可能會首先被觸發,因而,你將利用不到其他專門為Memstore而設計的優化。拋開這些不說,通過WAL限制來觸發Memstore的flush並非最佳方式,這樣做可能會會一次flush很多Region,儘管“寫資料”是很好的分佈於整個叢集,進而很有可能會引發flush“大風暴”。

提示:最好將hbase.regionserver.hlog.blocksize * hbase.regionserver.maxlogs 設定為稍微大於hbase.regionserver.global.memstore.lowerLimit * HBASE_HEAPSIZE.

Compression & Memstore Flush

HBase建議壓縮儲存在HDFS上的資料(比如HFiles)。除了節省硬碟空間,同樣也會顯著地減少硬碟和網路IO。使用壓縮,當Memstore flush並將資料寫入HDFS時候,資料會被壓縮。壓縮不會減慢多少flush的處理過程,卻會大大減少以上所述問題,例如因為Memstore變大(超過 upper limit)而引起的“寫阻塞”等等。

提示:壓縮庫建議使用Snappy。有關Snappy的介紹及安裝,可分別參考:《Hadoop壓縮-SNAPPY演算法》和《Hadoop HBase 配置 安裝 Snappy 終極教程

轉載http://www.cnblogs.com/shitouer/archive/2012/05/21/2511060.html