Iznad mikroservisa: projektiranje za stvarnu složenost sustava
Mikrousluge se često predstavljaju kao prirodan sljedeći korak nakon monolita: podijelite aplikaciju, samostalno implementirajte usluge i dopustite timovima da se brže kreću. U praksi ta promjena može jednu vrstu složenosti zamijeniti s nekoliko težih. Kodna baza može postati manja po usluzi, dok sustav postaje teži za razumijevanje, testiranje, upravljanje i razvoj.
Korisno pitanje nije „monolit ili mikrousluge?” Ono glasi: gdje pripada složenost, tko je posjeduje i može li njome tim pouzdano upravljati? Dobra arhitektura čini važan rad očitim. Loša arhitektura raspršuje kritično ponašanje na mjesta koja su pojedinačno razumna, ali zajedno neprozirna.
Složenost ne nestaje kada se usluge podijele
Modularna PHP aplikacija koja radi kao jedna jedinica za implementaciju ima stvarna ograničenja: izdanja se dijele, korištenje resursa se dijeli, a kvar u jednom području može utjecati na drugo. No ona ima i vrijedna svojstva. Zahtjev se može pratiti u jednom procesu. Transakcija baze podataka može osigurati invarijantu. Refaktoriranje granice domene obično je promjena koda, a ne distribuirana migracija.
Kada sposobnost postane zasebna usluga, njezino sučelje postaje dugoročni ugovor. Pozivi mogu isteći. Poruke mogu stići dvaput. Implementacija može ostaviti dvije verzije koje rade istodobno. Zapis u bazu podataka može uspjeti dok događaj namijenjen obavještavanju druge usluge ne uspije. Ništa od toga nisu argumenti protiv usluga; to je uobičajeni trošak distribuiranosti.
Granica usluge stoga je opravdana nečim većim od strukture direktorija. Trebala bi predstavljati sposobnost koja se neovisno mijenja, granicu vlasništva ili potrebu za skaliranjem i pouzdanošću koja se ne može čisto riješiti unutar postojeće aplikacije.
Započnite s dobro strukturiranim monolitom
„Monolit” ne bi trebao značiti „jedan golemi sloj kontrolera izravno povezan sa svakom tablicom.” Monolit koji se može održavati može imati snažne unutarnje granice: module za naplatu, identitet, katalog i obavijesti; eksplicitne aplikacijske usluge; stabilna sučelja; i testove koji provjeravaju poslovna pravila bez pokretanja cijelog web-stoga.
Za PHP pozadinski sustav to često znači zadržavanje briga okvira na rubu. Kontroler prevodi HTTP ulaz u aplikacijsku naredbu. Kod domene odlučuje što je valjano. Infrastrukturni kod sprema podatke ili poziva vanjske sustave. Točan obrazac manje je važan od sprječavanja kopiranja poslovnih pravila u kontrolere, obrađivače reda, CLI naredbe i zakazane poslove.
Unutarnja modularnost stvara mogućnosti. Ako modulu kasnije zatreba neovisna implementacija, njegove su ovisnosti već vidljive. Ako mu nikada ne zatreba izdvajanje, tim i dalje ima koristi od jasnog vlasništva i manjeg broja slučajnih upita između modula.
Učinite ovisnosti namjernima
Praktično je pravilo da jedan modul ne bi trebao zadirati u pojedinosti perzistencije drugog modula. Ako modul narudžbi treba podatke o kupcu, izložite malo sučelje na razini aplikacije umjesto da dopuštate proizvoljna čitanja tablica kupaca. To može djelovati sporije od izravnog spajanja tablica, ali otkriva povezanost prije nego što ona postane ograničenje u produkciji.
Granice baze podataka zaslužuju jednaku pažnju. Zajednička baza podataka nije automatski neuspjeh, osobito u modularnom monolitu. Problem počinje kada svaka komponenta svaku tablicu smatra javnom. Dodijelite vlasništvo nad tablicama i migracijama, dokumentirajte nekoliko odobrenih putova integracije i oduprite se pretvaranju izvještajnih upita u skrivene ovisnosti za operativne tijekove rada.
Koristite API-je kao ugovore, a ne kao infrastrukturu
API je dogovor o značenju, a ne samo o obliku JSON-a. Polja trebaju vlasništvo, pravila životnog ciklusa, provjeru valjanosti i očekivanja kompatibilnosti. Odgovor nazvan status dvosmislen je dok korisnici ne znaju njegove dopuštene vrijednosti, mogu li se pojaviti nove vrijednosti i koje su radnje sigurne za svaku vrijednost.
Za sinkrone HTTP API-je od početka projektirajte za djelomični neuspjeh. Postavite vremenska ograničenja za povezivanje i zahtjeve. Namjerno obradite odgovore koji ne označavaju uspjeh. Ponovne pokušaje koristite samo kada je operaciju sigurno ponoviti ili je zaštićena ključem idempotentnosti. Ponovni pokušaj čitanja nakon prolaznog neuspjeha može biti razuman; slijepo ponovno pokušavanje stvaranja plaćanja može stvoriti duplicirani posao.
$response = $client->request('POST', '/orders', [
'headers' => [
'Idempotency-Key' => $requestId,
],
'json' => $payload,
'timeout' => 5,
]);
if ($response->getStatusCode() === 409) {
// Retrieve the existing result associated with the idempotency key.
}
Primjer je namjerno nepotpun: klijentu su i dalje potrebni obrada iznimki, zapisivanje koje izbjegava osjetljive vrijednosti i jasna politika za dvosmislene ishode. Ako mreža zakaže nakon što udaljeni sustav prihvati zahtjev, pozivatelj možda neće znati je li se operacija dogodila. Idempotentnost je način na koji sustav tu dvosmislenost pretvara u stanje iz kojeg se može oporaviti.
Odaberite asinkroni rad iz pravih razloga
Redovi su vrijedni kada se posao može obaviti kasnije, kada je potrebno ublažiti opterećenje ili kada zahtjev ne bi trebao čekati sporu vanjsku ovisnost. Oni nisu prečac oko dosljednosti. Posao u redu može kasniti, pokrenuti se više puta ili ne uspjeti nakon što se povezana transakcija baze podataka potvrdi.
Projektirajte radnike kao da svaka poruka može biti ponovno isporučena. Pohranite dovoljno stanja za prepoznavanje dovršenog rada, učinite obrađivače idempotentnima i definirajte što bi se trebalo dogoditi nakon što se iscrpe ponovni pokušaji. Red neisporučenih poruka sam po sebi nije rješenje; to je mjesto gdje neriješeni posao čeka operativnu odluku.
Kada promjena baze podataka na kraju mora objaviti događaj, obrazac odlazne pošte često je pouzdaniji od pokušaja izvođenja obje radnje u jednom zahtjevu. Aplikacija zapisuje poslovnu promjenu i zapis odlaznog događaja u istoj transakciji baze podataka. Zaseban objavljivač šalje neposlane zapise i označava ih kao objavljene tek nakon uspješne predaje. To ne omogućuje čarobnu isporuku točno jednom, ali sustavu daje trajan put oporavka koji se može pregledati.
Operativna jednostavnost arhitektonska je značajka
Docker može lokalna okruženja učiniti reproducibilnima, ali spremnici ne uklanjaju operativne odgovornosti. Usluga spremna za produkciju i dalje treba upravljanje konfiguracijom, provjere stanja, strukturirane zapisnike, metrike, sigurnosne kopije, disciplinu migracija i strategiju vraćanja na prethodnu verziju.
Migracije baze podataka posebno je lako podcijeniti. Implementacija aplikacije može nakratko istodobno pokretati stari i novi kod. Siguran slijed migracije obično najprije dodaje stupac koji dopušta null vrijednost ili novu tablicu, implementira kod koji može raditi s oba oblika, popunjava podatke u kontroliranim serijama i uklanja stare strukture tek nakon što se više ne koriste. Preimenovanje često korištenog stupca u jednom koraku često je rizik za dostupnost prikriven kao čišćenje.
- Postavite izričita ograničenja resursa i pratite rast memorije u dugotrajnim PHP radnicima.
- Odvojite spremnost od živosti: proces može biti živ, a da ne može poslužiti koristan promet.
- Povežite zapisnike, ID-jeve zahtjeva, poslove u redu i odlazne pozive kako bi se kvarovi mogli pratiti preko granica.
- Vježbajte vraćanje sigurnosnih kopija; sigurnosna kopija koja nikada nije vraćena pretpostavka je, a ne plan oporavka.
Optimizirajte sustav koji ljudi mogu sigurno mijenjati
Rad na performansama trebao bi početi izmjerenim uskim grlom. To može biti indeks koji nedostaje, ponovljeni upit, neograničen skup rezultata, spor put serijalizacije, iscrpljeni skup veza ili vanjski poziv na putu zahtjeva. Predmemoriranje može pomoći, ali također uvodi pravila invalidacije i ponašanje zastarjelih podataka koje se mora projektirati, a ne samo nadati da će nestati.
Isti pragmatizam vrijedi za dekompoziciju. Izdvojite uslugu kada trenutačna granica stvara ponavljajuće operativne poteškoće, sukobljen ritam izdanja, izolirane potrebe skaliranja ili model vlasništva koji postojeća aplikacija ne može podržati. Izdvajanje zato što dijagram izgleda moderno rijetko je dovoljno.
Arhitektura nije broj spremnika u produkciji. Ona je skup odluka koji timu omogućuje razmišljanje o promjeni, neuspjehu i oporavku. Disciplinirani monolit može biti izvrstan sustav. Pažljivo odabrana usluga može biti transformativna. Trajni je cilj jednostavniji: izgraditi granice koje odgovaraju stvarnosti, a zatim učiniti teške putove vidljivima prije nego što ih produkcija mora otkriti umjesto vas.