Backend architektura

Návrh mikro/mini servisní architektury je obor sám o sobě. Jak služby rozdělit, aby byly samy o sobě škálovatelné? Která služba komunikuje s jakou? Co je bezstavovost a které komponenty se na to hodí? Pokud jde o technické aspekty komponent, v jakých jazycích je psát? A pokud teprve zvažujete přechod z monolitu na malé služby, co je třeba pro přechod zvážit?

Monolit nebo Mikroslužby?

Jako u všeho je třeba nejprve zvážit možné přínosy změn a neřídit se aktuální módou. I velké projekty jakým je například Windows, byly nejprve napsané jako jeden kód, pak se přešlo k mnoha malým kódům, aby se nakonec našlo nějaké hybridní optimum, jak velké mají oddělené moduly být.

Největší výhodou monolitu je jeho rychlost - zavolat metodu v jiné části kódu skoro nic nestojí. Mikroslužby se potýkají s latencí, i když i ta se dá výrazně snížit volbou gRPC nad Restem. Na druhou stranu oddělené služby vynikají v tom, že různé komponenty se dají napsat v různých jazycích, škálovat je nebo je libovolně vyměňovat a omlazovat tak celý systém. Každých pár let tak lze vyměnit celý systém po kouskách za nový.

Komunikace mezi službami

Služby mezi sebou mohou komunikovat více způsoby. Tím nejčastějším je přímé volání přes REST nebo gRPC. Pokud není pro danou službu rozhodující rychlost, stará se například o asynchronní postprocessing a potřebný vstup je malý, preferovanou volbou je REST pro svou jednoduchost použití. Jde o jednoduchá volání přes protokol HTTP, která si dokážeme jednoduše napodobit programy jako je Postman nebo i webový prohlížeč. Pro přenos větších objemů dat, od kilobajtů nahoru volaných synchronně, je vhodné zvážit protokol gRPC postavený na výrazně rychlejším HTTP/2. Tento protokol je postavený na myšlence volání vzdálených služeb pomocí jejich metod, tedy stejně, jako kdyby byli spolu v jednom monolitickém bloku.

Možné jsou i komunikace přes fronty, vhodné například pro batchová zpracování objektů, nebo různé eventy, kdy služba A zanechá pro službu B data na perzistentním úložišti, a trigger pak službu B spustí. Cloudová řešení mají vlastní služby pro zpracování front, v případě Googlu je jí například Pub/Sub. Konkrétní typ komunikace nakonec záleží na konkrétních službách.

Jazyk služby

Zvolený kód bývá žhavým tématem programátorů, navíc mnohdy značně emočně podbarveným. Racionalita je zde však důležitá. Při volbě je třeba zvážit rychlost/jednoduchost vývoje, dostupnost programátorů na trhu práce a vhodnost použití pro danou službu. Kódování videa v Pythonu není dobrým rozhodnutím, stejně jako správa kartotéky zaměstnanců v jazyce C. Pokud však tyto dva jazyky prohodíme, už nám jejich použití dává větší smysl.

Pokud je architektura v 5 a více programovacích jazycích, bude problém ho zásobovat novými programátory. I když v nějakém bodě možná i dávalo smysl napsat jednu z komponent v jazyce Haskell, protože jsme přece nechtěli chyby v kritické službě, ukázalo se to pak ne úplně šťastným rozhodnutím. Přidat pak dalšího člověka na takovou komponentu totiž může být nemožným úkolem.

Zde následuje běžný výběr jazyků pro backend:

  • Python: volba číslo 1 v aplikacích strojového učení nebo webu. Jazyk je velmi jednoduchý a napůl žertem se o něm říká, že je to jen logická angličtina. Na druhou stranu má špatnou správu balíčků, kvůli které můžeme časem řešit konflikty mezi nimi na denní bázi. Nepodporuje běh na více procesorech zároveň, takže může být náročné detekovat zahlcení a spuštění škálování v Cloudu. A běh je velmi pomalý. Pokud nejde o matematiku, tam je díky přímé komunikaci s C knihovnou naopak velmi rychlý.
  • C/C++: vyznačuje se velkou rychlostí běhu. Načíst do něj ML model však může být téměr nadlidský úkol. Navíc programátorů schopných v tomto jazyce napsat něco v rozumném čase je už dnes málo. Hodí se jako nematematický model, kde je kritická rychlost běhu, třeba jako knihovna do Pythonu nebo Go.
  • Go: zvládá vysokou rychlost běhu i vývoje, navíc je v něm jednoduché psát multiprocesorové programy. Jazyk z dílen Googlu připomíná dobrý hybrid mezi Pythonem a C. Nevýhodou je stále velká absence podpůrných knihoven, ve světě strojového učení zejména těch matematických. Ideální pro aplikace vyžadující velkou propustnost nebo různé workery.
  • Rust: poslední dobou populární jazyk, který podobně jako Go přichází s vlastním řešením vysoké náročnosti práce s pamětí v jazyce C, přičemž se snaží zachovat jeho vysokou rychlost běhu. Bohužel je poměrně složitý, stále vyžaduje vysoké nároky na programátora, což prodlužuje čas vývoje a nemá zatím moc podporu knihoven pro ML.
  • PHP: dříve populární jazyk pro web, dnes nahrazován Pythonem a Javascriptem. Do nových projektů už spíše nepatří.

Stavovost

Častou chybou je dávat přístup do databáze nebo disk všem službám. "Může se to hodit", jak se říkává. U některých služeb je však lepší, aby byly pouze "průtokové". Pokud máme limit na 200 připojení do databáze a každá z 20 služeb se začne v případě vyššího provozu škálovat, dojdou velmi rychle. Takto mohou zahltit každé naše médium.

Takzvané bezstavové služby, které odnikud nic nečtou, nic nikam nezapisují a pouze existují "v éteru", aby transformovaly vstup na výstup se velmi dobře škálují. Mohou tak pro nás dělat například preprocessing nebo postprocessing v poměrně vysokých počtech kopií sebe samých.

Závěr

Správná volba architektury závisí na mnoha faktorech. Pokud se chcete poradit, jestli je ta Vaše efektivní nebo přechod z monolitu na mikroservisní architekturu teprve plánujete, můžeme se sejít třeba na kávě.