Monolit nebo microservices? Ani jedno, services!

Velké kusy jsou zlo, ať žijí co nejmenší kousky!

To je s čím se často setkávám. Mám však jiný názor: praktičnost je mnohem důležitější než cokoliv jiného. Pokud budu mít úplně vše v jednom a bude problém takovou obří věc nasadit – je to špatně. Pokud budu mít spoustu malých krabiček, které budou různě mezi sebou komunikovat, sahat si na stejnou databázi bez plné automatizace včetně monitoringu – je to taky špatně.

Jakoby by existoval buď jen obrovský neohrabaný monolit nebo spoustu malých microservices. To ale není pravda. Existuje taky celá škála mezi těmito pojmy.

Spousta lidí utíká před monolitem, protože je tak nějak obecně známé, že mít aplikaci jako monolit je špatné. A sexy slovo je microservices a vrhají se po něm, aniž by vlastně věděli proč a přinášelo to nějaký dobrý užitek. Nepochopte mne špatně, nejsem proti microservices. Jen mají velmi málo opravdových využití a pokud mají, je potřeba jim velmi dobře rozumět a být na ně připraven. To samé platí pro monolit.

Drtivá většina naopak potřebuje něco uprostřed, říkejme tomu services. Něco, co logicky patří k sobě. Do takového logického celku může patřit databáze, cron joby, API, webovka a cokoliv dalšího, co utváří službu. A všechny tyto části mít v jednom repozitáři.

Z toho plyne spoustu výhod:

  • Jednu změnu lze provést v jednom commitu.
  • Snadněji se bude testovat, že je celek funkční.
  • Vždy vím, co je s čím kompatibilní – to co bylo dohromady v jednom commitu.
  • Nejsou tak problémy se závislostmi.
  • Deployment je pak mnohem přímočarejší a v případě nouze i rollback.

Pokud se služba rozbije na microservices, výše zmíněné výhody budou tu tam. Jakmile začnou dvě microservices komunikovat se stejnou databází, musí být někde specifikován model a pomocné funkce k němu. Jenže kde? Velice pravděpodobně v nějaké extra knihovně a bude se muset řešit závislost. Tím začne boj o to, co s čím je vlastně jak kompatibilní, z čehož vyplývá i pořadí nasazování. Testování napříč celou službou začne být náročné až téměř nemožné a bude vznikat spoustu falst-positiv či false-negativ, záleží na stylu testů. O jedné logické změně přes víc repositářů ani nemluvě.

Někteří si mohou všimnout, že co popisuji nejsou ve skutečnosti microservices. A budu jenom souhlasit. Microservices mají v definici nezávislost nasazování. Mezi lidi se však nějak dostalo „monolit je zlo a jediné správné jsou microservices, což je jeden proces napsaný v jednom jazyku“.

Aby se microservices v tom podání, které popisuji, obhájili, často slýchám či čtu podobné reakce:

Mohu nasazovat různé části různě často. Jenže to právě vede k častým problémům. Co s čím je vlastně kompatibilní, jak něco takového testovat, v jakém pořadí se musí instalovat, … Pokud tým něco takového opravdu nutně potřebuje, pak může mít smysl vynaložit energii do řešení těchto problémů. Jinak rozhodně ne.

Délka buildu je s microservices mnohem kratší. Koho to vlastně trápí? Nikdo to stejně ručně dělat nebude. V případě microservices je potřeba tak jako tak mít automatizaci na všechno, takže nikdo těch pár vteřin ani nepocítí.

Lehčí udržet čistotu a může pracovat na aplikaci více lidí. To lze i u monolitu. Množšství kódu bude úplně stejně, jen lehce jinak rozházen. Velikost repozitáře není důležitá, například Google má jeden obrovský úplně se vším!

Lze lépe škálovat. Jsou situace, kdy bude lehce snadnější situace u microservices, každopádně jak poběží aplikace na serveru by mi nemělo diktovat, jak si strukturovat aplikaci. Navíc s dnešními kontejnery rozhodně nechci, aby aplikace řešila kde a kolikrát běží. Chci jen aby uměla běhat kolikrát bude potřeba.

Je to jednodušší. To snad nyní už ani nepotřebuje komentář. :-)

Abych to shrnul, běžte do microservices, ale do těch správných. Pokud vás to svádí ke špatným, říkejte tomu prostě jen services.

4 responses
Tak tohle stokrát podepisuju. Výsledkem aplikace hesla,že microservices jsou to jediný správný přístup pro škálovatelnost a absencí architektonické debaty jsme se dostali do stavu, kdy i poměrně jednoduchá aplikace se zkládal z neintutivních microservice, psaných různými lidmy a různým stylem. Jakákoliv úprava byznys logiky pak znamená zásah do více komponent, který by nejlépe měl dělat autor té komponenty (ostatní členové týmu ji často ani nemají u sebe ve vývojovém prostředí zprovozněnou). Nasazení té změný do produkce pak znamená koordinovaný release více kontejnerů, protože psát ty komponenty tak, aby dokázaly poskytnout tu novou funkci, ale zároveň se vyrovnaly s tím, že ten, kdo k tomu poskytne příslušná data, ještě běží ve staré verzi, je práce navíc. Jako největší problém microservice (alespoň v našem podání) ale vidím ve vlastnictví kódu: tím, že je daný služba malá, dokáže jí napsat a udržovat jeden člověk a pokud v týmu není dostatečná kultura code reviews a sdílení knowhow, můžou se tam schovávat špatná řešení, výkonostní nebo i bezpečnostní bomby. Případně si každý autor zavede svůj vlastní mechanismus konfigurace, logování, codestyle nebo dokonce programovací jazyk. Nemluvě o složitosti monitoringu. U nás bylo výsledkem, že jsme hodně microservice zrušili a slučujeme je do jednoho monolitu v Djangu. Sice to není tak cool jako Node.js microservices, ale věci, které byly v předchozím guláši vedly na složité interakce (které po pár měsících od nasazení zapomněli i autoři) se najednou ukazují jako trapný dotaz do databáze. A kvalitu kódu si najednou hlídají všichni, protože je to náš společný kód a ne individuální projekty.
@Vaclav: Ano, základní obal každé microservice (možná říkejme pikoservice?) na bambilion plus jeden způsobů s pokaždé jinou copy-paste chybou (či změnou) je zlo. Díky za doplnění. Souhlasím i s vlastnictvím kódu, jen mi to přijde společné ve všech případech. I na druhé straně v případě monolitu může být vlastnictví na úrovni modulů a sice aplikace jako taková se tváří jednotně, uvnitř to je však každý pes jiná ves. Rozhodně je větší šance, že u větších celků bude kód jednotnější.
Základní problém je v tom, že předpokládáš, že microservices sahají na stejnou databázi. To je ta chyba. Jeden ze základních principů microservices je, že musí být nezávislé a tudíž nesmí sahat na společnou databázi. Microservisy musí být oddělené a pokud mají databázi tak každá svojí. Pokud jedna microservice chce data z databáze, jiné microservice musí přes její rozhraní a nikoliv napřímo sáhnout do databáze. A doba buildu? že nezáleží na tom jak dlouho build běží. Záleží a hrozně moc. Pokud během několika minut po commitu dostanu z build serveru odpověď, že je něco rozbité, tak se okamžitě vracím k úkolu a opravuji co se rozbilo. Pokud ale build trvá několik desítek minut nebo i déle a pak třeba můj commit čeká ve frontě než se dokončí build dalších commitů, a já se dozvím, že se něco rozbilo po hodině nebo i třeba déle, tak je to problém, protože už pracuju na něčem jiném a mám dávno přepnutý context na úplně jiný problém.Takže build by měl být co nejkratší.
@Pavel D: Zřejmě si nerozmíme. Já nepředpokládám. Popisuji stav, který vidím kolem sebe. Tímto článkem na to upozorňuji a varuji. Viz odstavec: > Někteří si mohou všimnout, že co popisuji nejsou ve skutečnosti microservices. A budu jenom souhlasit. Microservices mají v definici nezávislost nasazování. Mezi lidi se však nějak dostalo „monolit je zlo a jediné správné jsou microservices, což je jeden proces napsaný v jednom jazyku“. Doba buildu je doba buildu. Testy bych s buildem vůbec nespojoval a pokud někdo řeší testy buildem, pak mi to nepřijde zdravý proces. Chci vědět ihned, zda co dělám, funguje, nikoliv až po commitu.