- "Kontextus"
- "Feltételezések"
- "Előfeltételes kérdések"
- Keret/technológiai választások
- Összehasonlítás
- Miért? 🤔 - „Kódolási paradigmák és minták”
- TL;DR
Kontextus
A közelmúltban a Jupiter elindította ügyfelei számára a befektetési alap platformjának tervezési kezdeményezését. Ez lehetőséget adott arra, hogy újraértékeljük azokat a technológiákat, amelyekre a Jupiter eddig támaszkodott, és azok teljesítményét a méretekben.
Ezek a legfontosabb szempontok, amelyeket meg kell tenni -
- Keret/technológiai választások
- Kódolási paradigmák, minták
A fenti szakaszok mindegyikénél újraértékelésre volt szükség annak ellenőrzésére, hogy a rendszerek mennyire méretezhetőek. Ez a gyakorlat abban is segített, hogy kitaláljuk rendszereink korlátait, és azt, hogy mennyire skálázódnak.
Feltételezések
- A közönség tisztában van a mikroszolgáltatás-architektúrával és az általa a monolitikus kóddal szemben nyújtott általános előnyökkel.
- A közönség elsősorban a JVM nyelvek bármelyikével dolgozik[link]
Előfeltételes kérdések
A funkcionális követelmények mellett a következő értékeléseket kell elvégezni.
Ezek a) csoportértékelést és b) projektértékelést egyaránt tartalmaznak -
- Mi a csapat alapvető szakértelme/tudásbázisa? Melyik nyelvet/keretrendszert ismeri a csapat?
- Van-e elegendő emberünk, sokrétű tudással és szakértelemmel, hogy elkerüljük a visszhangkamrát?
- Mennyi időbe telik a csapatnak, hogy új kereteket/technológiákat hozzon létre?
- Milyen méretarányra tervezik a rendszert?
- Mi az az idővonal, amelyet a termék elképzel? Melyek a mérnöki POV hozzávetőleges idővonalai [beleértve a műszaki értékeléseket, a POC-kat és a megfontolásokat]?
Ezeket a kérdéseket előzetesen átgondolva megbizonyosodhatunk arról, hogy a projekt nem lesz „BigBallOfMud”.
Keret/technológiai választások
Rómát sem egy nap alatt építették.
Itt is két alternatívát javasolunk, illetve ezek felhasználását különböző szolgáltatásokban.
Összehasonlítás
Miért? 🤔
Micronaut vs Spring-Boot
A Micronaut natívan felhőszolgáltatásokhoz készült, fordítási időben függőségi injekciót végez, és 50%-kal kevesebb rendszerindítási időt és memóriát igényel [a tavaszi rendszerindításhoz képest][link]
Kotlin vs Java
A Kotlin kevesebb kódsort igényel + könnyebb karbantartani és elfogadni + jó támogatást nyújt[link][link]
Feign vs Webflux vs Micronaut
A Feign natívan nem támogatja a reaktív programozást, és minden API-hívást blokkoló módon hajt végre. Ez azt eredményezi, hogy a szolgáltatás lefagy [elfogy a szálak] egy downstream szolgáltatás időkorlátja esetén.
A Webflux támogatja a reaktív működést, és jól integrálható az OpenAPI generátorral, így nincs szükség sok kazánlemez kódra.
A Micronaut alapértelmezés szerint felhőszolgáltatásokhoz készült, és nem igényel harmadik féltől származó API-klienseket
jOOQ, R2DBC és KMongo
A jOOQ R2DBC támogatás biztosítja, hogy a DB i/o természeténél fogva nem blokkoló legyen[link]
A MongoDB esetében a KMongo[link] azonnali objektum-leképezést biztosít, és típusbiztosítja a lekérdezéseket[link]
Sémaáttelepítés [TBD]
A MongoDB egy dokumentumadatbázis, és nem igényel séma-migrációt [nincs rögzített séma, amelyhez a gyűjtemény ragaszkodik]
Indexek és új gyűjtemények létrehozása esetén a Mongock[link] egy lehetőség. Alternatív megoldásként a lambda-nyomtatásban is gondolkodunk az esetleges ad hoc változtatásokhoz.
OpenAPI generátor
Az OpenAPI generátor megkíméli a csapatot attól, hogy sok kazánkódot írjon a szolgáltatáshoz szükséges kliensekhez/modellekhez.
Sajnos a Micronaut-ot jelenleg nem támogatja az OpenAPI Generator (béta)[link]. Ezért egyelőre az OpenAPI YAML specifikációt állítjuk elő a micronaut megjegyzések alapján.[link]
A következőre konvertálva:
Postgres vs MongoDB
A Postgres nem egy természetesen szilánkos adatbázis. Partícionálást biztosít, ami segít az indexek kisebb méretében, és gyorsabbá teszi a keresést.
Avégtelen léptékkel azonban végtelen problémák jönnek. Ha az adatok olyan mértékben felduzzadnak, hogy egyetlen szerver nem tudja feldolgozni azokat, még a particionálás is nehezen kezelhető.
A NoSQL segít a vízszintes skálázásban azáltal, hogy a táblákat természetes módon szilánkokra bonthatóvá teszi, csupán egy szilánkos kulcs meghatározásával. Ha egy alkalmazás hozzáférési mintái nem túl bonyolultak [azaz nem igényel túl sok csatlakozást, vagy nem függ az adatbázis triggerektől + tranzakcióktól], a dokumentum-adatbázisok gyorsabb kulcs-érték hozzáférést biztosítanak, és gyakorlatilag végtelenül skálázhatók.
Egyéb megfontolt lehetőségek: DynamoDB, ScyllaDB, Cassandra
Gyorsítótár
A Redis elsősorban az időtesztelt gyorsítótárazási rétegként szolgált, amely magából a gyorsítótárrétegből kiszolgálja a későbbi és ismétlődő felhasználói lekérdezéseket.
A Mongo-val azt tervezzük, hogy kibővítjük a használati esetet, hogy adattárként is működjön néhány gyors hozzáférésű adat számára, és ezáltal a rendszer kevésbé függjön az indexektől.
Például az összes felhasználói tranzakcióazonosítót időbélyegük szerint rendezve tároljuk a redis-ben, így a szeletelés és a kockázás magán a gyorsítótár-adatokon történhet, és a DB-t nem kell lekérdezni minden felhasználói kérésnél.
A DB elsősorban egy célt fog szolgálni – egy rekordazonosítóval lekéri a rekord részleteit [legyen szó felhasználókról, tranzakciókról, rendelésekről stb.]
Paradigmák és minták kódolása
Két dologra lehet elsősorban összpontosítani:
- Algoritmusok
- Hozzáférési minták
A probléma ezen részéhez nagyon sok forrás áll rendelkezésre, ezért csak a legfontosabb szempontokat említem meg.
- Tartsa be a SOLID alapelveit [link]
- Kerülje a már ismert dolgok újraszámítását/újbóli lehívását. Ha az adatok nem változnak gyakran, több helyen gyorsítótárazhatók [kliensoldali, CDN, szerveroldali, DB gyors hozzáférési réteg stb.]
- Kerülje az idő előtti optimalizálást [link]
- Tartsa szem előtt az általános felhasználói élményt
TL;DR
- Először vetítse ki a felhasználói forgalmat a rendszerére. Elemezze, hogy a következő 2 évben mekkora lesz a várható forgalom az alkalmazáson, és próbálja meg legalább 10-szeresét biztosítani. [Ez lehet az aktuális forgalom egyszerű kivetítése].
- A felhasználói forgalom alapján próbálja kitalálni a szűk keresztmetszeteket. Van olyan lekérdezés, amelynek futtatása túl sokáig tart, vagy sok adatbázis-számítást használ? Optimalizálható a lekérdezés? A lekérdezhető paraméterek indexelhetők, ha még nem?
- Ismerje meg rendszerének korlátait. A kód monolitikus, vagy van más egyetlen hibapontja? Az architektúrának vannak eredendő korlátai, például túl sok függőség és blokkoló hívás? Hogyan lehet ezt minimális változtatásokkal újra felépíteni?
- NE HAJTJA újra a kódot, hacsak nem feltétlenül szükséges. Ne optimalizálja túl, és kerülje el, hogy más mérnökök életét sokkal bonyolultabbá tegye a projekt jövőjében.