Návrh aplikace orientované na mikroslužby

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.

Tato část se zaměřuje na vývoj hypotetické podnikové aplikace na straně serveru.

Specifikace aplikací

Hypotetická aplikace zpracovává požadavky spuštěním obchodní logiky, přístupem k databázím a následným vrácením odpovědí HTML, JSON nebo XML. Řekneme, že aplikace musí podporovat různé klienty, včetně desktopových prohlížečů s jednostrákovou aplikací (SPA), tradičních webových aplikací, mobilních webových aplikací a nativních mobilních aplikací. Aplikace může také zveřejnit rozhraní API, které mohou využívat třetí strany. Měla by také být schopna asynchronně integrovat své mikroslužby nebo externí aplikace, aby tento přístup pomohl zajistit odolnost mikroslužeb v případě částečných selhání.

Aplikace se bude skládat z těchto typů komponent:

  • Součásti prezentace. Tyto komponenty zodpovídají za zpracování uživatelského rozhraní a využívání vzdálených služeb.

  • Doména nebo obchodní logika Tato komponenta je doménová logika aplikace.

  • Logika přístupu k databázi Tato komponenta se skládá z komponent pro přístup k datům zodpovědným za přístup k databázím (SQL nebo NoSQL).

  • Logika integrace aplikací Tato komponenta zahrnuje kanál pro zasílání zpráv založený na zprostředkovatelích zpráv.

Aplikace bude vyžadovat vysokou škálovatelnost a zároveň umožní škálování vertikálních subsystémů nezávisle na více instancí, protože některé subsystémy budou vyžadovat větší škálovatelnost než jiné.

Aplikace musí být schopná být nasazená v několika prostředích infrastruktury (více veřejných cloudů a místních) a v ideálním případě by měla být multiplatformní, schopná snadno přejít z Linuxu do Windows (nebo naopak).

Kontext vývojového týmu

Předpokládáme také následující informace o procesu vývoje aplikace:

  • Máte několik vývojových týmů, které se zaměřují na různé obchodní oblasti aplikace.

  • Noví členové týmu se musí rychle stát produktivními a aplikace musí být snadno pochopitelná a upravená.

  • Aplikace bude mít dlouhodobý vývoj a neustále se měnící obchodní pravidla.

  • Potřebujete dobrou dlouhodobou udržovatelnost, což znamená, že při implementaci nových změn v budoucnu potřebujete flexibilitu a současně můžete aktualizovat více subsystémů s minimálním dopadem na ostatní subsystémy.

  • Chcete si procvičit kontinuální integraci a průběžné nasazování aplikace.

  • Při vývoji aplikace chcete využívat nově vznikající technologie (architektury, programovací jazyky atd.). Při přechodu na nové technologie nechcete provádět úplné migrace aplikace, protože by to mělo za následek vysoké náklady a dopad na předvídatelnost a stabilitu aplikace.

Volba architektury

Co by měla být architektura nasazení aplikace? Specifikace aplikace spolu s kontextem vývoje důrazně naznačují, že byste měli aplikaci navrhnout tak, že ji rozložíte do autonomních subsystémů ve formě spolupráce mikroslužeb a kontejnerů, kde mikroslužba je kontejner.

V tomto přístupu každá služba (kontejner) implementuje sadu soudržných a úzce souvisejících funkcí. Aplikace se může například skládat ze služeb, jako je katalogová služba, služba objednávání, služba košíku, služba profilů uživatelů atd.

Mikroslužby komunikují pomocí protokolů, jako je HTTP (REST), ale také asynchronně (například pomocí AMQP), kdykoli je to možné, zejména při šíření aktualizací s událostmi integrace.

Mikroslužby se vyvíjejí a nasazují jako kontejnery nezávisle na sobě. Tento přístup znamená, že vývojový tým může vyvíjet a nasazovat určité mikroslužby, aniž by to mělo vliv na ostatní subsystémy.

Každá mikroslužba má vlastní databázi, která umožňuje úplné oddělení od ostatních mikroslužeb. V případě potřeby se konzistence mezi databázemi z různých mikroslužeb dosahuje pomocí událostí integrace na úrovni aplikace (prostřednictvím logické sběrnice událostí), jak je zpracováno v nástroji Command and Query Responsibility Segregation (CQRS). Z tohoto důvodu musí obchodní omezení přijmout konečnou konzistenci mezi několika mikroslužbami a souvisejícími databázemi.

eShopOnContainers: Referenční aplikace pro .NET a mikroslužby nasazené pomocí kontejnerů

Abyste se mohli soustředit na architekturu a technologie, nemusíte přemýšlet o hypotetické obchodní doméně, kterou možná neznáte, vybrali jsme dobře známou obchodní doménu – konkrétně zjednodušenou aplikaci elektronického obchodování (e-shop), která představuje katalog produktů, přebírá objednávky od zákazníků, ověřuje inventář a provádí další obchodní funkce. Tento zdrojový kód aplikace založený na kontejneru je k dispozici v úložišti GitHubu eShopOnContainers .

Aplikace se skládá z několika subsystémů, včetně několika front-endů uživatelského rozhraní úložiště (webové aplikace a nativní mobilní aplikace) spolu s back-endovými mikroslužbami a kontejnery pro všechny požadované operace na straně serveru s několika branami ROZHRANÍ API jako konsolidované vstupní body interních mikroslužeb. Obrázek 6–1 znázorňuje architekturu referenční aplikace.

Diagram of client apps using eShopOnContainers in a single Docker host.

Obrázek 6–1 Referenční aplikační architektura eShopOnContainers pro vývojové prostředí

Výše uvedený diagram ukazuje, že klienti Mobile a SPA komunikují s koncovými body brány rozhraní API, které pak komunikují s mikroslužbami. Tradiční webové klienty komunikují s mikroslužbou MVC, která komunikuje s mikroslužbami prostřednictvím brány rozhraní API.

Hostitelské prostředí. Na obrázku 6–1 vidíte několik kontejnerů nasazených v rámci jednoho hostitele Dockeru. To by byl případ nasazení do jednoho hostitele Dockeru pomocí příkazu docker-compose up. Pokud ale používáte orchestrátor nebo cluster kontejnerů, může být každý kontejner spuštěný v jiném hostiteli (uzlu) a jakýkoli uzel může spouštět libovolný počet kontejnerů, jak jsme si vysvětlili dříve v části architektura.

Komunikační architektura. Aplikace eShopOnContainers používá dva typy komunikace v závislosti na druhu funkční akce (dotazy versus aktualizace a transakce):

  • Komunikace mezi klientem a mikroslužbou http prostřednictvím bran rozhraní API Tento přístup se používá pro dotazy a při přijímání aktualizačních nebo transakčních příkazů z klientských aplikací. Přístup k používání bran rozhraní API je podrobně vysvětlený v dalších částech.

  • Asynchronní komunikace založená na událostech. Tato komunikace probíhá prostřednictvím sběrnice událostí za účelem šíření aktualizací mezi mikroslužby nebo integrace s externími aplikacemi. Sběrnice událostí se dá implementovat s libovolnou technologií infrastruktury zprostředkovatele zasílání zpráv, jako je RabbitMQ, nebo pomocí sběrnic služeb vyšší úrovně (abstrakce), jako jsou Azure Service Bus, NServiceBus, MassTransit nebo Brighter.

Aplikace se nasadí jako sada mikroslužeb ve formě kontejnerů. Klientské aplikace můžou komunikovat s těmito mikroslužbami spuštěnými jako kontejnery prostřednictvím veřejných adres URL publikovaných bránami rozhraní API.

Svrchovanost dat v jednotlivých mikroslužbách

Každá mikroslužba v ukázkové aplikaci vlastní vlastní databázi nebo zdroj dat, i když jsou všechny databáze SQL Serveru nasazené jako jeden kontejner. Toto rozhodnutí o návrhu bylo provedeno jen proto, aby vývojář snadno získal kód z GitHubu, naklonoval ho a otevřel ho v sadě Visual Studio nebo Visual Studio Code. Nebo také umožňuje snadno zkompilovat vlastní image Dockeru pomocí rozhraní příkazového řádku .NET a Rozhraní příkazového řádku Dockeru a pak je nasadit a spustit ve vývojovém prostředí Dockeru. Použití kontejnerů pro zdroje dat umožňuje vývojářům vytvářet a nasazovat během několika minut, aniž by museli zřizovat externí databázi nebo jiný zdroj dat s pevnými závislostmi na infrastruktuře (cloudové nebo místní).

V reálném produkčním prostředí by pro zajištění vysoké dostupnosti a škálovatelnosti měly být databáze založené na databázových serverech v cloudu nebo v místním prostředí, ale ne v kontejnerech.

Jednotky nasazení pro mikroslužby (a dokonce i pro databáze v této aplikaci) jsou kontejnery Dockeru a referenční aplikace je vícekontenerová aplikace, která využívá principy mikroslužeb.

Další materiály

Výhody řešení založeného na mikroslužbách

Podobné řešení založené na mikroslužbách má mnoho výhod:

Každá mikroslužba je relativně malá – snadno se spravuje a vyvíjí. Konkrétně:

  • Vývojářům je snadné pochopit a rychle začít s dobrou produktivitou.

  • Kontejnery začínají rychle, což vývojářům zvyšuje produktivitu.

  • Integrované vývojové prostředí (IDE), jako je Visual Studio, může rychle načítat menší projekty, což vývojářům umožňuje produktivitu.

  • Jednotlivé mikroslužby je možné navrhovat, vyvíjet a nasazovat nezávisle na jiných mikroslužbách, které poskytují flexibilitu, protože je jednodušší nasazovat nové verze mikroslužeb často.

Je možné škálovat jednotlivé oblasti aplikace. Například služba katalogu nebo služba košíku může být potřeba škálovat na více instancí, ale ne proces objednávání. Infrastruktura mikroslužeb bude mnohem efektivnější s ohledem na prostředky používané při horizontálním navýšení kapacity než monolitická architektura.

Vývojovou práci můžete rozdělit mezi několik týmů. Každou službu může vlastnit jeden vývojový tým. Každý tým může spravovat, vyvíjet, nasazovat a škálovat služby nezávisle na ostatních týmech.

Problémy jsou izolovanější. Pokud dojde k problému v jedné službě, má to na začátku vliv jenom na tuto službu (s výjimkou případů použití nesprávného návrhu s přímými závislostmi mezi mikroslužbami) a dalšími službami můžou dál zpracovávat požadavky. Naproti tomu jedna chybná komponenta v monolitické architektuře nasazení může snížit celý systém, zejména v případě, že zahrnuje prostředky, jako je nevracení paměti. Kromě toho, když dojde k vyřešení problému v mikroslužbě, můžete nasadit pouze ovlivněnou mikroslužbu, aniž by to mělo vliv na zbytek aplikace.

Můžete použít nejnovější technologie. Vzhledem k tomu, že můžete začít vyvíjet služby nezávisle a spouštět je vedle sebe (díky kontejnerům a rozhraním .NET), můžete začít používat nejnovější technologie a architektury, aniž byste se museli uvíznout na starším zásobníku nebo rozhraní pro celou aplikaci.

Nevýhodou řešení založeného na mikroslužbách

Podobné řešení založené na mikroslužbách má také některé nevýhody:

Distribuovaná aplikace Distribuce aplikace při návrhu a vytváření služeb vývojářům zvyšuje složitost. Vývojáři například musí implementovat komunikaci mezi službami pomocí protokolů, jako je HTTP nebo AMQP, což zvyšuje složitost pro testování a zpracování výjimek. Přidává také latenci systému.

Složitost nasazení Aplikace, která má desítky typů mikroslužeb a potřebuje vysokou škálovatelnost (musí být schopná vytvářet mnoho instancí na službu a vyrovnávat tyto služby napříč mnoha hostiteli) znamená vysokou složitost nasazení pro provoz a správu IT. Pokud nepoužíváte infrastrukturu zaměřenou na mikroslužby (jako je orchestrátor a plánovač), může tato další složitost vyžadovat mnohem větší úsilí o vývoj než samotná obchodní aplikace.

Atomické transakce. Atomické transakce mezi několika mikroslužbami obvykle nejsou možné. Obchodní požadavky musí přijmout konečnou konzistenci mezi několika mikroslužbami. Další informace najdete v problémech s idempotentním zpracováním zpráv.

Zvýšené globální potřeby prostředků (celkový počet paměti, jednotek a síťových prostředků pro všechny servery nebo hostitele) V mnoha případech, když nahradíte monolitickou aplikaci přístupem mikroslužeb, množství počátečních globálních prostředků potřebných novou aplikací založenou na mikroslužbách bude větší než potřeby infrastruktury původní monolitické aplikace. Tento přístup je způsoben tím, že vyšší stupeň členitosti a distribuovaných služeb vyžaduje více globálních prostředků. Vzhledem k nízkým nákladům na zdroje obecně a výhodě schopnosti škálovat určité oblasti aplikace v porovnání s dlouhodobými náklady při vývoji monolitických aplikací je obvykle dobrým kompromisem pro velké dlouhodobé aplikace.

Problémy s přímou komunikací mezi klientem a mikroslužbou Pokud je aplikace velká, s desítkami mikroslužeb, existují problémy a omezení, pokud aplikace vyžaduje přímou komunikaci mezi klientem a mikroslužbou. Jedním zproblémůch V některých případech může klientská aplikace muset vytvořit mnoho samostatných požadavků na vytvoření uživatelského rozhraní, což může být neefektivní přes internet a nepraktické přes mobilní síť. Proto by se měly minimalizovat požadavky z klientské aplikace do back-endového systému.

Dalším problémem přímé komunikace mezi klientem a mikroslužbou je, že některé mikroslužby můžou používat protokoly, které nejsou vhodné pro web. Jedna služba může používat binární protokol, zatímco jiná služba může používat zasílání zpráv AMQP. Tyto protokoly nejsou vhodné pro bránu firewall a nejlépe se používají interně. Aplikace by obvykle měla používat protokoly, jako jsou HTTP a WebSocket, pro komunikaci mimo bránu firewall.

Další nevýhodou tohoto přímého přístupu typu klient-služba je, že znesnadňuje refaktoring kontraktů pro tyto mikroslužby. Vývojáři můžou v průběhu času chtít změnit způsob rozdělení systému na služby. Mohou například sloučit dvě služby nebo rozdělit službu na dvě nebo více služeb. Pokud ale klienti komunikují přímo se službami, může provádění tohoto typu refaktoringu přerušit kompatibilitu s klientskými aplikacemi.

Jak je uvedeno v části architektura, při návrhu a vytváření komplexní aplikace založené na mikroslužbách můžete zvážit použití několika jemně odstupňovaných bran rozhraní API místo jednoduššího přímého přístupu ke komunikaci mezi klienty a mikroslužbami.

Dělení mikroslužeb A konečně, bez ohledu na to, který přístup pro architekturu mikroslužeb používáte, je dalším úkolem rozhodnout se, jak rozdělit komplexní aplikaci do několika mikroslužeb. Jak je uvedeno v části průvodce architekturou, existuje několik technik a přístupů, které můžete využít. V podstatě potřebujete identifikovat oblasti aplikace, které jsou oddělené od ostatních oblastí a které mají nízký počet pevných závislostí. V mnoha případech je tento přístup v souladu se službami dělení podle případu použití. Například v naší aplikaci elektronického obchodu máme objednávkovou službu, která odpovídá za veškerou obchodní logiku související s procesem objednávky. Máme také katalogovou službu a službu košíku, která implementuje další možnosti. V ideálním případě by každá služba měla mít pouze malou sadu zodpovědností. Tento přístup se podobá principu jedné odpovědnosti (SRP) použitému u tříd, který uvádí, že třída by měla mít jen jeden důvod ke změně. V tomto případě se ale jedná o mikroslužby, takže rozsah bude větší než jedna třída. Mikroslužba musí být ve většině případů autonomní, komplexní, včetně odpovědnosti za vlastní zdroje dat.

Vnější versus vnitřní architektura a vzory návrhu

Externí architektura je architektura mikroslužeb složená z více služeb podle principů popsaných v části architektura tohoto průvodce. V závislosti na povaze jednotlivých mikroslužeb a nezávisle na architektuře mikroslužeb vysoké úrovně, kterou zvolíte, je ale běžné a někdy vhodné mít různé interní architektury, z nichž každá vychází z různých vzorů pro různé mikroslužby. Mikroslužby mohou dokonce používat různé technologie a programovací jazyky. Na obrázku 6–2 je znázorněna tato rozmanitost.

Diagram comparing external and internal architecture patterns.

Obrázek 6–2 Externí versus interní architektura a návrh

Například v ukázce eShopOnContainers jsou mikroslužby katalogu, košíku a profilů uživatelů jednoduché (v podstatě subsystémy CRUD). Proto je jejich vnitřní architektura a návrh jednoduché. Můžete ale mít další mikroslužby, jako je například mikroslužba řazení, která je složitější a představuje stále se měnící obchodní pravidla s vysokou mírou složitosti domény. V takových případech můžete chtít implementovat pokročilejší vzory v rámci konkrétní mikroslužby, jako jsou ty definované pomocí přístupů DDD (domain-driven design), jak to děláme v mikroslužbě objednávání eShopOnContainers . (Tyto vzory DDD si projdeme v části později, která vysvětluje implementaci mikroslužby objednávání eShopOnContainers .)

Dalším důvodem pro jinou technologii pro každou mikroslužbu může být povaha každé mikroslužby. Může být například lepší použít funkční programovací jazyk, jako je F#, nebo dokonce jazyk, jako je R, pokud cílíte na domény umělé inteligence a strojového učení místo objektově orientovaného programovacího jazyka, jako je C#.

Na konci je to, že každá mikroslužba může mít jinou interní architekturu založenou na různých vzorech návrhu. Ne všechny mikroslužby by se měly implementovat pomocí pokročilých vzorů DDD, protože by to bylo příliš technické. Podobně složité mikroslužby s neustále se měnící obchodní logikou by neměly být implementovány jako komponenty CRUD nebo můžete skončit s kódem nízké kvality.

Nový svět: několik architektur a mikroslužeb Polyglot

Existuje mnoho architektur, které používají softwaroví architekti a vývojáři. Následuje několik (kombinování stylů architektury a vzorů architektury):

Mikroslužby můžete vytvářet také s mnoha technologiemi a jazyky, jako jsou webová rozhraní API ASP.NET Core, NancyFx, ASP.NET Core SignalR (k dispozici pro .NET Core 2 nebo novější), F#, Node.js, Python, Java, C++, GoLang a další.

Důležitým bodem je, že pro všechny situace není správný žádný konkrétní vzor architektury ani styl ani žádná konkrétní technologie. Obrázek 6–3 ukazuje některé přístupy a technologie (i když ne v žádném konkrétním pořadí), které by bylo možné použít v různých mikroslužbách.

Diagram showing 12 complex microservices in a polyglot world architecture.

Obrázek 6–3 Multi-architektonické vzory a svět mikroslužeb Polyglot

Multi-architektonické vzory a mikroslužby polyglot znamená, že můžete kombinovat a shodovat jazyky a technologie s potřebami jednotlivých mikroslužeb a stále je vzájemně komunikovat. Jak je znázorněno na obrázku 6–3, v aplikacích složených z mnoha mikroslužeb (ohraničené kontexty v terminologii návrhu řízené doménou nebo jednoduše "subsystémy" jako autonomní mikroslužby), můžete každou mikroslužbu implementovat jiným způsobem. Každý z nich může mít jiný vzor architektury a používat různé jazyky a databáze v závislosti na povaze aplikace, obchodních požadavcích a prioritách. V některých případech můžou být mikroslužby podobné. To ale obvykle neplatí, protože kontextové hranice a požadavky jednotlivých subsystémů se obvykle liší.

Například pro jednoduchou aplikaci údržby CRUD nemusí mít smysl navrhovat a implementovat vzory DDD. U základní domény nebo základní firmy ale možná budete muset použít pokročilejší vzory pro řešení složitosti firmy s neustále se měnícími obchodními pravidly.

Zvlášť když se zabýváte velkými aplikacemi složenými z více subsystémů, neměli byste použít jedinou architekturu nejvyšší úrovně založenou na jednom vzoru architektury. CQRS by například nemělo být použito jako architektura nejvyšší úrovně pro celou aplikaci, ale může být užitečná pro konkrétní sadu služeb.

Pro každý daný případ neexistuje žádná stříbrná odrážka ani správný vzor architektury. Nemůžete mít "jeden vzor architektury, který by je mohl ovládnout všechny". V závislosti na prioritách jednotlivých mikroslužeb musíte pro každou z nich zvolit jiný přístup, jak je vysvětleno v následujících částech.