Komunikace v architektuře mikroslužeb

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.

V monolitické aplikaci spuštěné v jednom procesu volat komponenty navzájem pomocí metody na úrovni jazyka nebo volání funkce. Pokud vytváříte objekty s kódem (například new ClassName()) nebo je můžete vyvolat odděleným způsobem, pokud používáte injektáž závislostí odkazováním na abstrakce místo konkrétních instancí objektů. V obou směrech se objekty spouští ve stejném procesu. Největší výzvou při změně z monolitické aplikace na aplikaci založenou na mikroslužbách je změna komunikačního mechanismu. Přímý převod volání metod v procesu na volání RPC do služeb způsobí chatování a ne efektivní komunikaci, která nebude v distribuovaných prostředích dobře fungovat. Výzvy návrhu distribuovaného systému jsou dostatečně dobře známé, že existuje dokonce i kanon známý jako fallacies distribuovaného computingu , který uvádí předpoklady, které vývojáři často dělají při přechodu z monolitického na distribuované návrhy.

Neexistuje jedno řešení, ale několik. Jedním z řešení je izolace podnikových mikroslužeb co nejvíce. Pak použijete asynchronní komunikaci mezi interními mikroslužbami a nahradíte jemně odstupňovanou komunikaci, která je typická při komunikaci uvnitř procesu mezi objekty hrubou odstupňovanou komunikací. Můžete to provést seskupením volání a vrácením dat, která agregují výsledky více interních volání, klientovi.

Aplikace založená na mikroslužbách je distribuovaný systém běžící na více procesech nebo službách, obvykle i na více serverech nebo hostitelích. Každá instance služby je obvykle procesem. Služby proto musí komunikovat pomocí komunikačního protokolu mezi procesy, jako je HTTP, AMQP nebo binární protokol, jako je TCP, v závislosti na povaze každé služby.

Komunita mikroslužeb podporuje filozofie "inteligentních koncových bodů a fiktivních kanálů". Tento heslem podporuje návrh, který je co nejvíce oddělený mezi mikroslužbami a co nejkonkrétnější v rámci jedné mikroslužby. Jak bylo vysvětleno dříve, každá mikroslužba vlastní vlastní data a vlastní logiku domény. Mikroslužby, které tvoří ucelenou aplikaci, jsou ale obvykle jednoduše napodobovány pomocí komunikace REST místo složitých protokolů, jako jsou WS-* a flexibilní komunikace řízená událostmi místo centralizovaných orchestrátorů obchodních procesů.

Těmito dvěma běžně používanými protokoly jsou požadavky a odpovědi HTTP pomocí rozhraní API prostředků (při dotazování většiny všech) a jednoduché asynchronní zasílání zpráv při komunikaci aktualizací napříč několika mikroslužbami. Tyto informace jsou podrobněji vysvětleny v následujících částech.

Typy komunikace

Klienti a služby můžou komunikovat prostřednictvím mnoha různých typů komunikace, z nichž každý cílí na jiný scénář a cíle. Zpočátku lze tyto typy komunikace klasifikovat ve dvou osách.

První osa definuje, jestli je protokol synchronní nebo asynchronní:

  • Synchronní protokol. HTTP je synchronní protokol. Klient odešle požadavek a čeká na odpověď ze služby. To je nezávislé na provádění kódu klienta, které by mohlo být synchronní (vlákno je blokováno) nebo asynchronní (vlákno není blokováno a odpověď nakonec dosáhne zpětného volání). Důležitým bodem je, že protokol (HTTP/HTTPS) je synchronní a klientský kód může pokračovat pouze při přijetí odpovědi serveru HTTP.

  • Asynchronní protokol. Jiné protokoly, jako je AMQP (protokol podporovaný mnoha operačními systémy a cloudovými prostředími), používají asynchronní zprávy. Kód klienta nebo odesílatel zprávy obvykle nečeká na odpověď. Zpráva se odešle jenom jako při odesílání zprávy do fronty RabbitMQ nebo jakéhokoli jiného zprostředkovatele zpráv.

Druhá osa definuje, jestli má komunikace jeden přijímač nebo více přijímačů:

  • Jeden přijímač. Každý požadavek musí zpracovat přesně jeden příjemce nebo služba. Příkladem této komunikace je vzor Příkaz.

  • Více přijímačů. Každý požadavek může být zpracován nulou pro více příjemců. Tento typ komunikace musí být asynchronní. Příkladem je mechanismus publikování a odběrupoužívaný ve vzorech, jako je architektura řízená událostmi. To je založeno na rozhraní sběrnice událostí nebo zprostředkovatele zpráv při šíření aktualizací dat mezi více mikroslužeb prostřednictvím událostí; Obvykle se implementuje prostřednictvím služby Service Bus nebo podobného artefaktu, jako je Azure Service Bus , pomocí témat a odběrů.

Aplikace založená na mikroslužbách často používá kombinaci těchto stylů komunikace. Nejběžnějším typem je komunikace s jedním příjemcem s synchronním protokolem, jako je HTTP/HTTPS při vyvolání běžné služby HTTP webového rozhraní API. Mikroslužby také obvykle používají protokoly zasílání zpráv pro asynchronní komunikaci mezi mikroslužbami.

Tyto osy jsou dobré vědět, takže máte přehled o možných komunikačních mechanismech, ale nejsou to důležité obavy při vytváření mikroslužeb. Asynchronní povaha spouštění klientských vláken ani asynchronní povaha vybraného protokolu nejsou důležitými body při integraci mikroslužeb. Co je důležité, je schopnost integrovat mikroslužby asynchronně při zachování nezávislosti mikroslužeb, jak je vysvětleno v následující části.

Asynchronní integrace mikroslužeb vynucuje autonomii mikroslužeb.

Jak už bylo zmíněno, důležitým bodem při vytváření aplikace založené na mikroslužbách je způsob integrace mikroslužeb. V ideálním případě byste se měli pokusit minimalizovat komunikaci mezi interními mikroslužbami. Čím méně komunikace mezi mikroslužbami, tím lépe. V mnoha případech ale budete muset nějak integrovat mikroslužby. Když to potřebujete udělat, důležité pravidlo je, že komunikace mezi mikroslužbami by měla být asynchronní. To neznamená, že musíte použít konkrétní protokol (například asynchronní zasílání zpráv versus synchronní HTTP). To znamená, že komunikace mezi mikroslužbami by měla být provedena pouze asynchronním šířením dat, ale snažte se nezáviset na jiných interních mikroslužbách v rámci počáteční operace požadavku/odpovědi služby.

Pokud je to možné, nikdy nezávisí na synchronní komunikaci (požadavek/odpověď) mezi několika mikroslužbami, ani na dotazech. Cílem každé mikroslužby je být autonomní a dostupná pro příjemce klienta, i když ostatní služby, které jsou součástí komplexní aplikace, jsou mimo provoz nebo nejsou v pořádku. Pokud si myslíte, že potřebujete volat z jedné mikroslužby do jiných mikroslužeb (například provedení požadavku HTTP na datový dotaz), abyste mohli poskytnout odpověď na klientskou aplikaci, máte architekturu, která nebude odolná, když některé mikroslužby selžou.

Kromě toho mají závislosti HTTP mezi mikroslužbami, jako je vytváření dlouhých cyklů požadavků a odpovědí HTTP s řetězy požadavků HTTP, jak je znázorněno v první části obrázku 4–15, znamená to nejen, že mikroslužby nejsou autonomní, ale také jejich výkon je ovlivněný, jakmile některý ze služeb v daném řetězci nebude dobře fungovat.

Čím více přidáváte synchronní závislosti mezi mikroslužbami, jako jsou požadavky na dotazy, tím horší je celková doba odezvy pro klientské aplikace.

Diagram showing three types of communications across microservices.

Obrázek 4–15 Anti-patterns and patterns in communication between microservices

Jak je znázorněno na výše uvedeném diagramu, při synchronní komunikaci se vytvoří řetězec požadavků mezi mikroslužbami při obsluhování požadavku klienta. Toto je anti-vzor. V mikroslužbách asynchronní komunikace používají asynchronní zprávy nebo dotazování HTTP ke komunikaci s jinými mikroslužbami, ale požadavek klienta se obsluhuje hned.

Pokud vaše mikroslužba potřebuje vyvolat další akci v jiné mikroslužbě, pokud je to možné, neprovádějte tuto akci synchronně a jako součást původní operace žádosti mikroslužby a odpovědi. Místo toho to udělejte asynchronně (pomocí asynchronního zasílání zpráv nebo událostí integrace, front atd.). Ale co nejvíce nevyvolejte akci synchronně jako součást původní synchronní žádosti a operace odpovědi.

A nakonec (a to je místo, kde většina problémů vzniká při vytváření mikroslužeb), pokud vaše počáteční mikroslužba potřebuje data, která původně vlastní jiné mikroslužby, nespoléhejte na provádění synchronních požadavků na tato data. Místo toho replikujte nebo šíříte tato data (pouze atributy, které potřebujete) do počáteční databáze služby pomocí konečné konzistence (obvykle pomocí událostí integrace, jak je vysvětleno v nadcházejících částech).

Jak jsme si poznamenali dříve v sekci Identifikace doménového modelu pro každou část mikroslužby , duplikování některých dat mezi několika mikroslužbami není nesprávný návrh – naopak při tom můžete data přeložit do konkrétního jazyka nebo termínů této další domény nebo ohraničeného kontextu. Například v aplikaci eShopOnContainers máte mikroslužbu s názvem identity-api , která má na starosti většinu dat uživatele s entitou s názvem User. Pokud však potřebujete uložit data o uživateli v rámci Ordering mikroslužby, uložíte je jako jinou entitu s názvem Buyer. Entita Buyer sdílí stejnou identitu s původní User entitou, ale může mít pouze několik atributů, které Ordering doména potřebuje, a ne celý profil uživatele.

Pokud chcete mít konečnou konzistenci, můžete použít jakýkoli protokol ke komunikaci a šíření dat asynchronně mezi mikroslužby. Jak už bylo zmíněno, můžete použít integrační události pomocí sběrnice událostí nebo zprostředkovatele zpráv nebo dokonce použít HTTP dotazováním ostatních služeb. Nezáleží. Důležitým pravidlem je nevytvořovat synchronní závislosti mezi mikroslužbami.

Následující části popisují více stylů komunikace, které můžete zvážit při použití v aplikaci založené na mikroslužbách.

Styly komunikace

Existuje mnoho protokolů a možností, které můžete použít pro komunikaci v závislosti na typu komunikace, který chcete použít. Pokud používáte synchronní komunikační mechanismus založený na žádostech a odpovědích, nejběžnější jsou protokoly, jako je HTTP a REST, zejména pokud publikujete služby mimo hostitelský nebo cluster mikroslužeb Dockeru. Pokud interně komunikujete mezi službami (v rámci hostitele Dockeru nebo clusteru mikroslužeb), můžete také chtít použít mechanismy komunikace binárního formátu (například WCF pomocí protokolu TCP a binárního formátu). Alternativně můžete použít asynchronní komunikační mechanismy založené na zprávách, jako je AMQP.

Existuje také několik formátů zpráv, jako je JSON nebo XML, nebo dokonce binární formáty, které mohou být efektivnější. Pokud zvolený binární formát není standardní, pravděpodobně není vhodné veřejně publikovat služby pomocí daného formátu. Pro interní komunikaci mezi mikroslužbami můžete použít nestandardní formát. Můžete to udělat při komunikaci mezi mikroslužbami v rámci hostitele Dockeru nebo clusteru mikroslužeb (například orchestrátory Dockeru) nebo pro vlastní klientské aplikace, které komunikují s mikroslužbami.

Komunikace požadavků a odpovědí s protokolem HTTP a REST

Když klient používá komunikaci s požadavky a odpověďmi, odešle požadavek službě, pak tato služba požadavek zpracuje a odešle zpět odpověď. Komunikace požadavků a odpovědí je zvláště vhodná pro dotazování dat pro uživatelské rozhraní v reálném čase (živé uživatelské rozhraní) z klientských aplikací. Proto v architektuře mikroslužeb pravděpodobně použijete tento komunikační mechanismus pro většinu dotazů, jak je znázorněno na obrázku 4–16.

Diagram showing request/response comms for live queries and updates.

Obrázek 4–16 Použití komunikace požadavků/odpovědí HTTP (synchronní nebo asynchronní)

Když klient používá komunikaci s požadavky a odpověďmi, předpokládá, že odpověď přijde za krátkou dobu, obvykle kratší než sekunda nebo maximálně několik sekund. U zpožděných odpovědí je potřeba implementovat asynchronní komunikaci založenou na vzorech zasílání zpráv a technologiích zasílání zpráv, což je jiný přístup, který vysvětlujeme v další části.

Oblíbeným stylem architektury pro komunikaci požadavků a odpovědí je REST. Tento přístup je založený na protokolu HTTP, který je úzce propojený s protokolem HTTP , který přijímá příkazy HTTP, jako je GET, POST a PUT. REST je nejčastěji používaný přístup ke komunikaci architektury při vytváření služeb. Služby REST můžete implementovat při vývoji ASP.NET základních služeb webového rozhraní API.

Při použití služeb HTTP REST jako jazyka definice rozhraní je k dispozici další hodnota. Pokud například k popisu rozhraní API služby použijete metadata Swaggeru, můžete použít nástroje, které generují zástupné procedury klientů, které můžou vaše služby přímo zjišťovat a využívat.

Další materiály

Nabízená komunikace a komunikace v reálném čase založená na protokolu HTTP

Další možností (obvykle pro různé účely než REST) je komunikace v reálném čase a 1:N s architekturami vyšší úrovně, jako je ASP.NET SignalR a protokoly, jako je WebSockets.

Jak ukazuje obrázek 4–17, komunikace HTTP v reálném čase znamená, že můžete mít serverový kód, který odesílá obsah připojeným klientům, jakmile budou data dostupná, a ne čekat na to, aby server čekal na vyžádání nových dat klientem.

Diagram showing push and real-time comms based on SignalR.

Obrázek 4–17 Asynchronní komunikace zpráv 1:N v reálném čase

SignalR je dobrý způsob, jak dosáhnout komunikace v reálném čase pro odesílání obsahu klientům z back-endového serveru. Vzhledem k tomu, že komunikace probíhá v reálném čase, klientské aplikace zobrazují změny téměř okamžitě. To se obvykle zpracovává protokolem, jako je WebSockets, pomocí mnoha připojení WebSockets (jeden na klienta). Typickým příkladem je, když služba současně komunikuje se změnou skóre sportovní hry mnoha klientským webovým aplikacím.