天天看點

淺談微服務中的熔斷,限流,降級淺談微服務中的熔斷,限流,降級

淺談微服務中的熔斷,限流,降級

https://www.cnblogs.com/raoshaoquan/articles/6636067.html

1.1 名詞解釋

consumer  表示服務調用方 

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

下面的A調用B服務,一般是泛指調用B服務裡面的一個接口。

Provider是出接口的那一方,消費者是進行調用的一方

1.2 拓撲圖

大寫字母表示不同的服務,後面的序号表示同一個服務部署在不同機器的執行個體。

淺談微服務中的熔斷,限流,降級淺談微服務中的熔斷,限流,降級

2 從微觀角度思考

2.1 逾時(timeout)

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

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

是以,consumer不可能無限制地等待provider接口的傳回,會設定一個時間門檻值,如果超過了這個時間門檻值,就不繼續等待。

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

2.2 重試(retry)

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

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

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

重試時的一些細化政策:

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

2.2.1 幂等(idempotent)

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

即,同一個請求被consumer多次調用,對provider産生的影響(這裡的影響一般是指某些寫入相關的操作) 是一緻的。

而且這個幂等應該是服務級别的,而不是某台機器層面的,重試調用任何一台機器,都應該做到幂等。

 舉個例子:

同一筆訂單的支付資訊,假設被Consumer多次調用,

我在口碑網買了一杯奶茶,下了訂單,下訂單本身是一次接口調用,從流程上看是口碑網将使用者選擇的奶茶的資訊,比如奶茶品類編号,大杯,去冰,半糖,發送到指定店鋪

從接口調用上來看是:口碑網調用了奶茶店的訂單詳情接口,将生成訂單序号,單品資訊傳輸給奶茶店

奶茶店調用口碑網的接口,擷取了客戶的訂單詳情

使用者在微信頁面上進行注冊,頁面捕獲了會員資訊,組裝成指定的格式去調用服務端的注冊接口

頁面是consumer方,而服務端的接口,即服務端是我們常說的Prodiver端,

頁面即使多次調用,需要對服務端的DB資料是一緻的。

比如會員A進行1次,在進行注冊1次,服務端需要隻生成一條資料。是以說影響一般指的是某些寫入操作。

2.3 熔斷(circuit break)

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

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

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

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

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

是以就出現了熔斷的邏輯,也就是,如果檢查出來頻繁逾時,就把consumer調用provider的請求,直接短路掉,不實際調用,而是直接傳回一個mock的值。

等provider服務恢複穩定之後,重新調用。

2.3.1 簡單的熔斷處理邏輯

目前我們架構有通過注解使用的熔斷器,大家可以參考應用在項目中。

2.4 限流(current limiting)

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

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

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

是以,provider端,需要根據consumer的重要程度,以及平時的QPS大小,來給每個consumer設定一個流量上線,同一時間内隻會給A consumer提供N個線程支援,超過限制則等待或者直接拒絕。

2.4.1 資源隔離

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

同樣,consumer 也需要對調用provider的線程資源進行隔離。 這樣可以確定調用某個provider邏輯不會耗光整個consumer的線程池資源。

2.4.2 服務降級

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

2.4.2.1 consumer 端

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

2.4.2.2 provider 端

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

比如,1,直接給consumer傳回固定資料,2,需要實時寫入資料庫的,先緩存到隊列裡,異步寫入資料庫。

3 從宏觀角度重新思考

宏觀包括比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 最長路徑

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

繼續閱讀