深刻解讀HBase2.0新功能之高可用讀Region Replica

摘要: 基於時間線一致的高可用讀(Timeline-consistent High Available Reads),又稱Region replica,爲HBase帶來了高可用讀的能力。本文主要介紹region replica這個功能設計的背景,技術細節和使用方法,同時會仔細分析這個功能的優缺點並給出使用建議。html

前言

基於時間線一致的高可用讀(Timeline-consistent High Available Reads),又稱Region replica。其實早在HBase-1.2版本的時候,這個功能就已經開發完畢了,可是仍是不太穩定,離生產可用級別還有一段距離,後來社區又陸陸續續修復了一些bug,好比說HBASE-18223。這些bug不少在HBase-1.4以後的版本才修復,也就是說region replica功能基本上在HBase-1.4以後才穩定下來。介於HBase-1.4版本目前實際生產中使用的還比較少,把region replica功能說成是HBase2.0中的新功能也不爲過。shell

爲何須要Region Replica

CAP理論中,HBase一直是一個CP(Consistency&Partition tolerance)系統。HBase一直以來都在遵循着讀寫強一致的語義。因此說雖然在存儲層,HBase依賴HDFS實現了數據的多副本,可是在計算層,HBase的region只能在一臺RegionServer上線提供讀寫服務,來保持強一致。若是這臺服務器發生宕機時,Region須要從WAL中恢復還緩存在memstore中未刷寫成文件的數據,才能從新上線服務。
apache

因爲HBase的RegionServer是使用Zookeeper與Master保持lease。而爲了避免讓JVM GC停頓致使RegionServer被master「誤判」死亡,這個lease時間一般都會設置爲20~30s,若是RegionServer使用的Heap比較大時,這個lease可能還會設的更長。加上宕機後,region須要re-assign,WAL可能須要 recoverlease和被replay操做,一個典型的region宕機恢復時間可能長達一分鐘!這就意味着在這一分鐘內,這個region都沒法被讀寫。因爲HBase是一個分佈式系統,同一張表的數據可能分佈在很是多的RegionServer和region裏。若是這是一個大HBase集羣,有100臺RegionServer機器,那麼宕機一臺的話,可能只有1%的用戶數據被影響了。可是若是這是小用戶的HBase集羣,一共就只有2臺RegionServer,宕機一臺意味着50%的用戶數據都在1~2分鐘以內沒法服務,這是不少用戶都沒法忍受的。緩存

其實,很大一部分用戶對讀可用性的需求,可能比讀強一致的需求還要高。在故障場景下,只要保證讀繼續可用,「stale read」,即讀到以前的數據也能夠接受。這就是爲何咱們須要read replica這個功能。安全

Region Replica技術細節

Region replica的本質,就是讓同一個region host在多個regionserver上。原來的region,稱爲Default Replica(主region),提供了與以前相似的強一致讀寫體驗。而與此同時,根據配置的多少,會有一個或者多個region的副本,統稱爲 region replica,在另外的RegionServer上被打開。而且由Master中的LoadBalancer來保證region和他們的副本,不會在同一個RegionServer打開,防止一臺服務器的宕機致使多個副本同時掛掉。
服務器

Region Replica的設計巧妙之處在於,額外的region副本並不意味着數據又會多出幾個副本。這些region replica在RegionServer上open時,使用的是和主region相同的HDFS目錄。也就是說主region裏有多少HFile,那麼在region replica中,這些數據都是可見的,都是能夠讀出來的。
region replica相對於主region,有一些明顯的不一樣。
首先,region replica是不可寫的。這其實很容易理解,若是region replica也能夠寫的話,那麼同一個region會在多個regionserver上被寫入,連主region上的強一致讀寫都無法保證了。
再次,region replica是不能被split和merge的。region replica是主region的附屬品,任何發向region replica的split和merge請求都會被拒絕掉。只有當主region split/merge時,纔會把這些region replica從meta表中刪掉,創建新生成region的region的replica。網絡

replica之間的數據同步

那麼,既然region replica不能接受寫,它打開以後,怎麼讓新寫入的數據變的可見呢?這裏,region replica有兩種更新數據的方案:運維

1. 按期的StoreFile Refresher

這個方案很是好理解,region replica按期檢查一下它本身對應的HDFS目錄,若是發現文件有變更,好比說flush下來新的文件,文件被compaction掉,它就刷新一下本身的文件列表,這個過程很是像compaction完成以後刪除被compact掉的文件和加入新的文件的流程。StoreFile Refresher方案很是簡單,只須要在RegionServer中起一個定時執行的Chroe,按期去檢查一下它上面的region哪些是region replica,哪些到了設置好的刷新週期,而後刷新就能夠了。但這個方案缺點也十分明顯,主region寫入的數據,只有當flush下來後,才能被region replica看到。並且storeFile Refresher自己還有一個刷新的週期,設的過短了,list文件列表對NN的衝擊太頻繁,設的太長,就會形成數據長時間在region replica中都不可見異步

2. Internal Replication

咱們知道,HBase是有replication鏈路的,支持把一個HBase集羣的數據經過replication複製到另一個集羣。那麼,一樣的原理,能夠在HBase集羣內部創建一條replication通道,把一個Server上的主region的數據,複製到另外一個Server的region replica上。那麼region replica接收到這些數據以後,會把他們寫入memstore中。對,你沒看錯,剛纔我說了region replica是不接受寫的,這是指replica不接受來自客戶端的寫,若是來自主region的replication的數據,它仍是會寫入memstore的。可是,這個寫和普通的寫有很明顯的區別。第一個,replica region在寫入來自主region的時候,是不寫WAL的,由於這些數據已經在主region所在的WAL中持久化了,replica中無需再次落盤。第二個,replica region的memstore中的數據是不會被flush成HFile。咱們知道,HBase的replication是基於複製WAL文件實現的,那麼在主region進行flush時,也會寫入特殊的標記Flush Marker。當region replica收到這樣的標記時,就直接會把全部memstore裏的數據丟掉,再作一次HDFS目錄的刷新,把主region剛剛刷下去的那個HFile include進來。一樣,若是主region發生了compaction,也會寫入相應的Compaction Marker。讀到這樣的標記後,replica region也會作相似的動做。分佈式

Internal replication加快了數據在region replica中的可見速度。經過replication方案,只要replication自己不發生阻塞和延遲,region replica中的數據能夠作到和主region只差幾百ms。可是,replication方案自己也存在幾個問題:

  • META表 沒法經過replication來同步數據
    若是給meta表開了region replica功能,meta表主region和replica之間的數據同步,只能經過按期的StoreFile Refresher機制。由於HBase的replication機制中會過濾掉meta表的數據。
  • 須要消耗額外的CPU和網絡帶寬來作Replication
    因爲region replica的數據同步須要,須要在HBase集羣內部創建replication通道,並且有幾個replica,就意味着須要從主region發送幾份數據。這會增長RegionServer的CPU使用,同時在server之間複製數據還須要佔用帶寬
  • 寫memstore須要額外的內存開銷
    爲了讓replica region的數據缺失的內容儘可能的少,主region的數據會經過replication發送到replica中,這些數據都會保存在memstore中。也就是說一樣的一份數據,會同時存在主region的memstore中,也會存在replica region的memstore中。replica的數量是幾,那麼memstore的內存使用量就是幾倍。

下面的兩個問題雖然能夠經過配置一些參數解決,可是列在這裏,仍然須要注意,由於一旦參數沒有配對,就會產生這樣的問題。

  • 在replica region failover後,讀到的數據可能會回退
    咱們假設一個狀況。客戶端寫入X=1,主region發生flush,X=1刷在了HFile中,而後客戶端繼續寫入X=2,X=3,那麼在主region的memstore中X=3。同時,經過replication,X=2,X=3也被複制到了replica region的memstore中。若是客戶端去replica中去讀取X的數據,也能讀到3。可是因爲replica region memstore中的數據是不寫WAL的,也不刷盤。那麼當replica所在的機器宕機後,它是沒有任何數據恢復流程的,他會直接在其餘RegionServer上線。上線後它只能讀取HFile,沒法感知主region memstore裏的數據。這時若是客戶端來replica上讀取數據,那麼他只會讀到HFile中的X=1。也就是說以前客戶端能夠讀到X=3,但後來卻只能讀到X=1了,數據出現了回退。爲了不出現這樣的問題,能夠配置一個hbase.region.replica.wait.for.primary.flush=true的參數,配置以後,replica region上線後,會被標記爲不可讀,同時它會去觸發一次主region的flush操做。只有收到主region的flush marker以後,replica才把本身標記爲可讀,防止讀回退
  • replica memstore過大致使寫阻塞
    上面說過,replica的region中memstore是不會主動flush的,只有收到主region的flush操做,纔會去flush。同一臺RegionServer上可能有一些region replica和其餘的主region同時存在。這些replica可能因爲複製延遲(沒有收到flush marker),或者主region沒有發生flush,致使一直佔用內存不釋放。這會形成總體的內存超過水位線,致使正常的寫入被阻塞。爲了防止這個問題的出現,HBase中有一個參數叫作hbase.region.replica.storefile.refresh.memstore.multiplier,默認值是4。這個參數的意思是說,若是最大的replica region的memstore已經超過了最大的主region memstore的內存的4倍,就主動觸發一次StoreFile Refresher去更新文件列表,若是確實發生了flush,那麼replica內存裏的數據就能被釋放掉。可是,這只是解決了replication延遲致使的未flush問題,若是這個replica的主region確實沒有flush過,內存仍是不能被釋放。寫入阻塞仍是會存在

Timeline Consistency Read

不管是StoreFile Refresher仍是Internal replication,主region和replica之間的數據更新都是異步的,這就致使在replica region中讀取數據時,都不是強一致的。read replica的做者把從region replica中讀數據的一致性等級定爲Timeline Consistency。只有用戶明確表示可以接受Timeline consistency,客戶端的請求才會發往replica中。

好比說上圖中,若是客戶端是須要強一致讀,那麼客戶端的請求只會發往主region,即replica_id=0的region,他就會讀到X=3.若是他選擇了Timeline consistency讀,那麼根據配置,他的讀可能落在主上,那麼他仍然會讀到X=3,若是他的讀落在了replica_id=1的region上,由於複製延遲的存在,他就只能讀到X=2.若是落在了replica_id=2上,因爲replication鏈路出現了問題,他就只能讀到X=1。

Region replica的使用方法

服務端配置

hbase.regionserver.storefile.refresh.period

若是要使用StoreFile Refresher來作爲Region replica之間同步數據的策略,就必須把這個值設置爲一個大於0的數,即刷新storefile的間隔週期(單位爲ms)上面的章節講過,這個值要不能太大,也不能過小。

hbase.regionserver.meta.storefile.refresh.period

因爲Meta表的region replica不能經過replication來同步,因此若是要開啓meta表的region replica,必須把這個參數設成一個不爲0的值,具體做用參見上一個參數,這個參數只對meta表生效。

hbase.region.replica.replication.enabled
hbase.region.replica.replication.memstore.enabled

若是要使用Internal replication的方式在Region replica之間同步數據的策略,必須把這兩個參數都設置爲true

hbase.master.hfilecleaner.ttl

在主region發生compaction以後,被compact掉的文件會放入Achieve文件夾內,超過hbase.master.hfilecleaner.ttl時間後,文件就會被從HDFS刪除掉。而此時,可能replica region正在讀取這個文件,這會形成用戶的讀取拋錯返回。若是不想要這種狀況發生,就能夠把這個參數設爲一個很大的值,好比說3600000(一小時),總沒有讀操做須要讀一個小時了吧?

hbase.meta.replica.count

mata表的replica份數,默認爲1,即不開啓meta表的replica。若是想讓meta表有額外的一個replica,就能夠把這個值設爲2,依次類推。此參數隻影響meta表的replica份數。用戶表的replica份數是在表級別配置的,這個我後面會講

hbase.region.replica.storefile.refresh.memstore.multiplier

這個參數我在上面的章節裏有講,默認爲4

hbase.region.replica.wait.for.primary.flush

這個參數我在上面的章節裏有講,默認爲true

 

須要注意的是,開啓region replica以後,Master的balancer必定要用默認的StochasticLoadBalancer,只有這個balancer會盡可能使主region和他的replica不在同一臺機器上。其餘的balaner會無區別對待全部的region。

客戶端配置

hbase.ipc.client.specificThreadForWriting

由於當存在region replica時,當客戶端發往主region的請求超時後,會發起一個請求到replica region,當其中一個請求放回後,就無需再等待另外一個請求的結果了,一般要中斷這個請求,使用專門的的線程來發送請求,比較容易處理中斷。因此若是要使用region replica,這個參數要配爲true。

hbase.client.primaryCallTimeout.get
hbase.client.primaryCallTimeout.multiget
hbase.client.replicaCallTimeout.scan

分別對應着,get、multiget、scan時等待主region返回結果的時間。若是把這個值設爲1000ms,那麼客戶端的請求在發往主region超過1000ms還沒返回後,就會再發一個請求到replica region(若是有多個replica的話,就會同時發往多個replica)

hbase.meta.replicas.use

若是服務端上開啓了meta表的replica後,客戶端可使用這個參數來控制是否使用meta表的replica的region。

建表

在shell建表時,只需在表的屬性里加上REGION_REPLICATION => xx就能夠了,如

create 't1', 'f1', {REGION_REPLICATION => 2}

Replica的份數支持動態修改,但修改以前必須disable表

diable 't1'
alter 't1', {REGION_REPLICATION => 1}
enable 't1'

訪問有replica的表

若是能夠按請求設置一致性級別,若是把請求的一致性級別設爲Consistency.TIMELINE,即有可能讀到replica上

Get get1 = new Get(row);
get1.setConsistency(Consistency.TIMELINE);
...
ArrayList<Get> gets = new ArrayList<Get>();
gets.add(get1);
...
Result[] results = table.get(gets);

另外,用戶能夠經過Result.isStale()方法來得到返回的result是否來自主region,若是爲isStale爲false,則結果來自主region。

Result result = table.get(get);
if (result.isStale()) {
...
}

總結和建議

Region Replica功能給HBase用戶帶來了高可用的讀能力,提升了HBase的可用性,但同時也存在必定的缺點:

  • 高可用的讀基於Timeline consistency,用戶須要接受非強一致性讀才能開啓這個功能
  • 使用Replication來作數據同步意味着額外的CPU,帶寬消耗,同時根據replica的多少,可能會有數倍的memstore內存消耗
  • 讀取replica region中的block一樣會進block cache(若是表開啓了block cache的話),這意味着數倍的cache開銷
  • 客戶端Timeline consistency讀可能會把請求發往多個replica,可能帶來更多的網絡開銷

Region Replica只帶來了高可用的讀,宕機狀況下的寫,仍然取決於主region的恢復時間,所以MTTR時間並無隨着使用Region replica而改善。雖說region replica的做者在規劃中有寫計劃在宕機時把一個replica提高爲主,來優化MTTR時間,但截至目前爲止,尚未實現。

我的建議,region replica功能適合於用戶集羣規模較小,對讀可用性很是在乎,同時又能夠接受非強一致性讀的狀況下開啓。若是集羣規模較大,或者讀寫流量很是大的集羣上開啓此功能,須要留意內存使用和網絡帶寬。Memstore佔用內存太高可能會致使region頻繁刷盤,影響寫性能,同時cache容量的翻倍會致使一部分讀請求擊穿cache直接落盤,致使讀性能的降低。

雲端使用

阿里HBase目前已經在阿里雲提供商業化服務,任何有需求的用戶均可以在阿里雲端使用深刻改進的、一站式的HBase服務。雲HBase版本與自建HBase相比在運維、可靠性、性能、穩定性、安全、成本等方面均有不少的改進,更多內容歡迎你們關注 https://www.aliyun.com/product/hbase
同時,雲HBase2.0 在2018年6月6日將正式發佈,點擊瞭解更多: https://promotion.aliyun.com/ntms/act/hbase20.html

原文連接

相關文章
相關標籤/搜索