API網關Ocelot 使用Polly 處理部分失敗問題

来源:http://www.cnblogs.com/shanyou/archive/2017/02/06/6366360.html
-Advertisement-
Play Games

在實現API Gateway過程中,另外一個需要考慮的問題就是部分失敗。這個問題發生在分散式系統中當一個服務調用另外一個服務超時或者不可用的情況。API Gateway不應該被阻斷並處於無限期等待下游服務的狀態。但是,如何處理這種失敗依賴於特定的場景和具體服務。如果是產品信息服務無響應,那麼API ...


在實現API Gateway過程中,另外一個需要考慮的問題就是部分失敗。這個問題發生在分散式系統中當一個服務調用另外一個服務超時或者不可用的情況。API Gateway不應該被阻斷並處於無限期等待下游服務的狀態。但是,如何處理這種失敗依賴於特定的場景和具體服務。如果是產品信息服務無響應,那麼API Gateway就應該給客戶端返回一個錯誤。

Ocelot 是一個使用.NET Core平臺上的一個API Gateway,最近我在參與這個項目的開發,開發完成第一個就是使用Polly 處理部分失敗問題。各位同學可能對Polly這個項目不熟悉,先簡單介紹下,Polly是.NET基金會下的一個開源項目,Polly記錄那些超過預設定的極限值的調用。它實現了 circuit break模 式,使得可以將客戶端從無響應服務的無盡等待中停止。如果一個服務的錯誤率超過預設值,Polly 將中斷服務,並且在一段時間內所有請求立刻失效,Polly 可以為請求失敗定義一個fallback操作,例如讀取緩存或者返回預設值,有時候我們需要調用其他API的時候出現暫時連接不通超時的情況,那這時候也可以通過Polly進行Retry,具體信息參考 http://www.thepollyproject.org/2016/10/25/polly-5-0-a-wider-resilience-framework/

Ocelot從實現上來說就是一系列的中間件組合,在HTTP請求到達Ocelot,經過一系列的中間件的處理轉發到下游的服務,其中負責調用下游服務的中間件是HttpRequestBuilderMiddleware,通過調用HttpClient請求下游的HTTP服務,我們這裡就是要給HttpClient 的調用加上熔斷器功能,代碼參看https://github.com/TomPallister/Ocelot/pull/27/files ,主要的一段代碼如下:

using Ocelot.Logging;
using Polly;
using Polly.CircuitBreaker;
using Polly.Timeout;
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Ocelot.Requester
{
    public class CircuitBreakingDelegatingHandler : DelegatingHandler
    {
        private readonly IOcelotLogger _logger;
        private readonly int _exceptionsAllowedBeforeBreaking;
        private readonly TimeSpan _durationOfBreak;
        private readonly Policy _circuitBreakerPolicy;
        private readonly TimeoutPolicy _timeoutPolicy;

        public CircuitBreakingDelegatingHandler(int exceptionsAllowedBeforeBreaking, TimeSpan durationOfBreak,TimeSpan timeoutValue
            ,TimeoutStrategy timeoutStrategy, IOcelotLogger logger, HttpMessageHandler innerHandler)
            : base(innerHandler)
        {
            this._exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
            this._durationOfBreak = durationOfBreak;

            _circuitBreakerPolicy = Policy
                .Handle<HttpRequestException>()
                .Or<TimeoutRejectedException>()
                .Or<TimeoutException>()
                .CircuitBreakerAsync(
                    exceptionsAllowedBeforeBreaking: exceptionsAllowedBeforeBreaking,
                    durationOfBreak: durationOfBreak,
                    onBreak: (ex, breakDelay) =>
                    {
                        _logger.LogError(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex);
                    },
                    onReset: () => _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again."),
                    onHalfOpen: () => _logger.LogDebug(".Breaker logging: Half-open; next call is a trial.")
                    );
            _timeoutPolicy = Policy.TimeoutAsync(timeoutValue, timeoutStrategy);
            _logger = logger;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Task<HttpResponseMessage> responseTask = null;

            try
            {
                responseTask = Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync<HttpResponseMessage>(() =>
                {
                    return  base.SendAsync(request,cancellationToken);
                });
                return responseTask;
            }
            catch (BrokenCircuitException ex)
            {
                _logger.LogError($"Reached to allowed number of exceptions. Circuit is open. AllowedExceptionCount: {_exceptionsAllowedBeforeBreaking}, DurationOfBreak: {_durationOfBreak}",ex);
                throw;
            }
            catch (HttpRequestException)
            {
                return responseTask;
            }
        }

        private static bool IsTransientFailure(HttpResponseMessage result)
        {
            return result.StatusCode >= HttpStatusCode.InternalServerError;
        }
    }
}

上面代碼我們使用Policy.WrapAsync組合了熔斷器和重試的兩個策略來解決部分失敗問題,思路很簡單,定義需要處理的異常有哪些,比如 Policy.Handle<HttpRequestException>() .Or<TimeoutRejectedException>() .Or<TimeoutException>(),當異常發生時候需要如何處理,使用熔斷器還是重試,上面這個代碼當然也是適合調用第三方服務用了。

歡迎大家加入建設.NET Core的微服務開發框架。從給項目Ocelot 點贊和fork代碼開始,一起來建設,春節我已經給項目貢獻了2個特性的代碼,服務發現和本文所講的熔斷器。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 非電腦專業,導師基本做單片機的項目,所以基本靠自學,經過兩年實踐,證明該學習路線基本可靠 所以分亨給對嵌入式Linux感興趣的學弟學妹 要學的東西真的很多,這裡僅提供入門之道,分為基礎知識和實踐兩個部分 第一部分,專業知識 C語言學習 《C和指針》 《C專家編程》 《C陷阱與缺陷》 上面三本書,認 ...
  • 1、安裝kernel-debuginfo-common 和 kernel-debuginfo(下載地址:http://debuginfo.centos.org/6/x86_64/),安裝之前,先通過uname -r 確認內核版本 [root@xxxmysqlbkuat01 ~]# uname -r ...
  • 1.讀readme獲取信息 1.1 由Building the Software可知,需修改頂層makefile,指定架構和編譯器 ifeq ($(HOSTARCH),$(ARCH)) CROSS_COMPILE ?= arm-linux- endif ARCH = arm CROSS_COMPIL ...
  • 本文地址 分享提綱: 1. shell中的函數 2. shell中的數組 1. shell中的函數 1.1)【定義shell函數(define function)】 說明: 1、可以帶function fun() 定義,也可以直接fun() 定義,不帶任何參數。 2、參數返回,可以顯示加:retur ...
  • 七. 構建臨時系統 1. 通用編譯指南 a. 確認是否正確設置了 LFS 環境變數 b. 假定你已經正確地設置了宿主系統需求和符號鏈接 c. 對於每個軟體包: (1). 確保解壓軟體包時你使用的是 lfs 用戶 (2). 除非特別說明,刪除解壓出來的目錄和所有編譯過程中生成的 build 目錄 2. ...
  • GPS模塊使用串口通信,那麼它的的數據處理本質上還是串口通信處理,只是GPS模塊的輸出的有其特定的格式,需要字元串處理邏輯來解析其含義。如何高效的處理從GPS模塊接收到的數據幀,是GPS驅動設計的重點,本文使用狀態機的思想來處理GPS輸出的串口數據流,相對於定時從串口環形bufer取數據包然後依次解... ...
  • 一、應用調試1:使用strace命令來跟蹤系統調用1.strace移植 cd /work/debug/strace-4.5.15 tar xjf strace-4.5.15.tar.bz2 cd strace-4.5.15 patch -p1 ../strace-fix-arm-bad-syscal ...
  • 前一篇 簡單的介紹了Fody/PropertyChanged的使用方法, 這一篇,我們詳細介紹它的一些比較重要的特性和規則 1. Attributes 通過在類或屬性上標記這些特性,可以在編譯代碼時,註入特定的功能 ImplementPropertyChangedAttribute 為類標記此特性, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...