重新整理 .net core 實踐篇————熔斷與限流[三十五]


前言

簡單整理一下熔斷與限流,跟上一節息息相關。

正文

polly 的策略類型分為兩類:

  1. 被動策略(異常處理、結果處理)

  2. 主動策略(超時處理、斷路器、艙壁隔離、緩存)

熔斷和限流通過下面主動策略來實現:

  1. 降級響應

  2. 失敗重試

  3. 斷路器

  4. 艙壁隔離

Policy 類型 狀態 說明
CircuitBreaker(斷路器) 有狀態 共享失敗率,以決定是否熔斷
Bulkhead(艙壁隔離) 有狀態 共享容量使用情況,以決定是否執行動作
Cache(緩存) 有狀態 共享緩存的對象,以決定是否命中
其他策略 無狀態

先來看一下熔斷,什么是熔斷呢?

熔斷就是讓我們的上游服務器一段時間內對下游服務器不進行調用。

這里解釋一下上游服務器和下游服務器,比如說A調用B,那么A就是上游服務器,B就是下游服務器。

那么為什么要熔斷呢?比如說A調用B,現在A調用B 10次有8次是錯誤的,那么這個時候就要想一件事,代碼沒有變過,那么肯定是量變成了質變。

這時候B之所以不可用,那么是因為請求太多了,處理不過來(比如內存升高了,io 99%了等)。

那么這個時候A就不進行調用了,隔一段時間后再進行調用。也就是A對B的這條線進行了熔斷處理。

services.AddHttpClient("GreeterClient").AddPolicyHandler(Policy<HttpResponseMessage>
	.Handle<HttpRequestException>().CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 10,
		durationOfBreak: TimeSpan.FromSeconds(10), 
		onBreak: (r, t) =>
		{
			// 熔斷的時候處理事件
		},
		onReset: () =>
		{
			// 恢復的時候的處理
		},onHalfOpen: () =>
		{
			// 恢復之前進行處理
		}));

CircuitBreakerAsync 表示斷路器,這個用來實現熔斷的。

handledEventsAllowedBeforeBreaking 表示失敗10次,進行熔斷。

durationOfBreak 熔斷的事件

其他幾個事件上面做了備注。

其實上面這種不常用,因為限制比較死,比如說10次就熔斷。

一般都是百分比來計算的。

services.AddHttpClient("GreeterClient").AddPolicyHandler(Policy<HttpResponseMessage>
	.Handle<HttpRequestException>().AdvancedCircuitBreakerAsync(
		failureThreshold:0.8,
		samplingDuration:TimeSpan.FromSeconds(10),
		minimumThroughput:100,
		durationOfBreak: TimeSpan.FromSeconds(10),
		onBreak: (r, t) =>
		{
			// 熔斷的時候處理事件
		},
		onReset: () =>
		{
			// 恢復的時候的處理
		}, onHalfOpen: () =>
		{
			// 恢復之前進行處理
		}));

failureThreshold 表示失敗的比例

samplingDuration 表示失敗的時間

failureThreshold 和 samplingDuration一般是組合起來用的,表示是10秒內失敗次數要有80%就會熔斷。

minimumThroughput 表示10秒類必須有100個請求才會出根據其他的條件進行熔斷判斷。

上面就是熔斷了,那么什么是服務降級呢?

網上的一段話是這樣的:服務降級是指 當服務器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心業務正常運作或高效運作。

這段話的感覺好像是關閉某些服務一樣,而且比較繞。

個人理解是服務降級是指降低了原有的服務體驗,都屬於服務降級。

熔斷其實也是一種服務降級,但是單純的熔斷就降級的有點厲害了。

比如我去買東西,然后店直接關門了,服務體驗下降了,體驗降得比較厲害。

但是如果去買東西,店沒有關閉,而是有一排服務員,告訴你現在因為供銷商沒到貨買不到了,這體驗是不是好點,這也是服務降級。

那么就看下第二種情況的服務降級怎么實現吧。

var breakPolicy = Policy<HttpResponseMessage>
   .Handle<HttpRequestException>().AdvancedCircuitBreakerAsync(
	   failureThreshold: 0.8,
	   samplingDuration: TimeSpan.FromSeconds(10),
	   minimumThroughput: 100,
	   durationOfBreak: TimeSpan.FromSeconds(10),
	   onBreak: (r, t) =>
	   {
		   // 熔斷的時候處理事件
	   },
	   onReset: () =>
	   {
		   // 恢復的時候的處理
	   }, onHalfOpen: () =>
	   {
		   // 恢復之前進行處理
	   });

var message = new HttpResponseMessage()
{
	Content = new StringContent("不要慌,老板沒有跑路,只是和老婆的妹妹出去了,要等一下!")
};

var fallback = Policy<HttpResponseMessage>.Handle<BrokenCircuitException>().FallbackAsync(message);

var fallbackBreak = Policy.WrapAsync(fallback, breakPolicy);

services.AddHttpClient("GreeterClient").AddPolicyHandler(fallbackBreak);

上面代碼就是當熔斷后,過來的請求會有BrokenCircuitException異常,那么捕獲到BrokenCircuitException異常,那么就告訴用戶店沒有倒閉,等一下就好。

這種就是比較優雅的降級。

上面這種var fallbackBreak = Policy.WrapAsync(fallback, breakPolicy); 就是將幾個policy組合在一起,然后給某個或者某些HttpClient 增加該組合策略,比如Policy.WrapAsync(fallback, breakPolicy,xxx,yyy)等。

接下來解釋一下限流。

為什么要限流呢? 如果沒有限流其實熔斷的意義是不大的。

為什么這么說呢? 比如說公司有1百萬請求,然后這個時候熔斷了,但是這100w請求還在啊,只有恢復服務,服務器又要進行熔斷,一下子就瞬間爆炸。

var bulk = Policy.BulkheadAsync<HttpResponseMessage>(
	maxParallelization:30,
	maxQueuingActions:20,
	onBulkheadRejectedAsync:context=>Task.CompletedTask);

var message = new HttpResponseMessage()
{
	Content = new StringContent("你沒有搶到號碼,下次再來。")
};

var fallbackBulk = Policy<HttpResponseMessage>.Handle<BulkheadRejectedException>().FallbackAsync(message);

var fallbackBreak = Policy.WrapAsync(bulk, fallbackBulk);

上面這個就是限流了。

maxParallelization 表示可以並發處理30個請求,maxQueuingActions表示如果並發處於30,那么會加入到隊列中,隊列中最大能存20個。

如果隊列中也存不下,那么就會拋出BulkheadRejectedException這種拒絕異常,一但出現異常,第二個策略就捕獲到了,然后給出一些友好的提示。

下一節,網關。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM