Mikroservisi: Kako smo monolit zamijenili distribuiranim monolitom
Otvaramo pacijenta: umro je od previše servisa i premalo razuma, a dijagnoza glasi resume-driven development.
Poglavlje 10 pričalo je priču pristojno. Kronologija, imena, godine, poneka anegdota o Netflixu i njegovim tisućama servera — sve uredno, sve s poštovanjem prema pokojniku. Ovo poglavlje nema tu ambiciju. Ovo je obdukcija, a na obdukciji se ne nosi crno odijelo i ne govori se u superlativima o pokojniku. Navuci rukavice. Ili nemoj — ionako ćemo zaprljati ruke.
Pacijent na stolu: zdrav razum u softverskoj arhitekturi. Vrijeme smrti: teško utvrditi, negdje između prvog konferencijskog slajda s naslovom „Kako smo skalirali na milijardu korisnika” i trenutka kad je netko u tvrtki s dvadeset zaposlenih rekao rečenicu koja bi trebala biti kažnjiva: „Trebamo to napraviti kao Netflix.” Da razjasnimo o čemu pričamo prije nego što krene seciranje: monolit je aplikacija napisana kao jedna cjelina, jedan program, jedna baza koda koja sve radi na jednom mjestu; mikroservisi su ta ista funkcionalnost razbijena na desetke malih, samostalnih programčića koji jedni s drugima pričaju preko mreže, umjesto da samo pozovu funkciju u istom programu. Netflix je to napravio jer je imao tisuće servera i milijarde zahtjeva na dan. Firma s dvadeset zaposlenih to je napravila jer je zvučalo cool na slajdu.
I tu počinje uzrok smrti, ili barem ono što forenzičar upisuje pod „sumnja se”: razvoj vođen životopisom (resume-driven development, kako to zovemo). Ne zloba, ne glupost u klasičnom smislu — nešto puno banalnije i puno opasnije. Inženjer koji gradi CV, ne sustav. Menadžer koji želi da tvrtka zvuči moderno na sljedećoj konferenciji. Konzultant koji prodaje dijagnozu prije nego što je uopće pogledao pacijenta, jer dijagnoza je uvijek ista i uvijek se zove Kubernetes — alat koji automatski upravlja i pokreće stotine tih malih servisa na serverima, tako da barem netko (u ovom slučaju stroj) drži pod kontrolom kaos koji ste upravo stvorili.
Devedeset posto firmi koje su rasjekle svoj, da budemo iskreni, sasvim funkcionalan monolit na dvadeset međusobno ovisnih komadića — nisu imale ni jedan posto Netflixovih problema. Imale su bazu podataka, tim od šestero ljudi i aplikaciju koja je radila. Sad imaju bazu podataka, tim od šestero ljudi, aplikaciju koja ne radi na dvadeset različitih načina, i alat za praćenje zašto ne radi koji košta više nego što je aplikacija ikad zaradila.
Dakle. Otvaramo pacijenta. Ne da bismo se sažalili — sažaljenje smo ostavili u poglavlju 10. — nego da vidimo, komad po komad, kako je pristojna, čak i pametna ideja umorena do smrti vlastitom popularnošću. Skalpel, molim.
Vrijeme smrti: negdje između 2015. i danas — teško je odrediti precizno, jer pacijent nije umro odjednom. Zdrav razum u arhitekturi softvera nije zaklan, nije mu prerezano grlo jednom oštrom odlukom — umoren je do smrti postepeno, slajd po slajd, na tisuću konferencija, u tisuću timova koji su svi gledali iste dvije-tri kompanije i mislili: ako oni tako rade, valjda je to ispravno.
Prije nego počnemo rezati, pogledajmo tijelo cijelo, izvana. Poglavlje 10. ove enciklopedije ispričalo je kako su Netflix i Amazon, još krajem 2000-ih i početkom 2010-ih, počeli objavljivati inženjerske blogove o tome kako su razbili svoje ogromne, nezgrapne monolite u stotine i tisuće malih, nezavisnih servisa. Bilo je to, kad su to Netflix i Amazon napravili, pošteno i korisno, i — za njih — nužno. Imali su tisuće inženjera koji su se međusobno gazili po istom kodu, imali su promet koji bi srušio bilo koji jedinstveni sustav, imali su probleme za koje je taj rez u komadiće bio racionalan, gotovo neizbježan odgovor.
Problem nije u tome što su to napisali. Problem je u tome kako je ta objava pročitana. Ne kao dnevnik jedne bolnice s jedinstvenim, teškim slučajem, nego kao sveto pismo. Novi zavjet arhitekture. I kao svako sveto pismo, prepisivana je bez razumijevanja konteksta u kojem je nastala, umnožena u tisuću propovijedi, dok se izvorna poanta — »ovo smo napravili ZATO ŠTO imamo problem koji ti nemaš« — jednostavno izgubila u prijevodu.
A tko je taj recept dalje širio, tko je bio taj propovjednik s pojačalom u ruci? Ovdje dolazimo do drugog organa koji je pri obdukciji pokazao znakove teškog, kroničnog oštećenja: konferencijska ekonomija. Poglavlje 5. već je spomenulo H1/K5 mašinu — onaj treći pogon industrije, uz plaću i dionice, koji tjera ljude da govore na konferencijama, pišu knjige, postanu konzultanti. E pa, mikroservisi su bili idealno gorivo za taj pogon. Zamislite predavanje naslova »Zašto smo ostali na monolitu i sve nam je super« — nitko ne kupuje kartu za to, nitko ne piše knjigu o tome, nijedan konzultant ne naplaćuje za savjet »nemojte ništa raditi«. Ali predavanje »Kako smo razbili monolit u 40 mikroservisa i postali cloud-native« — to puni dvorane, to prodaje knjige, to opravdava satnicu konzultanta koji je upravo doletio poslovnom klasom da vam kaže isto što je rekao i prošlom klijentu.
Rezultat te trostruke infekcije — svetog pisma bez konteksta, logičke greške u temelju i konferencijske ekonomije koja je sve to naplaćivala — vidljiv je posvuda, u svakoj srednjoj firmi koja je odlučila da je 2018. njena godina transformacije. Tipičan scenarij, viđen toliko puta da bi mogao biti standardni udžbenički primjer patologije: firma od pedesetak developera ima monolit. Taj monolit je ružan, star, pomalo zapušten — ali radi. Kupci ga koriste, novac ulazi, sustav pada rijetko, i kad padne, pada kao jedna stvar, jasno i predvidljivo. Netko na tehničkom sastanku, netko tko se upravo vratio s konferencije s naljepnicom »I'm a Kubernetes person« na laptopu, kaže: ovo je monolit, to je tehnologija iz 2010., moramo u mikroservise, tako radi Netflix.
Dakle, optužnica glasi ovako: pacijent — zdrav razum u arhitektonskom odlučivanju — umoren je ne jednim ubojicom, nego trojnom kombinacijom: kultom bez razumijevanja izvora, logičkom greškom prerušenom u mudrost i ekonomijom koja je profitirala od svakog novog kimanja glavom. Sad idemo otvoriti tijelo i pogledati što je zapravo nastalo umjesto monolita. Spremite se — nije lijepo.

Dokaz #1: distribuirani monolit
Nalaz prvi. Otvaramo pacijenta dalje i tražimo ono što je ubilo obećanje — nezavisnost. Jer to je bila prodaja, sjećaš se? Servisi koji žive svoj život, svaki u svojoj kućici, pa ako jedan crkne, ostali nastavljaju rintati kao da se ništa nije dogodilo. Lijepa slika. Sad pogledajmo dijagnostiku.
Servis za korisnike zove servis za narudžbe. Servis za narudžbe zove servis za plaćanja. Servis za plaćanja, iz razloga koje je davno zaboravio i sam autor koda, zove servis za preporuke — jer je nekome 2019. trebala jedna jedina brojka za personalizirani e-mail. I tako imaš lanac. A lanac je jak onoliko koliko je jaka njegova najslabija karika, samo što ovdje karike ne vise mirno na zidu — one se bude ujutro, deployaju se u petak popodne i imaju svoje mišljenje o tome hoće li danas raditi.
Razdvojeni imenom, spojeni sudbinom — to je nalaz. Napisali smo ih u različitim repozitorijima, dali im različite timove, različite planove razvoja, možda i različite boje u dokumentaciji — sve da izgledaju nezavisno. A onda plaćanja padnu u petak u 16:47, i pola tvrtke gleda nadzornu ploču (dashboard) koja svijetli crveno od korisnika do preporuka, jer se pokazalo da je nezavisnost bila kozmetička. Dobio si najgore od oba svijeta: kompleksnost distribucije, bez ijedne od njezinih obećanih prednosti. Monolit koji pada zajedno, samo sad s dodatnim koracima i s YAML datotekom za svaki korak — a YAML je, ako te zanima, samo format teksta u kojem se piše konfiguracija: tko se s kim spaja, koliko resursa nešto smije potrošiti i slično, dakle ne kod, nego uredan popis uputa koji i stroj i čovjek mogu pročitati.
A kako sad to pratiš? Pa treba ti „distributed tracing”, odnosno distribuirano praćenje — alat koji nacrta kartu jednog zahtjeva korisnika kroz jedanaest servisa, sa šesnaest mrežnih skokova, da bi ti na kraju rekao: evo, ovdje je kasnilo 340 milisekundi, u servisu koji zapravo treba samo zbrojiti dva broja. Cijela industrija alata — Jaeger, Zipkin, OpenTelemetry, konzultanti koji ti to instaliraju za lijepu svotu — postoji samo zato da ti pomogne pogledati ranu koju si sam sebi nanio. To nije dijagnostička oprema. To je zavoj koji plaćaš mjesečno, pretplatnički, po zahtjevu.
Ironija, ako patolog smije primijetiti ironiju: monolit ti je tu istu kartu davao besplatno. Zvao se stack trace — trag greške, odnosno ispis koji ti, kad se program sruši, pokaže točan redoslijed poziva koji su do pada doveli, kao kad bi netko snimio kamerom cijeli put lopte od bacača do razbijenog prozora. Otvoriš ga, vidiš cijeli put poziva, od vrha do dna, u jednoj datoteci, na jednom stroju, bez mreže između. Sve to gledaš kroz debugger, alat koji ti dopušta da program pustiš korak po korak i vidiš točno gdje je nešto krenulo po zlu — kao usporena snimka, samo za kod. Sad plaćaš platformu da ti simulira ono što je debugger radio nativno prije nego što je bilo cool razrezati stroj na komade i onda kupiti kompas da nađeš sjever.

Dokaz #2: resume-driven development
Drugi nalaz na stolu. Prvi je bio distribuirani monolit — arhitektura koja izgleda razdvojeno, a umire zajedno. Distribuirani monolit je najgore od oba svijeta — razbio si ga na komadiće, ali su ti komadići toliko međusobno ovisni da moraš paliti sve zajedno, kao i prije, samo sad s dodatnom mrežom koja može pucati. Ovaj drugi nalaz je gadniji, jer ne leži u kodu. Leži u glavama ljudi koji su kod pisali, i zove se, sasvim službeno u krugovima koji se ovim bave, resume-driven development. Nemoj se smijati imenu. Ono što opisuje ubija arhitekture svaki dan, samo sporije od infarkta — više kao dugotrajno trovanje.
Definicija je jednostavna, skoro dosadna u svojoj preciznosti: tehnička odluka se ne donosi zato što sustav to treba, nego zato što će ta tri slova lijepo stajati u životopisu. K8s na CV-u vrijedi više od Kubernetesa u produkciji. Ne metaforički. Literalno — jedno ti otvara vrata na sljedećem intervjuu, drugo ti donosi tri alarma iz sustava koji te budi u tri ujutro kad nešto pukne, i to baš u trenutku kad ti se najmanje spava. Gadanje pogodi koje od to dvoje inženjer, koji je i čovjek prije svega, podsvjesno gura naprijed kad predlaže arhitekturu.
I evo ključne stvari koju treba reći glasno, jer je ovo poglavlje o pronalaženju krivca, a krivac ovdje nije zloća — krivac je poticaj. Inženjer koji gura Kubernetes u sustav koji bi savršeno radio na jednom dobro odabranom serveru za trideset dolara mjesečno nije loš čovjek. On je racionalan čovjek koji igra jedinu igru koja mu je ponuđena. Tržište rada za developere ne plaća ljude koji su održali monolit stabilnim pet godina bez incidenta. Tržište plaća ljude koji na razgovoru za posao mogu reći: implementirao sam mikroservisnu arhitekturu sa service mesh slojem i distributed tracingom. Service mesh sloj, da razjasnimo, nije ništa mistično — to je dodatni komad softvera koji pazi na to kako servisi međusobno pričaju: ko s kim smije razgovarati, je li veza sigurna, i što se događa kad jedan servis ne odgovori pa treba pokušati ponovno. Jedna rečenica na intervjuu, i plaća skoči osjetno. Druga rečenica — održavao sam nešto što je radilo — zvuči kao da se ništa nije dogodilo. A upravo to, da se ništa nije dogodilo, jest definicija dobre arhitekture. Samo je nitko ne plaća bolje zbog toga.
Dakle, imaš sustav poticaja koji je, gledano hladno, savršeno logičan na razini pojedinca i savršeno katastrofalan na razini organizacije. Svaki pojedinačni inženjer optimizira svoju tržišnu vrijednost — i treba, jer nitko drugi to neće učiniti za njega. Firma pak dobiva zbroj tih optimizacija: dvadeset ljudi, svaki gura svoj komadić kompleksnosti koji dobro izgleda na papiru, i jednog jutra imaš sustav koji nitko u potpunosti ne razumije, sastavljen od komada koje je svatko birao zbog vlastite budućnosti, a ne zbog zajedničke sadašnjosti. Klasična tragedija zajedničkih pašnjaka, samo umjesto ovaca — YAML datoteke, kojima se danas štopa i podešava pola softverskog svijeta, od Kubernetesa do jednostavnog popisa što se pokreće kad server krene.
A onda dolazimo do sekte unutar sekte, hereze unutar hereze. Postoji pokret — nastao, dakako, kao reakcija baš na ovo što opisujemo — koji se zove „dosadna tehnologija” (boring technology, ako želiš izvorni naziv). Filozofija je bolno jednostavna: biraj alate koji su dosadni, provjereni, bez drame, jer svaki egzotičan izbor u tvom skupu alata (žargonski: stacku) jedna je kartica povučena iz ograničenog budžeta pažnje koji tim ima za rješavanje pravih problema. PostgreSQL umjesto sedam različitih baza podataka. Monolit umjesto dvadeset mikroservisa. Cron job, obična ugrađena naredba koja nešto pokreće po rasporedu (recimo svaku noć u tri), umjesto orkestratora poslova s vlastitim jezikom za konfiguraciju.
Dijagnoza, dakle, postaje jasnija sa svakim rezom skalpela. Nije kod bio bolestan. Ljudi koji su ga pisali nisu bili nesposobni. Bolestan je bio sustav poticaja koji je nagradio pogrešnu vrstu kompleksnosti — a taj sustav, za razliku od servera, ne gasiš restartom.

Obrana: ponekad stvarno trebaš
Patolog mora biti pošten, čak i kad drži skalpel nad tijelom koje je sam htio secirati. Zato, prije nego nastavim s nalazom, moram unijeti nešto u zapisnik što mi ne ide u prilog teze: mikroservisi nisu izmišljotina zla. Nisu prijevara koju su konzultanti smislili da bi naplatili radionice od tri dana. Postoji stvaran, dokumentiran, klinički potvrđen problem koji mikroservisi rješavaju — i taj problem se ne zove tehnologija. Zove se ljudi.
Zamisli firmu s pedeset timova. Ne pedeset developera — pedeset TIMOVA, svaki sa svojim vlasnikom proizvoda, svojim sprintom, svojim mišljenjem o tome je li petak dobar dan za objavu nove verzije. Svih pedeset timova radi na istom monolitu. Ali ovdje svih pedeset timova ima isti repozitorij, isti build, isti proces objave. Jedan tim doda ovisnost koja pukne test nekog drugog tima na drugom katu zgrade, tima koji ni ne zna da onaj prvi postoji. Konflikti pri spajanju koda nisu incident, oni su svakodnevnica. Nova verzija se objavljuje utorkom u tri ujutro jer je to jedini termin kad se ne gura pedeset timova u istu cijev istovremeno. To nije monolit. To je prometna gužva u kojoj su svi u istom autu, s pedeset volana, i svi vuku u svoju stranu.
Ovdje mikroservisi ne rješavaju tehnički problem. Rješavaju organizacijski. Svaki tim dobije svoj servis (svoj mali, samostalni komadić sustava), svoj repozitorij (svoje mjesto gdje čuva kod), svoj deploy pipeline (svoj automatizirani postupak kako taj kod ide u pogon) i, uglavnom, svoju sudbinu — i sad tim A može objaviti promjenu u utorak popodne bez da mora zvati tim Ž da provjeri je li ga slučajno srušio. To se zove nezavisnost isporuke, i za organizaciju te veličine ona nije luksuz. Ona je razlika između isporuke i paralize.
I tu dolazimo do kriterija, jer patolog koji samo osuđuje nije patolog, on je propovjednik. Kad mikroservisi imaju smisla? Prvo, broj timova — ne broj ljudi, broj TIMOVA koji moraju nezavisno donositi odluke o tome kad i što isporučuju. Tri tima ne treba trideset servisa. Trideset timova vjerojatno treba više od jednog. Drugo, stvarna skala — ne skala koju sanjaš u pitch decku (onoj šarenoj prezentaciji kojom se firma hvali investitorima koliko će jednog dana biti velika), nego skala koju već imaš na vratima: milijuni zahtjeva, ne desetci. Treće, različit životni ciklus — dio sustava koji se mijenja pet puta dnevno (recimo, preporuke) i dio koji se ne dira mjesecima (recimo, obrada plaćanja) imaju različite potrebe za objavom, testiranjem, čak i timom koji ih posjeduje. Kad ta tri kriterija stvarno postoje — ne kad ih izmisliš da opravdaš odluku koju si već donio na konferenciji — mikroservisi nisu moda. Oni su lijek.
Ono što ubija pacijenta, dakle, nikad nije bila sama tehnologija. Skalpel nije krivac ako liječnik operira zdravo koljeno samo zato što je vidio poznatog kirurga da to radi na YouTubeu. Uzrok smrti u ovom slučaju je dijagnoza koja nikad nije napravljena — kopiranje lijeka bez pitanja postoji li uopće bolest. Netflix je imao stotine timova, više od dvjesto milijuna korisnika i probleme koje ti nikad nećeš imati. Ti imaš četiri developera i CRM koji radi. Terapija se ne prepisuje zato što je nekom drugom, u drugoj bolnici, s drugim pacijentom, spasila život.

Nalaz i lijek
Vrijeme smrti utvrđeno je, uzrok smrti nazire se. Ali obdukcija nije gotova dok patolog ne zapiše nalaz — a nalaz, kolega, glasi ovako: pacijent nije umro od mikroservisa. Pacijent je umro od kopiranja tuđe dijagnoze bez vlastitih simptoma. I evo, kao svaki dobar patolog, moram reći i ono što nitko ne voli čuti na kraju obdukcije — da je i sam pacijent, dok je još hodao i disao, aktivno sudjelovao u vlastitom umiranju.
Trend se, za one koji prate nekrologe u ovoj struci, već okreće. „Monolith-first” postao je legitiman termin na konferencijama koje su prije pet godina prodavale isključivo mikroservise — ista publika, ista pozornica, druga religija. Modularni monolit, ta čudna hibridna zvijer koja izgleda kao monolit ali se ponaša disciplinirano, iznenada je kul. A boli i onaj Prime Video slučaj koji smo već spomenuli, kad je Amazonov tim javno priznao monitoring streaminga vraćen u monolit i uz to smanjio troškove infrastrukture za preko 90 posto. Amazon. Firma čije su objave na inženjerskom blogu (poglavlje 5, poglavlje 10) doslovno pokrenule cijelu ovu epidemiju. Hereza iz srca hrama — kad svećenik javno kaže da bog možda ne postoji, vjernici obično počnu čitati sitna slova.
Recept postoji, i nije ljutit — patolog ne mora vikati da bi bio uvjerljiv, dovoljno je da ima brojku. Broj servisa u tvom sustavu treba biti manji ili jednak broju timova koji ih održavaju. To je cijela formula. Nije iz knjige o softverskoj arhitekturi — to je organizacijska matematika, i ona dolazi prije tehničke. Ako imaš tri tima i dvadeset servisa, nisi napravio mikroservisnu arhitekturu. Napravio si dvadeset razloga da nikad ne spavaš mirno, podijeljenih na troje ljudi koji sad moraju znati dvadeset stvari umjesto jedne.
Konstruktivan zaključak ove obdukcije, jer patolog ipak mora nešto reći obitelji prije nego zatvori vrata: najhrabrija arhitektonska odluka ovog desetljeća nije usvojiti mikroservise. Najhrabrija je odluka reći na sastanku da se ostaje na dosadnom monolitu dok stvarno, dokazivo i mjerljivo ne zaboli — a kad zaboli, to priznati bez sramote i rezati po granicama koje bol pokaže, ne po granicama koje je netko nacrtao na Netflixovu blogu. Dosadno ne prodaje ulaznice za konferencije. Dosadno ne puni CV. Dosadno — samo radi.
I to je, u konačnici, nalaz ove obdukcije, ali i tiha nit koja prolazi kroz cijelu ovu enciklopediju, od OS/2 do danas: najskuplja navika ove struke nije loš kod, nije loša tehnologija, nije čak ni loša arhitektura. Najskuplja navika je kopiranje tuđeg rješenja bez ijednog trenutka potrošenog na pitanje koje je, zapravo, bio problem. Netflix je imao problem. Ti, vjerojatno, nemaš. Razlika između te dvije rečenice vrijedi, u praksi, poneki otkazani vikend dežurstva.