超時,重試,熔斷,限流

2021-09-02 18:37:24 字數 4879 閱讀 8252

[size=medium][color=black][b]1 寫在前面[/b][/color][/size]

[size=medium][color=black][b]1.1 名詞解釋[/b][/color][/size]

consumer表示服務呼叫方

provider標示服務提供方,dubbo裡面一般就這麼講。

下面的a呼叫b服務,一般是泛指呼叫b服務裡面的乙個介面。

1.2 拓撲圖

大寫字母表示不同的服務,後面的序號表示同乙個服務部署在不同機器的例項。

[img]

[size=medium][color=black][b]2 從微觀角度思考[/b][/color][/size]

[size=medium][color=black][b]2.1 超時(timeout)[/b][/color][/size]

在介面呼叫過程中,consumer呼叫provider的時候,provider在響應的時候,有可能會慢,如果provider 10s響應,那麼consumer也會至少10s才響應。如果這種情況頻度很高,那麼就會整體降低consumer端服務的效能。

這種響應時間慢的症狀,就會像一層一層波浪一樣,從底層系統一直湧到最上層,造成整個鏈路的超時。

所以,consumer不可能無限制地等待provider介面的返回,會設定乙個時間閾值,如果超過了這個時間閾值,就不繼續等待。

這個超時時間選取,一般看provider正常響應時間是多少,再追加乙個buffer即可。

2.2 重試(retry)

超時時間的配置是為了保護服務,避免consumer服務因為provider 響應慢而也變得響應很慢,這樣consumer可以盡量保持原有的效能。

但是也有可能provider只是偶爾抖動,那麼超時後直接放棄,不做後續處理,就會導致當前請求錯誤,也會帶來業務方面的損失。

那麼,對於這種偶爾抖動,可以在超時後重試一下,重試如果正常返回了,那麼這次請求就被挽救了,能夠正常給前端返回資料,只不過比原來響應慢一點。

重試時的一些細化策略:

重試可以考慮切換一台機器來進行呼叫,因為原來機器可能由於臨時負載高而效能下降,重試會更加劇其效能問題,而換一台機器,得到更快返回的概率也更大一些。

[size=medium][color=black][b]2.2.1 冪等(idempotent)[/b][/color][/size]

如果允許consumer重試,那麼provider就要能夠做到冪等。

即,同乙個請求被consumer多次呼叫,對provider產生的影響(這裡的影響一般是指某些寫入相關的操作) 是一致的。

而且這個冪等應該是服務級別的,而不是某台機器層面的,重試呼叫任何一台機器,都應該做到冪等。

2.3 熔斷(circuit break)

重試是為了應付偶爾抖動的情況,以求更多地挽回損失。

可是如果provider持續的響應時間超長呢?

如果provider是核心路徑的服務,down掉基本就沒法提供服務了,那我們也沒話說。 如果是乙個不那麼重要的服務,卻因為這個服務一直響應時間長導致consumer裡面的核心服務也拖慢,那麼就得不償失了。

單純超時也解決不了這種情況了,因為一般超時時間,都比平均響應時間長一些,現在所有的打到provider的請求都超時了,那麼consumer請求provider的平均響應時間就等於超時時間了,負載也被拖下來了。

而重試則會加重這種問題,使consumer的可用性變得更差。

因此就出現了熔斷的邏輯,也就是,如果檢查出來頻繁超時,就把consumer呼叫provider的請求,直接短路掉,不實際呼叫,而是直接返回乙個mock的值。

等provider服務恢復穩定之後,重新呼叫。

[size=medium][color=black][b]2.3.1 簡單的熔斷處理邏輯[/b][/color][/size]

可以參考netflix開源出來的hystrix的**。

2.4 限流(current limiting)

上面幾個策略都是consumer針對provider出現各種情況而設計的。

而provider有時候也要防範來自consumer的流量突變問題。

這樣乙個場景,provider是乙個核心服務,給n個consumer提供服務,突然某個consumer抽風,流量飆公升,占用了provider大部分機器時間,導致其他可能更重要的consumer不能被正常服務。

所以,provider端,需要根據consumer的重要程度,以及平時的qps大小,來給每個consumer設定乙個流量上線,同一時間內只會給a consumer提供n個執行緒支援,超過限制則等待或者直接拒絕。

[size=medium][color=black][b]2.4.1 資源隔離[/b][/color][/size]

provider可以對consumer來的流量進行限流,防止provider被拖垮。

同樣,consumer 也需要對呼叫provider的執行緒資源進行隔離。 這樣可以確保呼叫某個provider邏輯不會耗光整個consumer的執行緒池資源。

[size=medium][color=black][b]2.4.2 服務降級[/b][/color][/size]

降級服務既可以**自動判斷,也可以人工根據突發情況切換。

[size=medium][color=black][b]2.4.2.1 consumer 端[/b][/color][/size]

consumer 如果發現某個provider出現異常情況,比如,經常超時(可能是熔斷引起的降級),資料錯誤,這是,consumer可以採取一定的策略,降級provider的邏輯,基本的有直接返回固定的資料。

[size=medium][color=black][b]2.4.2.2 provider 端[/b][/color][/size]

當provider 發現流量激增的時候,為了保護自身的穩定性,也可能考慮降級服務。

比如,1,直接給consumer返回固定資料,2,需要實時寫入資料庫的,先快取到佇列裡,非同步寫入資料庫。

[size=medium][color=black][b]3 從巨集觀角度重新思考[/b][/color][/size]

巨集觀包括比a -> b 更複雜的長鏈路。

長鏈路就是 a -> b -> c -> d這樣的呼叫環境。

而且乙個服務也會多機部署,a 服務實際會存在 a1,a2,a3 …

微觀合理的問題,巨集觀未必合理。

下面的一些討論,主要想表達的觀點是:如果系統複雜了,系統的容錯配置要整體來看,整體把控,才能做到更有意義。

3.1 超時

如果a給b設定的超時時間,比b給c設定的超時時間短,那麼肯定不合理把,a超時時間到了直接結束通話,b對c支援太長超時時間沒意義。

r表示服務consumer自身內部邏輯執行時間,tab表示consumer a開始呼叫provider b到返回的時間 。

那麼那麼tab > rb + tbc 才對。

3.2 重試

重試跟超時面臨的問題差不多。

b服務一般100ms返回,所以a就給b設定了110ms的超時,而b設定了對c的一次重試,最終120ms正確返回了,但是a的超時時間比較緊,所以b對c的重試被白白浪費了。

a也可能對b進行重試,但是由於上一條我們講到的,可能c確實效能不好,每次b重試一下就ok,但是a兩次重試其實都無法正確的拿到結果。

n標示設定的重試次數

修正一下上面section的公式,tab > rb+tbc * n。

雖然這個公式本身沒什麼問題,但是,如果站在長鏈路的視角來思考,我們需要整體規劃每個服務的超時時間和重試次數,而不是僅僅公式成立即可。

比如下面情況:

a -> b -> c。

rb = 100ms,tbc=10ms

b是個核心服務,b的計算成本特別大,那麼a就應該盡量給b長一點的超時時間,而盡量不要重試呼叫b,而b如果發現c超時了,b可以多呼叫幾次c,因為重試c成本小,而重試b成本則很高。 so …

3.3 熔斷

a -> b -> c,如果c出現問題了,那麼b熔斷了,則a就不用熔斷了。

3.4 限流

b只允許a以qps<=5的流量請求,而c卻只允許b以qps<=3的qps請求,那麼b給a的設定就有點大,上游的設定依賴下游。

而且限流對qps的配置,可能會隨著服務加減機器而變化,最好是能在集群層面配置,自動根據集群大小調整。

3.5 服務降級

服務降級這個問題,如果從整體來操作,

1,一定是先降級優先順序地的介面,兩權相害取其輕

2,如果服務鏈路整體沒有效能特別差的點,比如就是外部流量突然激增,那麼就從外到內開始降級。

3如果某個服務能檢測到自身負載上公升,那麼可以從這個服務自身做降級。

3.6 漣漪

a -> b -> c,如果c服務出現抖動,而b沒有處理好這個抖動,造成b服務也出現了抖動,a呼叫b的時候,也會出現服務抖動的情況。

這個暫時的不可用狀態就想波浪一樣從底層傳遞到了上層。

所以,從整個體系的角度來看,每個服務一定要盡量控制住自己下游服務的抖動,不要讓整個體系跟著某個服務抖動。

3.7 級聯失敗(cascading failure)

系統中有某個服務出現故障,不可用,傳遞性地導致整個系統服務不可用的問題。

跟上面漣漪(自造詞)的區別也就是嚴重性的問題。

漣漪描述服務偶發的不穩定層層傳遞,而級聯失敗基本是導致系統不可用。 一般,前者可能會因為短時間內恢復而未引起重視,而後者一般會被高度重視。

3.8 關鍵路徑

關鍵路徑就是,你的服務想正常工作,必須要完整依賴的下游服務鏈,比如資料庫一般就是關鍵路徑裡面的乙個節點。

儘量減少關鍵路徑依賴的數量,是提高服務穩定性的乙個措施。

資料庫一般在服務體系的最底層,如果你的服務可以會自己完整快取使用的資料,解除資料庫依賴,那麼資料庫掛掉,你的服務就暫時是安全的。

3.9 最長路徑

想要優化你的服務的響應時間,需要看服務呼叫邏輯裡面的最長路徑,只有縮短最長時間路徑的用時,才能提高你的服務的效能。

參考:[url]

mysql限流熔斷 熔斷,限流,降級

1 寫在前面 1.1 名詞解釋 consumer表示服務呼叫方 provider標示服務提供方,dubbo裡面一般就這麼講。下面的a呼叫b服務,一般是泛指呼叫b服務裡面的乙個介面。1.2 拓撲圖 大寫字母表示不同的服務,後面的序號表示同乙個服務部署在不同機器的例項。2 從微觀角度思考 2.1 超時 ...

dubbo熔斷限流

常見的限流演算法有 令牌桶 漏桶。計數器也可以進行粗暴限流實現。dubbo呼叫模型 連線呼叫圖 呼叫時關鍵引數影響 引數名 作用範圍 預設值說明 備註actives consumer 0每服務消費者每服務每方法最大併發呼叫數 0表示不限制 connections consumer 對每個提供者的最大...

dubbo 熔斷,限流,降級

1 寫在前面 1.1 名詞解釋 consumer表示服務呼叫方 provider標示服務提供方,dubbo裡面一般就這麼講。下面的a呼叫b服務,一般是泛指呼叫b服務裡面的乙個介面。1.2 拓撲圖 大寫字母表示不同的服務,後面的序號表示同乙個服務部署在不同機器的例項。2 從微觀角度思考 2.1 超時 ...