Implementace systému jističe

Tip

Tento obsah je výňatek z eBooku, architektury mikroslužeb .NET pro kontejnerizované aplikace .NET, které jsou k dispozici na .NET Docs nebo jako zdarma ke stažení PDF, které lze číst offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Jak jsme uvedli dříve, měli byste zpracovávat chyby, které můžou trvat různou dobu, než se obnoví, jak se může stát při pokusu o připojení ke vzdálené službě nebo prostředku. Zpracování tohoto typu chyby může zlepšit stabilitu a odolnost aplikace.

V distribuovaném prostředí můžou volání vzdálených prostředků a služeb selhat kvůli přechodným chybám, jako jsou pomalé síťová připojení a vypršení časového limitu, nebo pokud prostředky reagují pomalu nebo jsou dočasně nedostupné. Tyto chyby se obvykle opravují po krátké době a robustní cloudová aplikace by se měla připravit na jejich zpracování pomocí strategie, jako je například model opakování.

Mohou však také nastat situace, kdy chyby jsou způsobeny neočekávajícími událostmi, které mohou trvat mnohem déle, než se opraví. Tyto chyby můžou být různě závažné, od částečného výpadku připojení až po úplné selhání služby. V těchto situacích může být pro aplikaci zbytečné neustále opakovat operaci, která pravděpodobně nebude úspěšná.

Místo toho by měla být aplikace zakódovaná tak, aby přijímala, že operace selhala, a odpovídajícím způsobem zpracovat selhání.

Použití opakování http bezstarosti může vést k vytvoření útoku DoS (DoS) ve vašem vlastním softwaru. Vzhledem k tomu, že mikroslužba selže nebo funguje pomalu, může několik klientů opakovaně opakovat neúspěšné požadavky. To vytváří nebezpečné riziko exponenciálního zvýšení provozu cíleného na neúspěšnou službu.

Proto potřebujete nějaký druh ochranné bariéry, aby se nadměrné požadavky zastavily, když to nestojí za to pokračovat v pokusu. Tato obranná bariéra je přesně jistič.

Model Jistič má jiný účel než model opakování. Model opakování umožňuje aplikaci opakovat operaci v očekávání, že operace bude nakonec úspěšná. Model Jistič brání aplikaci v provádění operace, která pravděpodobně selže. Aplikace může tyto dva vzory kombinovat. Logika opakování by však měla být citlivá na všechny výjimky vrácené jističem a měla by opustit pokusy o opakování, pokud jistič indikuje, že chyba není přechodná.

Implementace modelu Jistič pomocí IHttpClientFactory a Polly

Stejně jako při implementaci opakování je doporučeným přístupem pro jističe využít osvědčené knihovny .NET, jako je Polly, a jeho nativní integrace s IHttpClientFactory.

Přidání zásad jističe do IHttpClientFactory odchozího kanálu middlewaru je stejně jednoduché jako přidání jediné přírůstkové části kódu k tomu, co už máte při použití IHttpClientFactory.

Jediným přidáním kódu použitého pro opakování volání HTTP je kód, do kterého přidáte zásadu Jistič do seznamu zásad, které se mají použít, jak je znázorněno v následujícím přírůstkovém kódu.

// Program.cs
var retryPolicy = GetRetryPolicy();
var circuitBreakerPolicy = GetCircuitBreakerPolicy();

builder.Services.AddHttpClient<IBasketService, BasketService>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))  // Sample: default lifetime is 2 minutes
        .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

Metoda AddPolicyHandler() je to, co přidává zásady k HttpClient objektům, které použijete. V tomto případě přidává zásady Polly pro jistič.

Pokud chcete mít modulární přístup, zásady jističe jsou definovány v samostatné metodě volané GetCircuitBreakerPolicy(), jak je znázorněno v následujícím kódu:

// also in Program.cs
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}

V příkladu kódu výše je zásada jističe nakonfigurovaná tak, aby přerušila nebo otevřela okruh, pokud při opakování požadavků HTTP došlo k pěti po sobě jdoucím chybám. Když k tomu dojde, okruh se přeruší po dobu 30 sekund: v daném období se volání okamžitě nezdaří jističem, a ne ve skutečnosti se umístí. Zásada automaticky interpretuje relevantní výjimky a stavové kódy HTTP jako chyby.

Jističe by se také měly použít k přesměrování požadavků na záložní infrastrukturu, pokud jste měli problémy s konkrétním prostředkem nasazeným v jiném prostředí než klientská aplikace nebo služba, která provádí volání HTTP. Pokud dojde k výpadku v datacentru, které ovlivní jenom vaše back-endové mikroslužby, ale ne klientské aplikace, můžou se klientské aplikace přesměrovat na náhradní služby. Polly plánuje novou zásadu pro automatizaci tohoto scénáře zásad převzetí služeb při selhání.

Všechny tyto funkce jsou určené pro případy, kdy spravujete převzetí služeb při selhání v kódu .NET, a ne automaticky ji spravuje azure s transparentností umístění.

Z hlediska použití není nutné při použití HttpClient přidat nic nového, protože kód je stejný jako při použití HttpClient s IHttpClientFactory, jak je znázorněno v předchozích částech.

Testování opakovaných pokusů HTTP a jističů v eShopOnContainers

Kdykoli spustíte řešení eShopOnContainers v hostiteli Dockeru, musí spustit více kontejnerů. Některé kontejnery se spouštějí a inicializují pomaleji, například kontejner SQL Serveru. To platí zejména při prvním nasazení aplikace eShopOnContainers do Dockeru, protože potřebuje nastavit image a databázi. Skutečnost, že některé kontejnery začínají pomaleji než jiné, můžou způsobit počáteční vyvolání výjimek HTTP, i když nastavíte závislosti mezi kontejnery na úrovni docker-compose, jak je vysvětleno v předchozích částech. Tyto závislosti docker-compose mezi kontejnery jsou jen na úrovni procesu. Proces vstupního bodu kontejneru se může spustit, ale SQL Server nemusí být připravený na dotazy. Výsledkem může být kaskádová chyba a aplikace může získat výjimku při pokusu o využití tohoto konkrétního kontejneru.

Tento typ chyby se může zobrazit také při spuštění, když se aplikace nasazuje do cloudu. V takovém případě můžou orchestrátory přesouvat kontejnery z jednoho uzlu nebo virtuálního počítače do jiného (tj. spouštění nových instancí) při vyrovnávání počtu kontejnerů v uzlech clusteru.

Způsob, jakým eShopOnContainers tyto problémy řeší při spouštění všech kontejnerů, je použití vzoru Opakování, který je znázorněn dříve.

Otestování jističe v eShopOnContainers

Existuje několik způsobů, jak přerušit nebo otevřít okruh a otestovat ho pomocí eShopOnContainers.

Jednou z možností je snížit povolený počet opakování na 1 v zásadách jističe a znovu nasadit celé řešení do Dockeru. Při jednom opakování existuje dobrá šance, že požadavek HTTP během nasazení selže, otevře se jistič a zobrazí se chyba.

Další možností je použít vlastní middleware implementovaný v mikroslužbě Košíku . Pokud je tento middleware povolený, zachytí všechny požadavky HTTP a vrátí stavový kód 500. Middleware můžete povolit tak, že do identifikátoru URI způsobujícího selhání vytvoříte požadavek GET, například takto:

  • GET http://localhost:5103/failing
    Tento požadavek vrátí aktuální stav middlewaru. Pokud je middleware povolený, vrátí žádost stavový kód 500. Pokud je middleware zakázaný, neexistuje žádná odpověď.

  • GET http://localhost:5103/failing?enable
    Tento požadavek povolí middleware.

  • GET http://localhost:5103/failing?disable
    Tento požadavek zakáže middleware.

Například po spuštění aplikace můžete middleware povolit tak, že v libovolném prohlížeči vytvoříte požadavek pomocí následujícího identifikátoru URI. Všimněte si, že mikroslužba řazení používá port 5103.

http://localhost:5103/failing?enable

Stav pak můžete zkontrolovat pomocí identifikátoru URI http://localhost:5103/failing, jak je znázorněno na obrázku 8-5.

Screenshot of checking the status of failing middleware simulation.

Obrázek 8–5 Kontrola stavu "Selhání" ASP.NET middleware – v tomto případě je zakázáno.

V tomto okamžiku mikroslužba Košík odpoví stavovým kódem 500 při každém volání.

Po spuštění middlewaru můžete zkusit vytvořit objednávku z webové aplikace MVC. Vzhledem k tomu, že požadavky selžou, okruh se otevře.

V následujícím příkladu vidíte, že webová aplikace MVC má v logice blok catch pro umístění objednávky. Pokud kód zachytí výjimku otevřeného okruhu, zobrazí se uživateli popisná zpráva s oznámením, že má počkat.

public class CartController : Controller
{
    //…
    public async Task<IActionResult> Index()
    {
        try
        {
            var user = _appUserParser.Parse(HttpContext.User);
            //Http requests using the Typed Client (Service Agent)
            var vm = await _basketSvc.GetBasket(user);
            return View(vm);
        }
        catch (BrokenCircuitException)
        {
            // Catches error when Basket.api is in circuit-opened mode
            HandleBrokenCircuitException();
        }
        return View();
    }

    private void HandleBrokenCircuitException()
    {
        TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business message due to Circuit-Breaker)";
    }
}

Tady je shrnutí. Zásada opakování se několikrát pokusí provést požadavek HTTP a získá chyby HTTP. Když počet opakování dosáhne maximálního počtu nastaveného pro zásadu jističe (v tomto případě 5), aplikace vyvolá výjimku BrokenCircuitException. Výsledkem je popisná zpráva, jak je znázorněno na obrázku 8-6.

Screenshot of the MVC web app with basket service inoperative error.

Obrázek 8-6 Jistič vracející chybu do uživatelského rozhraní

Pro otevření nebo přerušení okruhu můžete implementovat jinou logiku. Nebo můžete zkusit požadavek HTTP na jinou back-endovou mikroslužbu, pokud existuje záložní datacentrum nebo redundantní back-endový systém.

A konečně, další možností CircuitBreakerPolicy je použít Isolate (což vynutí otevření a drží otevřený okruh) a Reset (který ho znovu zavře). Ty se dají použít k vytvoření koncového bodu HTTP nástroje, který přímo v zásadách vyvolá izolaci a resetování. Takový koncový bod HTTP lze také použít, vhodně zabezpečený, v produkčním prostředí pro dočasné izolování podřízeného systému, například když ho chcete upgradovat. Nebo by mohl okruh ručně projet a chránit podřízený systém, u něhož máte podezření, že je chybný.

Další materiály