摘要: 基於時間線一致的高可用讀(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
在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 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。網絡
那麼,既然region replica不能接受寫,它打開以後,怎麼讓新寫入的數據變的可見呢?這裏,region replica有兩種更新數據的方案:運維
這個方案很是好理解,region replica按期檢查一下它本身對應的HDFS目錄,若是發現文件有變更,好比說flush下來新的文件,文件被compaction掉,它就刷新一下本身的文件列表,這個過程很是像compaction完成以後刪除被compact掉的文件和加入新的文件的流程。StoreFile Refresher方案很是簡單,只須要在RegionServer中起一個定時執行的Chroe,按期去檢查一下它上面的region哪些是region replica,哪些到了設置好的刷新週期,而後刷新就能夠了。但這個方案缺點也十分明顯,主region寫入的數據,只有當flush下來後,才能被region replica看到。並且storeFile Refresher自己還有一個刷新的週期,設的過短了,list文件列表對NN的衝擊太頻繁,設的太長,就會形成數據長時間在region replica中都不可見異步
咱們知道,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方案自己也存在幾個問題:
下面的兩個問題雖然能夠經過配置一些參數解決,可是列在這裏,仍然須要注意,由於一旦參數沒有配對,就會產生這樣的問題。
不管是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。
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'
若是能夠按請求設置一致性級別,若是把請求的一致性級別設爲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的可用性,但同時也存在必定的缺點:
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