1. 程式人生 > >再探Circuit Breaker之使用Polly

再探Circuit Breaker之使用Polly

前言

上一篇介紹了使用Steeltoe來處理服務熔斷,這篇我們將用Polly來處理服務熔斷。

不廢話了,直接進正題。

簡單的例子

同樣先定義一個簡單的服務。

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public string Get()
    {
        return "service--a";
    }
}

再來一個新服務去呼叫上面的服務。

定義一個用於訪問服務的Service介面和實現。

public interface IAService
{
    Task<string> GetAsync();
}

public class AService : IAService
{
    private PolicyWrap<string> _policyWrap;

    private ILogger _logger;

    public AService(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AService>();

        //超時
        var timeout = Policy
              .TimeoutAsync(1, Polly.Timeout.TimeoutStrategy.Pessimistic, (context, ts, task) =>
              {
                  _logger.LogInformation("AService timeout");
                  return Task.CompletedTask;
              });
        
        //熔斷
        var circuitBreaker = Policy
            .Handle<Exception>()
            .CircuitBreakerAsync(2, TimeSpan.FromSeconds(5), (ex, ts) =>
            {
                _logger.LogInformation($"AService OnBreak -- ts = {ts.Seconds}s ,ex.message = {ex.Message}");
            }, () =>
            {
                _logger.LogInformation("AService OnReset");
            });
        
        //Fallback + 熔斷 + 超時
        _policyWrap = Policy<string>
            .Handle<Exception>()
            .FallbackAsync(GetFallback(), (x) =>
            {
                _logger.LogInformation($"AService Fallback -- {x.Exception.Message}");                    
                return Task.CompletedTask;
            })
            .WrapAsync(circuitBreaker)
            .WrapAsync(timeout);
    }

    //降級處理
    private string GetFallback()
    {
        return "fallback";
    }

    public async Task<string> GetAsync()
    {
        return await _policyWrap.ExecuteAsync(() =>
        {
            return QueryAsync();
        });
    }

    private async Task<string> QueryAsync()
    {
        using (var client = new HttpClient())
        {
            var res = await client.GetStringAsync("http://localhost:9001/api/values");
            return res;
        }
    }
}

要注意的有幾個地方。

Polly沒有既包含熔斷又包含降級又包含超時的,這個需要自己去組合。相對來說,Hystrix在這一方面似乎好一點點。

但是,各有各的好,Polly分離了每一個模組,讓我們自由組合,也是很靈活的。

所以可以看到,我們定義了3個Policy,再把它們Wrap起來。

另外,還在觸發每一個Policy的時候,都會輸出相應的日記,方便我們後面看效果。

對於寫日記這一塊,個人認為對比Steeltoe,Polly的方式要更加方便和簡單。

下面是控制器的使用。

// GET api/values
[HttpGet]
public async Task<string> A([FromServices]IAService aService)
{
    return await aService.GetAsync();
}

還有一個關鍵的步驟:在Startup註冊我們的AService。

services.AddSingleton<IAService, AService>();

切記是Singleton!不然熔斷就不會起作用了!!

直接上效果圖

簡單說明一下這張圖,一開始,服務A和呼叫方都是正常的,後面中斷服務A,使其不可用,這個時候呼叫方就會走降級處理。

呼叫方多請求幾次,就可以看到OnBreak的日記輸出,說明斷路器已經處於Open狀態,不會直接走真正的請求,而是走的Fallback。

最後啟動服務A,可以看到OnReset的日記輸出,說明斷路器已經處於Closed狀態了,瀏覽器顯示的也是服務A的返回結果。

再來模擬一下超時的情形。

因為上面設定的超時時間是1秒,所以讓其休息1001毫秒就可以模擬了。

// GET api/values
[HttpGet]
public string Get()
{
    System.Threading.Thread.Sleep(1001);
    return "service--a";
}

再來看看效果圖

呼叫方一直是提示因為超時而降級,而熔斷。從日記也可以看出,是因為超時而導致熔斷的。

前面還提到一個註冊服務的問題,這裡解釋一下為什麼我們要讓其註冊成Singleton?

我們先把註冊服務這一塊調整為不是Singleton,這裡以Scope為例,Transient也是一樣的。

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IAService, AService>();
    //services.AddSingleton<IAService, AService>();
    services.AddMvc();
}

效果如下:

可以看到,日記一直輸出超時!並沒有提示熔斷相關的資訊!這說明我們設定的熔斷並沒有起作用!!

這個問題與例項的生命週期有著密不可分的關係!

試想一下,如果每次請求,都建立一個AService的例項,同樣的每次都會重新建立一個新的熔斷器,那熔斷還會生效嗎?

反之,如果熔斷器只有一個,那麼無論發起多少次請求,它都是唯一的,所以它才能統計到有多少次異常,從而去觸發熔斷。

這也是一個我們需要特別注意的地方。不然一個不小心就入坑了。

總結

Polly用起來還是比較簡單,比較靈活的,我們可以組合多種不同的Policy來達到我們想要的結果。

本文的示例程式碼:

相關推薦

Circuit Breaker使用Polly

前言 上一篇介紹了使用Steeltoe來處理服務熔斷,這篇我們將用Polly來處理服務熔斷。 不廢話了,直接進正題。 簡單的例子 同樣先定義一個簡單的服務。 [Route("api/[controller]")] public class ValuesController : Controller {

Spring學習旅(四)Spring工作原理

容器 mxml 實現 span ssp express 16px 部分 做了 上篇博文對Spring的工作原理做了個大概的介紹,想看的同學請出門左轉。今天詳細說幾點。 (一)Spring IoC容器及其實例化與使用 Spring IoC容器負責Bean的實例化、配置和組裝工

SteeltoeCircuit Breaker

page val collect mman seve vat ken tar localhost 在分布式系統中,服務發生異常是很正常的現象。為了處理這類“例外”,可以采取不同的應對策略,斷路器模式即是其中一種方法。這個模式的主要特點是其可以阻斷失敗的級聯影響,不會因為一個

AkkaCircuit Breaker

 這周在專案中遇到了一個錯誤,就是Circuit Breaker time out。以前沒有接觸過,因此學習了下akka的斷路器。 一、為什麼使用Circuit Breaker 斷路器是為了防止分散式系統中的級聯故障,從而保障其穩定性。其應該與遠端系統之間介面的明智超時結合使

spark

在Spark2.X.X後,想要在Spark-shell中執行這個命令,你需要使用spark.sqlContext.sql()的形式。spark的cache快取其中的方法 (儲存在記憶體中) .cache()  //進行快取.unpresist(true) //對資源進行釋放s

iOS開發多執行緒程式設計:Grand Central Dispatch詳解

Swift3.0相關程式碼已在github上更新。之前關於iOS開發多執行緒的內容釋出過一篇部落格,其中介紹了NSThread、操作佇列以及GCD,介紹的不夠深入。今天就以GCD為主題來全面的總結一下GCD的使用方式。GCD的歷史以及好處在此就不做過多的贅述了。本篇部落格會通過一系列的例項來好好的總結一下GC

Go語言入門系列(六)函式

[Go語言入門系列](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1441283546689404928)前面的文章: - [Go語言入門系列(三)之陣列和切片](https://mp.weixin.qq.com/

gdb經常使用命令

exti step poi 使用 href 運行 top ng- post ?? 前面已經有了一篇對gdb經常使用命令的總結。見 http://blog.csdn.net/u011848617/article/details/12838875 這裏對眼下學過的gdb

for循環

for語句 步驟 for循環 摘要 循環 變量 p s 失敗 spa 摘要:for循環頭的組成、for的執行流程 一、for 語句的組成 0. 舉個例子 for (int val = 1; val <= 10; ++val)  sum += val; 1. 循環頭

(3)左右值與decltype

left 哪些 而是 ++ 但是 是什麽 了解 ati pure Decltype 類型指示符 “引用從來都作為其所指對象的同義詞出現,只有用在decltype處是一個例外” 理解: Decltype和auto區別: 1. auto是從表達式類型推斷出要定義的變量類

Building Microservices with Spring Cloud - Fault tolerance Circuit breaker

tps blog logs single pri ros ces nts bre ref: https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_circuit_bre

Prism for WPF(基於Prism事件的模塊間通信)

模塊化 mod ane red chan lazy eat markup pub 上篇博文鏈接 一、簡單介紹:   在上一篇博文中初步搭建了Prism框架的各個模塊,但那只是搭建了一個空殼,裏面的內容基本是空的,在這一篇我將實現各個模塊間的通信,在上一篇博文的基礎上改的。

使用kubeadm部署高可用的k8s集群-01引言

data- mode etcd [1] working -s device master 基本 再探使用kubeadm部署高可用的k8s集群-01引言 2018/1/26 提示 僅供測試用途前言:高可用一直是重要的話題,需要持續研究。最近關註到 k8s 官網文檔有更新,其中

C#——控件調用/數據庫操作/配置文件

HR 利用 查詢 .text click cut initial comm man 因為這學期的設計模式課需要進行面向對象的編程, 所以這裏抽時間復習一下C# 命名空間的設計目的是提供一種讓一組名稱與其他名稱分隔開的方式。 利用對象指針調用控件: publ

【Java入門提高篇】Day15 Java泛型——泛型通配符及上下邊界

編譯器 pan 會有 認識 方法重載 上界 圖片 解決 int   上篇文章中介紹了泛型是什麽,為什麽要使用泛型以及如何使用泛型,相信大家對泛型有了一個基本的了解,本篇將繼續講解泛型的使用,讓你對泛型有一個更好的掌握和更深入的認識。   上篇中介紹完泛型之後,是不是覺得泛型

談談Circuit Breaker在.NET Core中的簡單應用

訂單號 exe 什麽 login isolation HA 使用 doc his 前言 由於微服務的盛行,不少公司都將原來細粒度比較大的服務拆分成多個小的服務,讓每個小服務做好自己的事即可。 經過拆分之後,就避免不了服務之間的相互調用問題!如果調用沒有處理好,就有可能造成整

.NET Core中Circuit Breaker

face The please res 一段時間 故障 cte dds 理想 談談Circuit Breaker在.NET Core中的簡單應用 前言 由於微服務的盛行,不少公司都將原來細粒度比較大的服務拆分成多個小的服務,讓每個小服務做好自己的事即可。 經過拆分之後,就避

計算機網絡

阻塞 接管 取數據 數據鏈路層 工作 收獲 數據鏈路 使用 數據 這個星期在工作之余花了一些時間去研究計算機網絡部分的一些知識,感覺頗有收獲,便記錄下來以供交流。 一,計算機通信原理: 我們都知道tcp/ip協議鏃有五層模型(其實和osi七成模型沒多大區別),那麽這五層模

Circuit Breaker

roc ppr cati range opera things taf regular arr CircuitBreaker 轉載自 https://martinfowler.com/bliki/CircuitBreaker.html Martin Fowler I

【C++ Primer | 10】叠代器

begin clu eve ++ algorithm end 測試 區間 code 反向叠代器 1. 測試代碼: 1 #include<iostream> 2 #include<vector> 3 #include<itera