HBase服務(wù)高可用之路的探索

[toc]

HBase服務(wù)高可用之路的探索

一、背景

這里的高可用并不是指HBase本身的高可用機(jī)制。而是HBase主備雙服務(wù)的高可用,線上業(yè)務(wù)依賴于主備HBase集群來提供數(shù)據(jù)支持,主集群首要的任務(wù)時(shí)負(fù)責(zé)數(shù)據(jù)的讀寫,備集群只是為了容災(zāi)。

對(duì)于HBase主備服務(wù)高可用方案的調(diào)研,團(tuán)隊(duì)內(nèi)部從未停止過探索的步伐。從最初手動(dòng)切換Nginx的域名映射,到統(tǒng)計(jì)異常日志占比,然后進(jìn)行自動(dòng)的域名切換。那時(shí)候我們面臨的狀況是,主集群大量讀寫超時(shí)、甚至服務(wù)不可用,造成業(yè)務(wù)方接口無法為用戶提供正常的線上業(yè)務(wù)時(shí),HBase運(yùn)維小伙伴們才能感知到HBase集群的異常狀態(tài),手動(dòng)切換流量至備集群,從而在服務(wù)恢復(fù)的時(shí)間內(nèi),造成了無法容忍的損失。

針對(duì)舊方案的種種痛點(diǎn),以及受微服務(wù)中熔斷概念的啟發(fā),最終選擇集成了餓了么提供的一個(gè)熔斷框架——doctor,實(shí)現(xiàn)了HBase主集群服務(wù)查詢異常時(shí),查詢流量能夠及時(shí)、自動(dòng)、無感知地進(jìn)行切換到備集群。

二、HBase熔斷API目前已實(shí)現(xiàn)的功能

  • 基于happybase封裝的HBase讀寫操作的基本功能API
  • 錯(cuò)誤請(qǐng)求比例到達(dá)一定閾值,觸發(fā)熔斷機(jī)制,主備集群自動(dòng)無感知切換
  • 主備切換后,熔斷的恢復(fù)機(jī)制,將自動(dòng)感知主集群是否可以正常提供線上服務(wù)
  • 服務(wù)異常切換時(shí),精確到單個(gè)接口的微信預(yù)警

三、關(guān)于熔斷

一般在微服架構(gòu)中,有一個(gè)組件角色叫熔斷器。顧名思義,熔斷器起的作用就是在特定的場(chǎng)景下關(guān)掉當(dāng)前的通路,從而起到保護(hù)整個(gè)系統(tǒng)的效果。

在微服務(wù)架構(gòu)中,一般我們的獨(dú)立服務(wù)是比較多的,每個(gè)獨(dú)立服務(wù)之間劃分責(zé)任邊界,并通過約定協(xié)議接口來進(jìn)行通信。當(dāng)我們的調(diào)用鏈路復(fù)雜依賴多時(shí),很可能會(huì)發(fā)生雪崩效應(yīng)。

假設(shè)有這么一個(gè)場(chǎng)景,有A, B, C, D四個(gè)獨(dú)立服務(wù),A會(huì)依賴B,C,D;當(dāng)D發(fā)生負(fù)載過高或網(wǎng)絡(luò)異常等導(dǎo)致響應(yīng)過慢或超時(shí)時(shí),很可能A會(huì)因此堆積過多的等待鏈接,從而導(dǎo)致A的狀態(tài)也轉(zhuǎn)為異常,后面依賴到A的其他服務(wù)跟著發(fā)生鏈?zhǔn)椒磻?yīng),這將會(huì)導(dǎo)致大面積的服務(wù)不可用,即使本來是一些沒有依賴到B,C,D的服務(wù)。如下圖所示:

img

這不是我們希望看到的結(jié)果,所以這個(gè)時(shí)候熔斷器可以派上用場(chǎng)。最簡(jiǎn)單的做法,我們?yōu)槊總€(gè)依賴服務(wù)配置一個(gè)熔斷器開關(guān),正常情況下是關(guān)閉的,也就是可以正常發(fā)起請(qǐng)求;當(dāng)請(qǐng)求失敗(超時(shí)或者其他異常)次數(shù)超過預(yù)設(shè)值時(shí),熔斷器自動(dòng)打開,這時(shí)所有經(jīng)過這個(gè)熔斷器的請(qǐng)求都會(huì)直接返回失敗,并沒有真正到達(dá)所依賴的服務(wù)上。這時(shí)服務(wù)A本身仍然是能正常服務(wù)的。當(dāng)然,我們針對(duì)失敗請(qǐng)求的策略,并沒有這么簡(jiǎn)單粗暴。

四、借鑒HBase熔斷切換在有贊團(tuán)隊(duì)內(nèi)的實(shí)踐

HBase 雖然提供了 HBase Replication 機(jī)制,用來實(shí)現(xiàn)集群間單方向的異步數(shù)據(jù)復(fù)制,線上雖然部署了雙集群,備集群 SSD 分組和主集群 SSD 分組有相同的配置。當(dāng)主集群因?yàn)榇疟P,網(wǎng)絡(luò),或者其他業(yè)務(wù)突發(fā)流量影響導(dǎo)致某些 RegionServer 甚至集群不可用的時(shí)候,就需要提供備集群繼續(xù)提供服務(wù),備集群的數(shù)據(jù)可能會(huì)因?yàn)?HBase Replication 機(jī)制的延遲,相比主集群的數(shù)據(jù)是滯后的,按照我們集群目前的規(guī)模統(tǒng)計(jì),平均延遲在 100ms 以內(nèi)。所以為了達(dá)到高可用,業(yè)務(wù)方只能接受復(fù)制延遲,放棄強(qiáng)一致性,選擇最終一致性和高可用性。

有贊技術(shù)團(tuán)隊(duì)對(duì)于HBase高可用服務(wù)接口的設(shè)計(jì),同樣使用了熔斷的概念,只是其底層的熔斷技術(shù)依賴于java微服務(wù)中的Hystrix框架。其簡(jiǎn)單的客戶端高可用方案原理圖如下所示:

img

業(yè)務(wù)方是不想感知到后端服務(wù)的狀態(tài),也就是說在客戶端層面,他們只希望一個(gè) Put 或者 Get 請(qǐng)求正常送達(dá)且返回預(yù)期的數(shù)據(jù)即可,那么就需要高可用客戶端封裝一層降級(jí),熔斷處理的邏輯,這里有贊采用 Hystrix 做為底層熔斷處理引擎,在引擎之上封裝了 HBase 的基本 API,用戶只需要配置主備機(jī)房的 ZK 地址即可,所有的降級(jí)熔斷邏輯最終封裝到 ha-hbase-client 中。

以上文字描述摘選自有贊的技術(shù)博客,詳情可以參考鏈接,有贊 HBase 技術(shù)實(shí)踐:讀流程解析與優(yōu)化

五、熔斷在我們的HBase接口服務(wù)中的應(yīng)用

與微服務(wù)中的熔斷概念類比,我們也可以把我們的主備HBase集群看做是兩個(gè)獨(dú)立的服務(wù),而我們的業(yè)務(wù)方則需要依賴這一個(gè)HBase服務(wù),對(duì)外提供自己的服務(wù)。這里稍微有一點(diǎn)不一樣的地方是,我們HBase服務(wù)的角色是由兩個(gè)集群來擔(dān)任,正常情況下,只有一個(gè)集群來承擔(dān)起HBase服務(wù)的功能。HBase熔斷切換的簡(jiǎn)單示例如下:

hbase-rongduan
  • 正常狀態(tài)下APP的請(qǐng)求通過熔斷器只會(huì)落在主集群上
  • 當(dāng)發(fā)生例如超時(shí)異常時(shí),在指定的窗口期內(nèi),錯(cuò)誤的請(qǐng)求數(shù)達(dá)到一定的閾值,熔斷器就會(huì)認(rèn)為,HBase主集群處于非正常狀態(tài),此時(shí),在服務(wù)的最小恢復(fù)時(shí)間內(nèi),所有的請(qǐng)求通過熔斷器,會(huì)落在備集群中。而熔斷器與主集群的通信鏈路則是被鎖定的。
  • 過了指定的服務(wù)的最小恢復(fù)時(shí)間,還未到達(dá)服務(wù)的最大恢復(fù)時(shí)間時(shí),APP的請(qǐng)求會(huì)隨機(jī)落在主備集群,當(dāng)主集群的請(qǐng)求依舊異常時(shí),熔斷器會(huì)繼續(xù)鎖住與主集群的通信鏈路。直至?xí)r間達(dá)到服務(wù)的最大恢復(fù)時(shí)間,熔斷器才會(huì)繼續(xù)嘗試把請(qǐng)求落在主集群上。

六、HBase熔斷工作的流程圖

此處,我們以get請(qǐng)求舉例,用流程圖來演示我們的HBase查詢?nèi)蹟嗯c主備切換機(jī)制。

Untitled Diagram

七、滾動(dòng)計(jì)數(shù)RollingNumber

如果想要更深入地理解主備熔斷切換的設(shè)計(jì)理念,那么,需要優(yōu)先理解一下滾動(dòng)窗口計(jì)數(shù),以及閾值判斷相關(guān)的一些內(nèi)容。doctor熔斷框架的設(shè)計(jì)中,依賴于滑動(dòng)窗口時(shí)間內(nèi)的滾動(dòng)計(jì)數(shù),來進(jìn)行閾值計(jì)算,從而判斷當(dāng)前服務(wù)的健康狀況。

1. 滾動(dòng)計(jì)數(shù)的概念

滾動(dòng)計(jì)數(shù)的行為類似于一個(gè)擁有固定長(zhǎng)度的先進(jìn)先出隊(duì)列,或者時(shí)間戳序列上的滑動(dòng)窗口。一個(gè)滾動(dòng)計(jì)數(shù)的值是隊(duì)列元素的和,時(shí)鐘結(jié)束時(shí),最后一個(gè)元素的值將滾動(dòng)到先前的位置,傳遞了一個(gè)時(shí)間粒度,這個(gè)時(shí)間粒度,默認(rèn)1s。下面將借助一個(gè)小例子,具體來說明這種機(jī)制。

示例中我們使用的滑動(dòng)窗口長(zhǎng)度為4,移位的時(shí)間戳粒度為1s??偟臅r(shí)間周期是20s。

  1. 初始時(shí)創(chuàng)建一個(gè)填充4個(gè)0元素的列表,這是整個(gè)滾動(dòng)計(jì)數(shù)行為的最開始的狀態(tài)。
[0, 0, 0, 0]
  1. 在第一個(gè)滑動(dòng)窗口的時(shí)間周期(4s)內(nèi),假如第一秒內(nèi)處理了3個(gè)請(qǐng)求,第二秒內(nèi)處理了2個(gè)請(qǐng)求,第三秒內(nèi)處理了5個(gè)請(qǐng)求,第四秒內(nèi)處理了4個(gè)請(qǐng)求,那么,此時(shí)列表中的狀態(tài)如下,需要計(jì)算的指標(biāo)從上至下依次為,請(qǐng)求的總數(shù),失敗請(qǐng)求的總數(shù)失敗請(qǐng)求所占的比例
[3, 2, 5, 4]
+--- 14 ---+
+---  7 ---+
+--- 0.5 ---+

# 則這一個(gè)滑動(dòng)窗口的時(shí)間周期內(nèi)的請(qǐng)求數(shù)總和為14,假如失敗的請(qǐng)求總數(shù)為7,那么,此時(shí)間周期內(nèi)的失敗比例為7 / 14 = 0.5
  1. 假如在第五秒處理的請(qǐng)求為4,滑動(dòng)窗口需要前移一個(gè)時(shí)間粒度,此時(shí)列表中的狀態(tài)如下:
3, [2, 5, 4, 4]
   +--- 15 ---+
   +---  3 ---+
   +--- 0.2 ---+
  
# 則這一個(gè)滑動(dòng)窗口的時(shí)間周期內(nèi)的請(qǐng)求數(shù)總和為15,假如失敗的請(qǐng)求總數(shù)為3,那么,此時(shí)間周期內(nèi)的失敗比例為3 / 15 = 0.2
  1. 依次類推,第m個(gè)時(shí)間周期內(nèi)
3, 2, 5, 4, 4,..., 6, [8, 2, 4, 4], 5 ... (<= time passing 20s)
                      +--- 18 ---+
                                        +--- 6 ---+
                                        +--- 0.33 ---+
# 則第m個(gè)滑動(dòng)窗口的時(shí)間周期內(nèi)的請(qǐng)求數(shù)總和為18,假如失敗的請(qǐng)求總數(shù)為6,那么,此時(shí)間周期內(nèi)的失敗比例為6 / 18 = 0.33

八、深入理解熔斷在我們HBase接口服務(wù)中的工作機(jī)制

1. HBase熔斷機(jī)制工作的核心參數(shù)

讀寫閾值判定的配置示例


READ_DOCTOR_CONF = dict(
            # Metrics settings.
            METRICS_GRANULARITY=1,  # sec
            METRICS_ROLLINGSIZE=10,
            # Health settings.
            HEALTH_MIN_RECOVERY_TIME=10,  # sec
            HEALTH_MAX_RECOVERY_TIME=2 * 10,  # sec
            HEALTH_THRESHOLD_REQUEST=5 * 1,  # per `INTERVAL`
            HEALTH_THRESHOLD_TIMEOUT=0.01,  # percentage per `INTERVAL`
            HEALTH_THRESHOLD_SYS_EXC=0.01,  # percentage per `INTERVAL`
            HEALTH_THRESHOLD_UNKWN_EXC=0.01,  # percentage per `INTERVAL`
     )
WRITE_DOCTOR_CONF = dict(
            # Metrics settings.
            METRICS_GRANULARITY=3,  # sec
            METRICS_ROLLINGSIZE=20,
            # Health settings.
            HEALTH_MIN_RECOVERY_TIME=20,  # sec
            HEALTH_MAX_RECOVERY_TIME=2 * 60,  # sec
            HEALTH_THRESHOLD_REQUEST=10 * 1,  # per `INTERVAL`
            HEALTH_THRESHOLD_TIMEOUT=0.5,  # percentage per `INTERVAL`
            HEALTH_THRESHOLD_SYS_EXC=0.5,  # percentage per `INTERVAL`
            HEALTH_THRESHOLD_UNKWN_EXC=0.5,  # percentage per `INTERVAL`
     )

核心參數(shù)解讀

  • METRICS_GRANULARITY:滾動(dòng)計(jì)數(shù)中窗口移位的時(shí)間粒度
  • METRICS_ROLLINGSIZE:滾動(dòng)計(jì)數(shù)中滑動(dòng)窗口的長(zhǎng)度
  • HEALTH_MIN_RECOVERY_TIME:服務(wù)發(fā)生異常時(shí)的最小恢復(fù)時(shí)間
  • HEALTH_MAX_RECOVERY_TIME:服務(wù)發(fā)生異常時(shí)的最大恢復(fù)時(shí)間
  • HEALTH_THRESHOLD_REQUEST:此參數(shù)用于控制是否需要進(jìn)行錯(cuò)誤閾值計(jì)算
  • HEALTH_THRESHOLD_TIMEOUT:發(fā)生超時(shí)異常的請(qǐng)求數(shù)與請(qǐng)求總數(shù)的比值,超過此設(shè)定,將觸發(fā)主備服務(wù)的熔斷切換
  • HEALTH_THRESHOLD_SYS_EXC:發(fā)生系統(tǒng)異常的請(qǐng)求數(shù)與請(qǐng)求總數(shù)的比值,超過此設(shè)定,將觸發(fā)主備服務(wù)的熔斷切換
  • HEALTH_THRESHOLD_UNKWN_EXC:發(fā)生未知異常的請(qǐng)求數(shù)與請(qǐng)求總數(shù)的比值,超過此設(shè)定,將觸發(fā)主備服務(wù)的熔斷切換

2. 判斷接口是否健康的策略

判斷當(dāng)前接口是否健康的詳細(xì)策略

  • 如果當(dāng)前api(例如:getRow的一個(gè)操作)在讀/寫主集群時(shí)嚴(yán)重出錯(cuò),則會(huì)直接去從備集群中獲取結(jié)果,在配置中設(shè)定的服務(wù)最小恢復(fù)時(shí)間內(nèi),進(jìn)一步的請(qǐng)求不會(huì)再操作主集群。
  • 如果主集群恢復(fù)健康,但是熔斷器此時(shí)并不知道主集群已經(jīng)恢復(fù)正常了,它的恢復(fù)機(jī)制是:在配置中設(shè)定的服務(wù)恢復(fù)的最小和最大時(shí)間之間,請(qǐng)求通過熔斷器,隨機(jī)去操作主備集群,如果期間訪問主集群的請(qǐng)求,有一次發(fā)生異常,熔斷器就會(huì)鎖住與主集群的通信鏈路,余下所有請(qǐng)求將會(huì)訪問備集群,繼續(xù)去等待最小間隔,然后開啟隨機(jī)訪問模式,直至達(dá)到配置設(shè)定的服務(wù)最大的恢復(fù)時(shí)間,熔斷器認(rèn)為主集群已恢復(fù)上線,之后的請(qǐng)求又會(huì)繼續(xù)操作主集群。

錯(cuò)誤閾值說明

  • 接口錯(cuò)誤包括系統(tǒng)錯(cuò)誤與操作的超時(shí)
  • 閾值是百分比,錯(cuò)誤請(qǐng)求數(shù)/總的請(qǐng)求數(shù)
  • 當(dāng)一個(gè)滑動(dòng)窗口時(shí)間內(nèi)的請(qǐng)求計(jì)數(shù)大于配置設(shè)定的THRESHOLD_REQUEST時(shí),才會(huì)觸發(fā)進(jìn)一步的錯(cuò)誤閾值檢查,然后,如果錯(cuò)誤閾值大于設(shè)定的比例時(shí),才會(huì)觸發(fā)最終的熔斷切換。

3. 健康檢查

  • 每一次請(qǐng)求經(jīng)過熔斷器,都會(huì)觸發(fā)健康檢查。

九、總結(jié)

上述便是對(duì)HBase熔斷思想所做的一個(gè)由淺入深的解釋,用于實(shí)現(xiàn)業(yè)務(wù)方訪問HBase時(shí),對(duì)于主備HBase集群的狀態(tài)切換無感知。即使主集群處于異常狀態(tài),我們依舊可以為業(yè)務(wù)方提供正常的HBase服務(wù)。

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

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

  • 前言(文末有 Java學(xué)習(xí)交流群 ,需要的可以加入~) 2011年畢玄和竹莊兩位大神將HBase引入阿里技術(shù)體系,...
    聊聊程序員閱讀 316評(píng)論 0 0
  • 數(shù)據(jù)結(jié)構(gòu)隊(duì)列集合鏈表、數(shù)組字典、關(guān)聯(lián)數(shù)組棧樹二叉樹完全二叉樹平衡二叉樹二叉查找樹(BST)紅黑樹B-,B+,B*樹...
    jackcooper閱讀 3,385評(píng)論 1 50
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,879評(píng)論 28 54
  • 信任包括信任自己和信任他人 很多時(shí)候,很多事情,失敗、遺憾、錯(cuò)過,源于不自信,不信任他人 覺得自己做不成,別人做不...
    吳氵晃閱讀 6,391評(píng)論 4 8
  • 步驟:發(fā)微博01-導(dǎo)航欄內(nèi)容 -> 發(fā)微博02-自定義TextView -> 發(fā)微博03-完善TextView和...
    dibadalu閱讀 3,429評(píng)論 1 3

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