HBase2.0新功能之高可用讀-Region Replica

基于時間線一致的高可用讀(Timeline-consistent High Available Reads),又稱Region replica。早在HBase-1.2版本的時候,這個功能就已經(jīng)開發(fā)完畢了,但是還是不太穩(wěn)定,離生產(chǎn)可用級別還有一段距離,后來社區(qū)又陸陸續(xù)續(xù)修復(fù)了一些bug,比如說HBASE-18223。這些bug很多在HBase-1.4之后的版本才修復(fù),也就是說region replica功能基本上在HBase-1.4之后才穩(wěn)定下來。介于HBase-1.4版本目前實際生產(chǎn)中使用的還比較少,把region replica功能說成是HBase2.0中的新功能也不為過。

為什么需要Region Replica

在CAP理論中,HBase一直是一個CP(Consistency&Partition tolerance)系統(tǒng)。HBase一直以來都在遵循著讀寫強一致的語義。所以說雖然在存儲層,HBase依賴HDFS實現(xiàn)了數(shù)據(jù)的多副本,但是在計算層,HBase的region只能在一臺RegionServer上線提供讀寫服務(wù),來保持強一致。如果這臺服務(wù)器發(fā)生宕機時,Region需要從WAL中恢復(fù)還緩存在memstore中未刷寫成文件的數(shù)據(jù),才能重新上線服務(wù)。

RS dies -> ZK waits for heartbeat until ZK session timeout -> ZK notifies Master -> Assignment Manager running inside Master chooes new RS for the Unavailable Regions -> Logs are split -> RS are notified of their newly-assigned Regions. Region are opend and become available

由于HBase的RegionServer是使用Zookeeper與Master保持lease。為了不讓JVM GC停頓導(dǎo)致RegionServer被master“誤判”死亡,這個lease時間通常都會設(shè)置為20~30s,如果RegionServer使用的Heap比較大時,這個lease可能還會設(shè)的更長。加上宕機后,region需要re-assign,WAL可能需要recoverlease和被replay操作,一個典型的region宕機恢復(fù)時間可能長達一分鐘!這就意味著在這一分鐘內(nèi),這個region都無法被讀寫。由于HBase是一個分布式系統(tǒng),同一張表的數(shù)據(jù)可能分布在非常多的RegionServer和region里。如果這是一個大HBase集群,有100臺RegionServer機器,那么宕機一臺的話,可能只有1%的用戶數(shù)據(jù)被影響了。但是如果這是小用戶的HBase集群,一共就只有2臺RegionServer,宕機一臺意味著50%的用戶數(shù)據(jù)都在1~2分鐘之內(nèi)無法服務(wù),這是很多用戶都無法忍受的。

其實,很大一部分用戶對讀可用性的需求,可能比讀強一致的需求還要高。在故障場景下,只要保證讀繼續(xù)可用,“stale read”,即讀到之前的數(shù)據(jù)也可以接受。這就是為什么我們需要read replica這個功能。

Region Replica技術(shù)細節(jié)

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

Region Replica的設(shè)計巧妙之處在于,額外的region副本并不意味著數(shù)據(jù)又會多出幾個副本。這些region replica在RegionServer上open時,使用的是和主region相同的HDFS目錄。也就是說主region里有多少HFile,那么在region replica中,這些數(shù)據(jù)都是可見的,都是可以讀出來的。

region replica相對于主region,有一些明顯的不同:

  • 首先,region replica是不可寫的。這其實很容易理解,如果region replica也可以寫的話,那么同一個region會在多個regionserver上被寫入,連主region上的強一致讀寫都沒法保證了。
  • 再次,region replica是不能被split和merge的。region replica是主region的附屬品,任何發(fā)向region replica的split和merge請求都會被拒絕掉。只有當主region split/merge時,才會把這些region replica從meta表中刪掉,建立新生成region的region的replica。

replica之間的數(shù)據(jù)同步

那么,既然region replica不能接受寫,它打開之后,怎么讓新寫入的數(shù)據(jù)變的可見呢?這里,region replica有兩種更新數(shù)據(jù)的方案:

1. 定期的StoreFile Refresher

這個方案非常好理解,region replica定期檢查一下它自己對應(yīng)的HDFS目錄,如果發(fā)現(xiàn)文件有變動,比如說flush下來新的文件,文件被compaction掉,它就刷新一下自己的文件列表,這個過程非常像compaction完成之后刪除被compact掉的文件和加入新的文件的流程。StoreFile Refresher方案非常簡單,只需要在RegionServer中起一個定時執(zhí)行的任務(wù),定期去檢查一下它上面的region哪些是region replica,哪些到了設(shè)置好的刷新周期,然后刷新就可以了。但這個方案缺點也十分明顯,主region寫入的數(shù)據(jù),只有當flush下來后,才能被region replica看到。而且storeFile Refresher本身還有一個刷新的周期,設(shè)的太短了,list文件列表對NN的沖擊太頻繁,設(shè)的太長,就會造成數(shù)據(jù)長時間在region replica中都不可見。

2. Internal Replication

我們知道,HBase是有replication鏈路的,支持把一個HBase集群的數(shù)據(jù)通過replication復(fù)制到另外一個集群。那么,同樣的原理,可以在HBase集群內(nèi)部建立一條replication通道,把一個Server上的主region的數(shù)據(jù),復(fù)制到另一個Server的region replica上。那么region replica接收到這些數(shù)據(jù)之后,會把他們寫入memstore中。對,你沒看錯,剛才我說了region replica是不接受寫的,這是指replica不接受來自客戶端的寫,如果來自主region的replication的數(shù)據(jù),它還是會寫入memstore的。

但是,這個寫和普通的寫有很明顯的區(qū)別。

第一個,replica region在寫入來自主region的時候,是不寫WAL的,因為這些數(shù)據(jù)已經(jīng)在主region所在的WAL中持久化了,replica中無需再次落盤。

第二個,replica region的memstore中的數(shù)據(jù)是不會被flush成HFile。HBase的replication是基于復(fù)制WAL文件實現(xiàn)的,那么在主region進行flush時,也會寫入特殊的標記Flush Marker。當region replica收到這樣的標記時,就直接會把所有memstore里的數(shù)據(jù)丟掉,再做一次HDFS目錄的刷新,把主region剛剛刷下去的那個HFile include進來。同樣,如果主region發(fā)生了compaction,也會寫入相應(yīng)的Compaction Marker。讀到這樣的標記后,replica region也會做類似的動作。

Internal replication加快了數(shù)據(jù)在region replica中的可見速度。通過replication方案,只要replication本身不發(fā)生阻塞和延遲,region replica中的數(shù)據(jù)可以做到和主region只差幾百ms。但是,replication方案本身也存在幾個問題:

  • META表無法通過replication來同步數(shù)據(jù)

如果給meta表開了region replica功能,meta表主region和replica之間的數(shù)據(jù)同步,只能通過定期的StoreFile Refresher機制。因為HBase的replication機制中會過濾掉meta表的數(shù)據(jù)。

  • 需要消耗額外的CPU和網(wǎng)絡(luò)帶寬來做Replication

由于region replica的數(shù)據(jù)同步需要,需要在HBase集群內(nèi)部建立replication通道,而且有幾個replica,就意味著需要從主region發(fā)送幾份數(shù)據(jù)。這會增加RegionServer的CPU使用,同時在server之間復(fù)制數(shù)據(jù)還需要占用帶寬

  • 寫memstore需要額外的內(nèi)存開銷

為了讓replica region的數(shù)據(jù)缺失的內(nèi)容盡量的少,主region的數(shù)據(jù)會通過replication發(fā)送到replica中,這些數(shù)據(jù)都會保存在memstore中。也就是說同樣的一份數(shù)據(jù),會同時存在主region的memstore中,也會存在replica region的memstore中。replica的數(shù)量是幾,那么memstore的內(nèi)存使用量就是幾倍。

下面的兩個問題雖然可以通過配置一些參數(shù)解決,但一旦參數(shù)沒有配對,就會產(chǎn)生這樣的問題。

  • 在replica region failover后,讀到的數(shù)據(jù)可能會回退

假設(shè)一個情況。客戶端寫入X=1,主region發(fā)生flush,X=1刷在了HFile中,然后客戶端繼續(xù)寫入X=2,X=3,那么在主region的memstore中X=3。同時,通過replication,X=2,X=3也被復(fù)制到了replica region的memstore中。如果客戶端去replica中去讀取X的數(shù)據(jù),也能讀到3。但是由于replica region memstore中的數(shù)據(jù)是不寫WAL的,也不刷盤。那么當replica所在的機器宕機后,它是沒有任何數(shù)據(jù)恢復(fù)流程的,他會直接在其他RegionServer上線。上線后它只能讀取HFile,無法感知主region memstore里的數(shù)據(jù)。這時如果客戶端來replica上讀取數(shù)據(jù),那么他只會讀到HFile中的X=1。也就是說之前客戶端可以讀到X=3,但后來卻只能讀到X=1了,數(shù)據(jù)出現(xiàn)了回退。為了避免出現(xiàn)這樣的問題,可以配置一個hbase.region.replica.wait.for.primary.flush=true的參數(shù),replica region上線后,會被標記為不可讀,同時它會去觸發(fā)一次主region的flush操作。只有收到主region的flush marker之后,replica才把自己標記為可讀,防止讀回退。

  • replica memstore過大導(dǎo)致寫阻塞

上面說過,replica的region中memstore是不會主動flush的,只有收到主region的flush操作,才會去flush。同一臺RegionServer上可能有一些region replica和其他的主region同時存在。這些replica可能由于復(fù)制延遲(沒有收到flush marker),或者主region沒有發(fā)生flush,導(dǎo)致一直占用內(nèi)存不釋放。這會造成整體的內(nèi)存超過水位線,導(dǎo)致正常的寫入被阻塞。為了防止這個問題的出現(xiàn),HBase中有一個參數(shù)叫做hbase.region.replica.storefile.refresh.memstore.multiplier,默認值是4。這個參數(shù)的意思是說,如果最大的replica region的memstore已經(jīng)超過了最大的主region memstore的內(nèi)存的4倍,就主動觸發(fā)一次StoreFile Refresher去更新文件列表,如果確實發(fā)生了flush,那么replica內(nèi)存里的數(shù)據(jù)就能被釋放掉。但是,這只是解決了replication延遲導(dǎo)致的未flush問題,如果這個replica的主region確實沒有flush過,內(nèi)存還是不能被釋放。寫入阻塞還是會存在。

Timeline Consistency Read

無論是StoreFile Refresher還是Internal replication,主region和replica之間的數(shù)據(jù)更新都是異步的,這就導(dǎo)致在replica region中讀取數(shù)據(jù)時,都不是強一致的。read replica的作者把從region replica中讀數(shù)據(jù)的一致性等級定為Timeline Consistency。只有用戶明確表示能夠接受Timeline consistency,客戶端的請求才會發(fā)往replica中。

比如說上圖中,如果客戶端是需要強一致讀,那么客戶端的請求只會發(fā)往主region,即replica_id=0的region,他就會讀到X=3。如果他選擇了Timeline consistency讀,那么根據(jù)配置,他的讀可能落在主上,那么他仍然會讀到X=3,如果他的讀落在了replica_id=1的region上,因為復(fù)制延遲的存在,他就只能讀到X=2。如果落在了replica_id=2上,由于replication鏈路出現(xiàn)了問題,他就只能讀到X=1。

Region replica的使用方法

服務(wù)端配置

hbase.regionserver.storefile.refresh.period

如果要使用StoreFile Refresher來做為Region replica之間同步數(shù)據(jù)的策略,就必須把這個值設(shè)置為一個大于0的數(shù),即刷新storefile的間隔周期(單位為ms)上面的章節(jié)講過,這個值要不能太大,也不能太小。

hbase.regionserver.meta.storefile.refresh.period

由于Meta表的region replica不能通過replication來同步,所以如果要開啟meta表的region replica,必須把這個參數(shù)設(shè)成一個不為0的值,具體作用參見上一個參數(shù),這個參數(shù)只對meta表生效。

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

如果要使用Internal replication的方式在Region replica之間同步數(shù)據(jù)的策略,必須把這兩個參數(shù)都設(shè)置為true。

hbase.master.hfilecleaner.ttl

在主region發(fā)生compaction之后,被compact掉的文件會放入Archieve文件夾內(nèi),超過hbase.master.hfilecleaner.ttl時間后,文件就會被從HDFS刪除掉。而此時,可能replica region正在讀取這個文件,這會造成用戶的讀取拋錯返回。如果不想要這種情況發(fā)生,就可以把這個參數(shù)設(shè)為一個很大的值,比如說3600000(一小時),總沒有讀操作需要讀一個小時了吧?

hbase.meta.replica.count

mata表的replica份數(shù),默認為1,即不開啟meta表的replica。如果想讓meta表有額外的一個replica,就可以把這個值設(shè)為2,依次類推。此參數(shù)只影響meta表的replica份數(shù)。用戶表的replica份數(shù)是在表級別配置的

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

默認為4。如果最大的replica region的memstore已經(jīng)超過了最大的主region memstore的內(nèi)存的4倍,就主動觸發(fā)一次StoreFile Refresher去更新文件列表

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

replica region上線后,會被標記為不可讀,同時它會去觸發(fā)一次主region的flush操作。只有收到主region的flush marker之后,replica才把自己標記為可讀,防止讀回退

需要注意的是,開啟region replica之后,Master的balancer一定要用默認的StochasticLoadBalancer,只有這個balancer會盡量使主region和他的replica不在同一臺機器上。其他的balaner會無區(qū)別對待所有的region。

客戶端配置

hbase.ipc.client.specificThreadForWriting

當存在region replica時,當客戶端發(fā)往主region的請求超時后,會發(fā)起一個請求到replica region,當其中一個請求放回后,就無需再等待另一個請求的結(jié)果了,通常要中斷這個請求,使用專門的的線程來發(fā)送請求,比較容易處理中斷。所以如果要使用region replica,這個參數(shù)要配為true。

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

分別對應(yīng)著,get、multiget、scan時等待主region返回結(jié)果的時間。如果把這個值設(shè)為1000ms,那么客戶端的請求在發(fā)往主region超過1000ms還沒返回后,就會再發(fā)一個請求到replica region(如果有多個replica的話,就會同時發(fā)往多個replica)。

hbase.meta.replicas.use

如果服務(wù)端上開啟了meta表的replica后,客戶端可以使用這個參數(shù)來控制是否使用meta表的replica的region。

建表

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

> create 't1', 'f1', {REGION_REPLICATION => 2}
# Replica的份數(shù)支持動態(tài)修改,但修改之前必須disable表。
> diable 't1'
> alter 't1', {REGION_REPLICATION => 1}
> enable 't1'

訪問有replica的表

如果可以按請求設(shè)置一致性級別,如果把請求的一致性級別設(shè)為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,則結(jié)果來自主region。

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

總結(jié)和建議

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

  • 高可用的讀基于Timeline consistency,用戶需要接受非強一致性讀才能開啟這個功能

  • 使用Replication來做數(shù)據(jù)同步意味著額外的CPU,帶寬消耗,同時根據(jù)replica的多少,可能會有數(shù)倍的memstore內(nèi)存消耗

  • 讀取replica region中的block同樣會進block cache(如果表開啟了block cache的話),這意味著數(shù)倍的cache開銷

  • 客戶端Timeline consistency讀可能會把請求發(fā)往多個replica,可能帶來更多的網(wǎng)絡(luò)開銷

Region Replica只帶來了高可用的讀,宕機情況下的寫,仍然取決于主region的恢復(fù)時間,因此MTTR時間(平均恢復(fù)時間)并沒有隨著使用Region replica而改善。雖然說region replica的作者在規(guī)劃中有寫計劃在宕機時把一個replica提升為主,來優(yōu)化MTTR時間,但截至目前為止,還沒有實現(xiàn)。

region replica功能適合于用戶集群規(guī)模較小,對讀可用性非常在意,同時又可以接受非強一致性讀的情況下開啟。如果集群規(guī)模較大,或者讀寫流量非常大的集群上開啟此功能,需要留意內(nèi)存使用和網(wǎng)絡(luò)帶寬。Memstore占用內(nèi)存過高可能會導(dǎo)致region頻繁刷盤,影響寫性能,同時cache容量的翻倍會導(dǎo)致一部分讀請求擊穿cache直接落盤,導(dǎo)致讀性能的下降。

轉(zhuǎn)載:HBase技術(shù)社區(qū)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考:http://www.itdecent.cn/p/569106a3008f 最近在逐步跟進Hbase的相關(guān)...
    博弈史密斯閱讀 931評論 1 1
  • 最近在逐步跟進Hbase的相關(guān)工作,由于之前對Hbase并不怎么了解,因此系統(tǒng)地學(xué)習(xí)了下Hbase,為了加深對Hb...
    飛鴻無痕閱讀 50,588評論 19 272
  • 比特科技: 存儲、數(shù)據(jù)庫、大數(shù)據(jù)技術(shù) ? HBase原理和設(shè)計 http://www.bitstech.net/...
    葡萄喃喃囈語閱讀 765評論 0 11
  • 簡介 [HBase]——Hadoop Database的簡稱,Google BigTable的另一種開源實現(xiàn)方式,...
    高廣超閱讀 2,553評論 1 27
  • 簡介 HBase —— Hadoop Database的簡稱,Google BigTable的另一種開源實現(xiàn)方式,...
    尼小摩閱讀 584評論 0 3

友情鏈接更多精彩內(nèi)容