Návrh komunikace mezi službami pro mikroslužby
Komunikace mezi mikroslužbami musí být efektivní a robustní. Díky spoustě malých služeb, které pracují na dokončení jedné aktivity podniku, může to být výzva. V tomto článku se podíváme na kompromisy mezi asynchronním zasíláním zpráv oproti synchronním rozhraním API. Pak se podíváme na některé problémy v návrhu odolné komunikace mezi službami.
Výzvy
Tady jsou některé z hlavních výzev vyplývajících z komunikace mezi službami. Sítě, které jsou popsané dále v tomto článku, jsou navržené tak, aby zpracovávala mnohé z těchto problémů.
Odolnost proti chybám. Může se jednat o desítky nebo dokonce stovky instancí jakékoli dané mikroslužby. Instance může selhat z libovolného počtu důvodů. Může se jednat o selhání na úrovni uzlu, jako je například selhání hardwaru nebo restartování virtuálního počítače. Instance může selhat nebo být zahlcena požadavky a nemůže zpracovat žádné nové žádosti. Kterákoli z těchto událostí může způsobit selhání síťového volání. Existují dva způsoby návrhu, které vám pomůžou zajistit větší odolnost volání sítě mezi službami:
Zkuste to znovu. Síťové volání může selhat kvůli přechodné chybě, která se neukončí sám sebou. Místo napravo neúspěchu by volající měl obvykle operaci zopakovat, nebo až do doby, kdy uplyne nakonfigurovaný časový limit. Pokud však operace není idempotentní, mohou opakované pokusy způsobit nezamýšlené vedlejší účinky. Původní volání může být úspěšné, ale volající nikdy nezíská odpověď. Pokud volající opakuje pokus, operace může být vyvolána dvakrát. Obecně není bezpečné opakovat metodu POST nebo PATCH, protože tyto metody nejsou zaručené idempotentní.
Přerušení okruhu. Příliš mnoho neúspěšných žádostí může způsobit kritický bod, protože čekající požadavky se sčítají ve frontě. Tyto blokované požadavky můžou blokovat důležité systémové prostředky jako paměť vlákna, připojení k databázím atd., což může způsobit další chyby. Vzor přerušení okruhu může službě zabránit v opakovaném pokusu o operaci, která pravděpodobně selže.
Vyrovnávání zatížení. Když služba "A" volá službu "B", požadavek musí dosáhnout spuštěné instance služby "B". V Kubernetes Service typ prostředku poskytuje stabilní IP adresu pro skupinu lusků. Síťový provoz na IP adresu služby se přepošle do pod, a to prostřednictvím pravidel iptable. Ve výchozím nastavení je vybrána možnost náhodného pod. Síť sítě (viz níže) může poskytovat další algoritmy inteligentního vyrovnávání zatížení na základě pozorované latence nebo jiných metrik.
Distribuované trasování. Jedna transakce může zahrnovat několik služeb. Díky tomu může být obtížné monitorovat celkový výkon a stav systému. I v případě, že každá služba generuje protokoly a metriky, aniž byste je museli spojit dohromady, jejich použití je omezené. V článku protokolování a sledování se dozvíte více o distribuovaném trasování, ale zmiňujeme ho jako výzva.
Verze služby. Když tým nasadí novou verzi služby, musí se vyvarovat porušení jakýchkoli jiných služeb nebo externích klientů, kteří na něm závisejí. Kromě toho můžete chtít spustit více verzí souběžně a směrovat požadavky na určitou verzi. Další diskuzi o tomto problému najdete v tématu Správa verzí rozhraní API .
Šifrování TLS a vzájemné ověřování TLS. Z bezpečnostních důvodů možná budete chtít šifrovat provoz mezi službami pomocí protokolu TLS a použít vzájemné ověřování TLS k ověřování volajících.
Synchronní versus asynchronní zasílání zpráv
Existují dva základní způsoby zasílání zpráv, které mohou mikroslužby používat ke komunikaci s ostatními mikroslužbami.
Synchronní komunikace. V tomto modelu služba volá rozhraní API, které jiná služba zpřístupňuje, pomocí protokolu, jako je HTTP nebo gRPC. Tato možnost je synchronní vzor pro zasílání zpráv, protože volající čeká na odpověď od příjemce.
Asynchronní předávání zpráv V tomto vzoru služba odesílá zprávy bez čekání na odpověď a jedna nebo více služeb zpracovává zprávu asynchronně.
Je důležité rozlišovat mezi asynchronními vstupně-výstupními operacemi a asynchronním protokolem. Asynchronní vstupně-výstupní operace znamená, že volající vlákno není zablokované, když se vstup/výstup dokončí. To je důležité pro výkon, ale v souvislosti s architekturou se jedná o podrobnosti implementace. Asynchronní protokol znamená, že odesílatel nečeká na odpověď. HTTP je synchronní protokol, i když klient HTTP může použít asynchronní vstupně-výstupní operace, když odešle požadavek.
Existují kompromisy pro každý vzor. Požadavek nebo odpověď je dobře pochopitelné paradigma, takže návrh rozhraní API může být přirozenější než návrh systému zasílání zpráv. Asynchronní zasílání zpráv ale má některé výhody, které můžou být užitečné v architektuře mikroslužeb:
Snížené spojení. Odesílatel zprávy nemusí o příjemci znát.
Několik předplatitelů. Pomocí modelu Pub/sub se může přihlásit k odběru událostí více příjemcům. Viz styl architektury řízený událostmi.
Izolace selhání. Pokud se příjemce nepodaří, může odesilatel stále odesílat zprávy. Zprávy budou po obnově obnovy vydány. Tato možnost je užitečná hlavně v architektuře mikroslužeb, protože každá služba má svůj vlastní životní cyklus. Služba může být nedostupná nebo ji můžete v daném okamžiku nahradit novější verzí. Asynchronní zasílání zpráv může zpracovávat občasné výpadky. Synchronní rozhraní API na druhé straně vyžaduje, aby byla služba pro příjem dat k dispozici nebo tato operace nebyla úspěšná.
Odezva. Nadřazený služba může odpovědět rychleji, pokud nečeká na služby pro příjem dat. To je užitečné hlavně v architektuře mikroslužeb. Pokud existuje řetězec závislostí služby (obsluha A volání B, která volá C atd.), čekání na synchronní volání může přidat nepřijatelné množství latence.
Vyrovnávání zatížení. Fronta může fungovat jako vyrovnávací paměť pro vyrovnání zatížení, aby příjemci mohli zpracovávat zprávy podle vlastní míry.
Pracovní postupy. Fronty lze použít ke správě pracovního postupu tak, že se po každém kroku pracovního postupu zobrazí zpráva.
Existují však také problémy s efektivním používáním asynchronního zasílání zpráv.
Spojení s infrastrukturou zasílání zpráv. Použití konkrétní infrastruktury zasílání zpráv může způsobit těsné spojení s touto infrastrukturou. Později bude obtížné přepnout na jinou infrastrukturu zasílání zpráv.
Latence. Koncová latence pro operaci může být vysoká, pokud se fronty zpráv naplní.
Náklady. V případě vysoké propustnosti může být peněžní náklady na infrastrukturu zasílání zpráv významné.
Složitost: Zpracování asynchronního zasílání zpráv není triviální úloha. Například je třeba zpracovávat duplicitní zprávy, a to buď pomocí odstranění duplicit, nebo provedením operací idempotentní. Je také obtížné implementovat sémantiku požadavku a odpovědi pomocí asynchronního zasílání zpráv. K odeslání odpovědi budete potřebovat jinou frontu a také způsob, jak sladit zprávy požadavků a odpovědí.
Propustnost: Pokud zprávy vyžadují sémantiku fronty, může se stát, že se fronta stane kritickým bodem v systému. Každá zpráva vyžaduje alespoň jednu operaci fronty a jednu operaci vyřadit z fronty. Sémantika fronty navíc obvykle vyžaduje určitý druh zamykání uvnitř infrastruktury zasílání zpráv. Pokud je frontou spravovaná služba, může existovat další latence, protože fronta je externá pro virtuální síť clusteru. Tyto problémy můžete zmírnit pomocí dávkování zpráv, ale to komplikuje kód. Pokud zprávy nevyžadují sémantiku fronty, může být možné místo fronty použít datový proud událostí. Další informace najdete v tématu Styl architektury řízený událostmi.
Doručování pomocí dronů: Volba vzorů zasílání zpráv
S ohledem na tyto aspekty vývojový tým provedl následující volby návrhu pro aplikaci pro doručování pomocí dronů.
Služba příjmu dat zveřejňuje veřejnou REST API které klientské aplikace používají k plánování, aktualizaci nebo rušení dodávek.
Služba příjmu dat používá Event Hubs k odesílání asynchronních zpráv do služby Scheduler. Asynchronní zprávy jsou nezbytné k implementaci vyrovnávání zatížení, které je potřeba pro příjem dat.
Služby Account, Delivery, Package, Drone a Third-Party Transport zpřístupňuje interní rozhraní REST API. Služba Scheduler volá tato rozhraní API k provedení požadavku uživatele. Jedním z důvodů, proč používat synchronní rozhraní API, je, že plánovač potřebuje získat odpověď z každé podřízené služby. Selhání jakékoli podřízené služby znamená, že celá operace selhala. Potenciálním problémem je však míra latence, která se zavádí voláním back-endových služeb.
Pokud u jakékoli podřízené služby dojde k neúspěchu, celá transakce by měla být označena jako neúspěšná. Za tímto případem služba Scheduler odešle do správce asynchronní zprávu, aby správce mohl plánovat kompenzační transakce.
Služba Delivery zveřejňuje veřejné rozhraní API, které klienti mohou použít k získání stavu doručení. V článku Brána rozhraní APIprobereme, jak může brána rozhraní API skrýt základní služby před klientem, takže klient nemusí vědět, které služby zpřístupňuje rozhraní API.
Během letu dronu odesílá služba Drone události, které obsahují aktuální polohu a stav dronu. Služba Delivery naslouchá těmto událostem, aby sledovala stav doručení.
Když se stav doručení změní, služba Delivery service odešle událost stavu doručení, například
DeliveryCreatedneboDeliveryCompleted. K odběru těchto událostí se může přihlásit jakákoli služba. V aktuálním návrhu je služba Historie doručení jediným odběratelem, ale později můžou být další odběratelé. Události můžou například přejít do analytické služby v reálném čase. A protože plánovač nemusí čekat na odpověď, nemá přidání dalších odběratelů vliv na hlavní cestu pracovního postupu.

Všimněte si, že události stavu doručení se odvozují z událostí umístění dronů. Když třeba dron dosáhne místa doručení a balíček odloží, služba Delivery service ho přeloží na událost DeliveryCompleted. Toto je příklad uvažování z hlediska doménových modelů. Jak je popsáno výše, správa dronů patří do samostatného ohraničeného kontextu. Události dronů vyjadřují fyzické umístění dronu. Události doručení na druhé straně představují změny stavu doručení, což je jiná obchodní entita.
Použití sítě služeb
Síť služeb je softwarová vrstva, která zpracovává komunikaci mezi službou. Sítě služeb jsou navržené tak, aby řešily řadu obav uvedených v předchozí části a přesouvali odpovědnost za tyto záležitosti mimo samotné mikroslužby a do sdílené vrstvy. Síť služeb funguje jako proxy, který zachycuje síťovou komunikaci mezi mikroslužbami v clusteru. V současné době se koncept sítě služeb vztahuje hlavně na orchestrátory kontejnerů, a ne na architektury bez serveru.
Poznámka
Service Mesh je příkladem modelu ambasador jako pomocná služba, která jménem aplikace odesílá — síťové požadavky.
V této části jsou hlavní možnosti sítě služeb v Kubernetes linkerované a Istio. Obě tyto technologie se rychle vyvíjejí. Mezi některé funkce, které linkerd i Istio mají společné, ale patří:
Vyrovnávání zatížení na úrovni relace na základě pozorovaných latencí nebo počtu nevyřízených požadavků. To může zlepšit výkon nad vyrovnáváním zatížení vrstvy 4, které poskytuje Kubernetes.
Směrování vrstvy 7 na základě cesty URL, hlavičky hostitele, verze rozhraní API nebo jiných pravidel na úrovni aplikace.
Opakování neúspěšných požadavků. Síť služeb rozumí kódům chyb HTTP a může automaticky opakovat neúspěšné požadavky. Tento maximální počet opakování můžete nakonfigurovat společně s časovým limitem, aby se maximální latence vázala.
Jistič. Pokud instance trvale selže požadavky, síť služeb ji dočasně označí jako nedostupnou. Po uplynutí časového období bude instance zkoušet znovu. Jistič můžete nakonfigurovat na základě různých kritérií, jako je počet po sobě jdoucích selhání.
Service Mesh zachycuje metriky o voláních mezi službami, jako je objem požadavků, latence, míra chyb a úspěšnosti a velikosti odpovědí. Síť služeb také umožňuje distribuované trasování přidáním informací o korelaci pro každý segment směrování v požadavku.
Vzájemné ověřování TLS pro volání mezi službou.
Potřebujete síť služeb? To závisí na okolnostech. Bez sítě služeb budete muset vzít v úvahu všechny výzvy uvedené na začátku tohoto článku. Můžete vyřešit problémy, jako je opakování, jistič a distribuované trasování bez sítě služeb, ale síť služeb přesune tyto obavy z jednotlivých služeb do vyhrazené vrstvy. Na druhé straně síť služeb zvyšuje složitost nastavení a konfigurace clusteru. To může mít vliv na výkon, protože požadavky se teď směruje přes proxy sítě služeb a protože na každém uzlu v clusteru teď běží další služby. Před nasazením sítě služeb v produkčním prostředí byste měli provést důkladné testování výkonu a zatížení.
Distribuované transakce
Běžným problémem v mikroslužbách je správné zpracování transakcí, které zahrnují více služeb. V tomto scénáři je úspěch transakce často vše nebo nic, pokud selže jedna ze zúčastněných — služeb, celá transakce musí selhat.
Je třeba zvážit dva případy:
U služby může dojít k přechodnému selhání, jako je například časový limit sítě. Tyto chyby lze často vyřešit jednoduše opakováním volání. Pokud operace i po určitém počtu pokusů selže, považuje se za netransientní selhání.
Netransientní selhání je jakékoli selhání, které pravděpodobně sám o sobě nezmizí. Netransientní selhání zahrnují normální chybové stavy, například neplatný vstup. Zahrnují také neošetřené výjimky v kódu aplikace nebo selhání procesu. Pokud dojde k tomuto typu chyby, celá obchodní transakce musí být označena jako selhání. Může být nutné vrátit zpět další kroky ve stejné transakci, která již byla úspěšná.
Po selhání netransientu může být aktuální transakce ve stavu částečně selhání, kde jeden nebo více kroků již bylo úspěšně dokončeno. Pokud už služba Drone například dron naplánoval, musí být tento dron zrušen. V takovém případě musí aplikace vrátit zpět kroky, které proběhly úspěšně, pomocí kompenzační transakce. V některých případech to musí udělat externí systém nebo dokonce ruční proces.
Pokud je logika pro kompenzační transakce složitá, zvažte vytvoření samostatné služby, která je zodpovědná za tento proces. V aplikaci pro doručování pomocí dronů služba Scheduler přemisuje neúspěšné operace do vyhrazené fronty. Samostatná mikroslužba, která se nazývá Supervisor, čte z této fronty a volá u služeb rozhraní API pro zrušení, které je potřeba kompenzovat. Jedná se o variantu modelu plánovač-agent-správce. Služba Supervisor může také provádět další akce, například upozornit uživatele textem nebo e-mailem nebo odeslat upozornění na řídicí panel operací.

Samotná služba Scheduler může selhat (například kvůli chybě uzlu). V takovém případě se může z rozjet nová instance a převzít ji. Všechny transakce, které už byly v průběhu, však musí být obnoveny.
Jedním z přístupů je uložení kontrolního bodu do trvalého úložiště po dokončení každého kroku pracovního postupu. Pokud dojde k chybě instance služby Scheduler uprostřed transakce, může nová instance pomocí kontrolního bodu obnovit, kde předchozí instance opustila. Psaní kontrolních bodů ale může mít za to režii z hlediska výkonu.
Další možností je navrhnout všechny operace jako idempotentní. Operace je idempotentní, pokud ji lze volat vícekrát, aniž by po prvním volání vyvolala další vedlejší účinky. V podstatě by měla podřízené služby ignorovat duplicitní volání, což znamená, že služba musí být schopna detekovat duplicitní volání. Není vždy jednoduché implementovat idempotentní metody. Další informace najdete v tématu Idempotentní operace.
Další kroky
U mikroslužeb, které vzájemně přímo vzájemně mluví, je důležité vytvořit dobře navržená rozhraní API.