【微服務(wù)】服務(wù)容錯機(jī)制

服務(wù)容錯概述

本文主要參考Netflix Hystrix機(jī)制潮剪。


Hystrix全局請求處理邏輯

服務(wù)容錯機(jī)制即防御性編程,Design For Failure,核心思想如下:

  • 單一服務(wù)/節(jié)點(diǎn)的故障不會嚴(yán)重破壞用戶的體驗(yàn):降級、隔離、超時等
  • 系統(tǒng)具備自動或者半自動恢復(fù)的能力:多活重試擅这、熔斷器、限流等

超時/重試

在分布式服務(wù)調(diào)用的場景中景鼠,主要解決了當(dāng)依賴服務(wù)出現(xiàn)網(wǎng)絡(luò)連接或響應(yīng)延遲時仲翎,當(dāng)前服務(wù)不用無限等待的問題。
可以通過設(shè)置RPC、Redis谭确、DB等調(diào)用的超時時間(一般可以設(shè)置為服務(wù)響應(yīng)的99分位),及時釋放關(guān)鍵資源票渠,避免耗盡系統(tǒng)資源逐哈,導(dǎo)致系統(tǒng)不可用。

超時傳遞:從網(wǎng)關(guān)入口進(jìn)行傳遞鏈路超時问顷,以及請求消耗后的超時昂秃;

  • RPC中通過Metadata傳遞
  • HTTP接口通過header傳遞,然后通過語言內(nèi)超時機(jī)制保證接口的超時處理杜窄;

重試:一般和超時結(jié)合使用肠骆,主要用于對下游服務(wù)有強(qiáng)依賴的場景,通過重試增加數(shù)據(jù)的可靠性塞耕。同步重試次數(shù)不宜過多蚀腿,避免影響接口性能。

限流

限流主要用于下游服務(wù)容量有限扫外,在面對流量激增(惡意刷子或者節(jié)日大促)時候壓力過大導(dǎo)致拒絕服務(wù)的場景:通過犧牲一部分人莉钙,來保證大部分人的體驗(yàn)(服務(wù)整體可用)。

常見的限流分為:

  • 控制并發(fā)數(shù):連接池筛谚、線程池等
  • 控制流量:漏洞和令牌桶

漏桶:由于恒定速率處理請求磁玉,對于突發(fā)流量不是很友好。
相當(dāng)于請求先進(jìn)入到桶中(等待隊列)驾讲,當(dāng)桶滿了以后開始丟棄請求蚊伞;
水以恒定的速度從桶中流出(處理)請求。

漏桶

令牌桶

  • 和漏桶一樣吮铭,基于固定速率放入时迫,但是由于令牌桶是允許任意速度取出的,所以可以容忍瞬間的流量激增:但是總的時間窗口內(nèi)的令牌數(shù)是固定的
  • 假設(shè)限制X的QPS谓晌,桶的大小為單位時間內(nèi)允許的最大流量别垮,即這里的X(單位時間這里是秒)
  • 可以分為初始值為空桶或者滿的桶兩種做法
  • 以1/X的速率向桶中放入令牌,桶滿了則無法放入
  • 每個請求拿走1個令牌扎谎,所以單位時間內(nèi)最多拿走桶的大小個令牌碳想,達(dá)到限流目的


    令牌桶

分布式限流

關(guān)鍵為限流操作需要為原子化,可以使用redis+lua腳本來保證原子性毁靶。

-- 令牌桶限流: 不支持預(yù)消費(fèi), 初始桶是滿的
-- KEYS[1]  string  限流的key

-- ARGV[1]  int     桶最大容量
-- ARGV[2]  int     每次添加令牌數(shù)
-- ARGV[3]  int     令牌添加間隔(秒)
-- ARGV[4]  int     當(dāng)前時間戳

local bucket_capacity = tonumber(ARGV[1])
local add_token = tonumber(ARGV[2])
local add_interval = tonumber(ARGV[3])
local now = tonumber(ARGV[4])

-- 保存上一次更新桶的時間的key
local LAST_TIME_KEY = KEYS[1].."_time";         
-- 獲取當(dāng)前桶中令牌數(shù)
local token_cnt = redis.call("get", KEYS[1])    
-- 桶完全恢復(fù)需要的最大時長
local reset_time = math.ceil(bucket_capacity / add_token) * add_interval;

if token_cnt then   -- 令牌桶存在
    -- 上一次更新桶的時間
    local last_time = redis.call('get', LAST_TIME_KEY)
    -- 恢復(fù)倍數(shù)
    local multiple = math.floor((now - last_time) / add_interval)
    -- 恢復(fù)令牌數(shù)
    local recovery_cnt = multiple * add_token
    -- 確保不超過桶容量
    local token_cnt = math.min(bucket_capacity, token_cnt + recovery_cnt) - 1
    
    if token_cnt < 0 then
        return -1;
    end
    
    -- 重新設(shè)置過期時間, 避免key過期
    redis.call('set', KEYS[1], token_cnt, 'EX', reset_time)                     
    redis.call('set', LAST_TIME_KEY, last_time + multiple * add_interval, 'EX', reset_time)
    return token_cnt
    
else    -- 令牌桶不存在
    token_cnt = bucket_capacity - 1
    -- 設(shè)置過期時間避免key一直存在
    redis.call('set', KEYS[1], token_cnt, 'EX', reset_time);
    redis.call('set', LAST_TIME_KEY, now, 'EX', reset_time + 1);    
    return token_cnt    
end

偽代碼邏輯:

如果令牌桶存在(key A)
- 獲取上次桶放入令牌的時間(key B)和當(dāng)前時間的差距(比如50ms)胧奔,則放入50*1/X個令牌(加上并且判斷不超過容量X)
- 從桶中拿走一個令牌,判斷是否被限流
桶不存在:則設(shè)置key A = X-1(容量-本次使用)预吆,key B=當(dāng)前時間龙填,EX時間均為時間窗口,即1s

熔斷器

在工程實(shí)踐中,由于一些系統(tǒng)異逞乙牛或者網(wǎng)絡(luò)異常導(dǎo)致的調(diào)用失敗扇商,可能需要一段時間才能恢復(fù)。
而這段時間內(nèi)的請求會占用寶貴的系統(tǒng)資源宿礁,并且由于持續(xù)失敗可能將資源消耗殆盡(比如db案铺、redis連接池),從而導(dǎo)致系統(tǒng)不可用梆靖。

所以此時能夠立即返回錯誤而不是等待超時是更好的選擇 => 熔斷器

關(guān)鍵參數(shù)配置

滑動窗口

window=“10s” - 即整個滑動窗口的大小
bucket=10 - 即bucket的數(shù)量控汉,用window/bucket可以得到單個bucket的大小為1s;滑動窗口以bucket為單位進(jìn)行滑動返吻;
ratio=0.5 - 即滑動窗口內(nèi)統(tǒng)計的總錯誤率到達(dá)50%時觸發(fā)熔斷閾值
request=100 - 即當(dāng)滑動窗口內(nèi)的請求數(shù)量過小時姑子,暫不觸發(fā)熔斷,最小值100
sleep=100ms - 即熔斷器從打開到半打開的時長

熔斷器工作機(jī)制

熔斷器狀態(tài)流向
  1. closed -> open:滑動窗口內(nèi)request > 100 && ratio > 0.5
  2. open -> half open:sleep 100ms后测僵,進(jìn)入半打開狀態(tài)
  3. half open -> closed/open:半開后會放一個請求去執(zhí)行街佑,如果失敗則繼續(xù)open,如果成功則熔斷器關(guān)閉

船艙隔離

在造船行業(yè)捍靠,往往使用此類模式對船艙進(jìn)行隔離舆乔,利用艙壁將不同的船艙隔離起來,這樣如果一個船艙破了進(jìn)水剂公,只損失一個船艙希俩,其它船艙可以不受影響。
而借鑒造船行業(yè)的經(jīng)驗(yàn)纲辽,在微服務(wù)架構(gòu)中為每個服務(wù)單獨(dú)設(shè)置資源颜武,用盡后不影響其他服務(wù):如db隔離、redis隔離拖吼、容器隔離

Fallback 回退/降級

當(dāng)請求失敗/超時/被熔斷/被限流后鳞上,會進(jìn)入Fallback邏輯:
降級邏輯:返回備用數(shù)據(jù),默認(rèn)數(shù)據(jù)吊档,本地數(shù)據(jù)(客戶端緩存)等
故障沉默 Fail-Silent:直接返回空值篙议,相應(yīng)模塊不展示(比如商品的相關(guān)推薦)
快速失敗 Fail-Fast:對于非強(qiáng)依賴的場景則直接報錯(不影響體驗(yàn)的前提下)

參考

  1. 美團(tuán)技術(shù)團(tuán)隊-服務(wù)容錯模式
  2. Spring Cloud 源碼學(xué)習(xí)之 Hystrix 熔斷器
  3. 令牌桶模式
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市怠硼,隨后出現(xiàn)的幾起案子鬼贱,更是在濱河造成了極大的恐慌,老刑警劉巖香璃,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件这难,死亡現(xiàn)場離奇詭異,居然都是意外死亡葡秒,警方通過查閱死者的電腦和手機(jī)姻乓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門嵌溢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹋岩,你說我怎么就攤上這事赖草。” “怎么了剪个?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵秧骑,是天一觀的道長。 經(jīng)常有香客問我禁偎,道長腿堤,這世上最難降的妖魔是什么阀坏? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任如暖,我火速辦了婚禮,結(jié)果婚禮上忌堂,老公的妹妹穿的比我還像新娘盒至。我一直安慰自己,他們只是感情好士修,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布枷遂。 她就那樣靜靜地躺著,像睡著了一般棋嘲。 火紅的嫁衣襯著肌膚如雪酒唉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天沸移,我揣著相機(jī)與錄音痪伦,去河邊找鬼秸架。 笑死隐绵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的壕吹。 我是一名探鬼主播蕊爵,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辉哥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了攒射?” 一聲冷哼從身側(cè)響起醋旦,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎会放,沒想到半個月后浑度,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸦概,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年箩张,在試婚紗的時候發(fā)現(xiàn)自己被綠了甩骏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡先慷,死狀恐怖饮笛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情论熙,我是刑警寧澤福青,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站脓诡,受9級特大地震影響无午,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祝谚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一宪迟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧交惯,春花似錦次泽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至只锻,卻和暖如春玖像,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背齐饮。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工捐寥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沈矿。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓上真,卻偏偏與公主長得像,于是被迫代替她去往敵國和親羹膳。 傳聞我的和親對象是個殘疾皇子睡互,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容