Golang microservice framework

Hello!

Ha valaki nagy üzemben gyárt goval mikroszervízeket - használ hozzá bármilyen framework-öt?

Go-Kit, Go-Micro, stb. - mik a tapasztalatok?

Csomó helyen olvasom hogy ma már nem javasolt a go-kit. Nekem meg a Go-Micro valahogy nem áll kézre.

Van még esetleg más amit érdemes megnézni, ki mire esküszik?

Hozzászólások

Szerkesztve: 2022. 12. 10., szo – 12:34

Nem nagyüzemben, csak saját felhasználásra, kvázi hobbiból.

Én eszerint építkezem:

The Best Go framework: no framework?

Illetve a cikkben hivatkozott könyvből (Go with the Domain - Building Modern Business Software in Go):

I’ve heard many times the question from newcomers to Go what framework they should use to create an HTTP service. I always advise against using any kind of HTTP framework in Go. A simple router, like chi is more than enough. chi provides us only the lightweight glue to define what URLs and methods are supported by our API. Under the hood, it uses the Go standard library http package, so all related tools like middlewares are 100% compatible.

It may be a bit weird to not use a framework if you are coming from any language where Spring, Symfony, Django, or Express may be the obvious choice. It was weird for me too. Using any kind of framework in Go adds unnecessary complexity and will couple your project with this framework. KISS.

Mit csinálsz vele? Eddig nem értettem meg, hogy miért jobb mikroszervízbe tenni bármit is, miért jobb egy http hívás, mint egy sima metódushívás? Kivéve persze ha teljesen független csapat csinálja, vagy pláne más programozási nyelven. De ha egy a csapat és a programozási nyelv, akkor van ennek bármi értelme?

(tudom, hogy nem nekem szólt a kérdés, de én is válaszolok)

Bár én csak nagyon egyszerű dolgokat csinálok (eddig), mégis próbálom úgy felépíteni a rendszeremet, amibe beleszerettem a Unixban, hogy minden egység egy dolgot csinál (jól), és könnyen össze lehet őket drótozni.

Ha pedig később fejleszteni kell, akkor elég ahhoz az egységhez hozzányúlni, a többi nagyjából változatlan maradhat.

Pl. van egy egység, ami az adatbázisért felelős, ott most a PoC szintjén csak egy SQLite van, és ha egyszer ez kevés lesz, akkor kap egy izmosabb adatbáziskezelőt. Tudom, hogy monolitban is simán le lehet cserélni a DB layert, de ez mégis más érzés.

Ami nálam most nyitott kérdés ez ügyben, hogy hosszú távon melyikkel járok jobban: HTTP/JSON vagy gRPC interfész. A JSON output egyszerűbb, könnyebb tesztelni, egy curl | jq bármikor kéznél van. A gRPC pedig kódilag egyszerűbb (egy szint megugrása fölött), az adattípusok egyértelműek, nincs konverzió, tényleg csak egy metódushívás.

Grpc -vel játszok én is egy ideje nagyon szeretem. Felmerült már, hogy jó lenne a protobuf adatot egy mezőben eltárolni, nem kellene JSON-ba sorosítani vagy bonyolult db struktúrát létrehozni. Viszont nem igazán találtam adatbáziskezelőt, mely ezt  támogatná. Sqlite-ban megoldottam egy saját proto függvénnyel mely segítségével a proto descriptort használva tudok keresni a protobuf binaris adatban és indexeket is tudok vele készíteni a mezőhöz. Viszont a descriptor jóval lassabb mint a fordított proto bináris, 2M mező nálam 20 perc míg újraindexeli. Egyedi beszúrásoknál, módosításoknál nem okoz teljesítményproblémát az index frissítése, de nem tudom mennyire bízhatok meg benne.
Ti hogy tároljátok a protobuf adatokat ?  

Kifejtenéd?

Ennek a dögnek elég komplex test-case-ei vannak, és hiába vannak unit/IT tesztek, igazából a manuális tesztelők sem tudják rendesen letesztelni, nem hogy értelmes regressziót csináljunk, ha frissítunk framework-öt.

Eddigi tapasztalatom szerint egy jó contract based kommunikációval, jó tesztlefedettséggel egész jól meg tudtam szabadulni az ilyen irányú fear-től.

A version hellt eddig el tudtuk kerülni értelmes API verziózással, contract testinggel, stb.

De az biztos, hogy elég sokat kellett magyarázni az üzemeltetésnek, hogy hogyan tudjuk garantálni azt, hogy egy adott verzió működik a másik verziójú appal.

Volt rá olyan ötlet is, hogy adjuk le a letesztelt staging 30 appjának a verzióját, és azt rakjuk ki élesre. Úgy, hogy 6-8 csapat tök párhuzamosan deploy-ol staging-re, és prodra. De ugyanakkor meg a rollback is külön témakör, ha van elméletileg független 30 appod, mire rollback-elsz vissza hiba esetén?

Nehéz kérdések ezek.

Event driven archi lenne (EventSourcing, CQRS)

Nagyon képlékeny itt minden - de a go-micro pl azért volt szimpatikus mert "plugin"-okkal elég könnyen konfigurálható és azt ígéri együtt működik Etcd, NATS,Kafka, és társaival könnyen - out of the box jelleggel.

Kb 30-40 service-nek kellene jól működnie - Spring boot versenyzik a Goval jelenleg.

A "no framework" szemlélet is izgalmas - erre nem gondoltam még.

Mi egyébként a cél?

- Nagyobb sebesség?
- Alacsonyabb memória foglalás?
- CV driven development?

Ha még nincs Go, akkor:
- Hogyan fogjátok felszedni a tudást? Van erre terv?
- Code review-zni ki fog?
- Mennyi időt szántok arra, hogy a pipeline-ok kialakuljanak? (docker base, fordítások, tesztek, stb.)
- Léteznek-e azok a könyvtárak, amiket akár most, akár a jövőben fogtok használni? Ha nem, akkor ki fogja megírni? Ez mennyibe kerül?
- Tooling (checkstyle, pmd, sonar, stb.)-nak megvan-e a megfelelője?
- Tesztelés hogyan történik majd?
- Jogosultságkezeléssel mi lesz?
- Akartok-e több nyelvet támogatni (ha már MS architektúra? Mi a helyzet a fentiekkel?)?
- Amikor azt mondjátok hogy out of box működik valami, az VALÓBAN működik, vagy csak az internet mondja?
- DB módosítás és eseményküldést hogyan is szeretnétek tranzakcióba rakni?
- Loggolás (elosztott rendszerben különösen kellemes)-re van már megoldásotok ami production-ben van?

Azért kérdezem ezeket, mert egy hasonló helyzetben elég sok mindenbe benéztük, hátha megússzátok :D

Egyszer kellett végigmennem ezeken a kérdéseken, végül abban maradtunk, hogy kipocolni mindet több idő lenne, mint amennyit most rá tudunk szánni, vagy amennyi pénzt várhatóan hozna (már nem emlékszem, hogy a Goland, vagy az ExpessJS). Főleg az eloszott loggolás volt a fő kérdés, hogyan utazzon a span/traceId, mert az nem mindig volt adott.

A hozzáadott érték elég bonyolult kérdés. A microservice divatos buzzword, és a farvizén hasznos eszközök, gyakorlatok kerülhetnek be egy céges IT-ba. Akkor is, ha adott feladatra esetleg nem a microservicekből álló alkalmazás architektúra az optimális. Főleg nagyvállalatoknál, ahol az egy hozzáadott érték management szempontból, ha divatos és trendi dolgokkal tudják magukat összefüggésbe hozni. Lehet is adni a döntéshozók alá a lovat, micsoda rakétatudományt fog ezzel meghonosítani a cég, az elavulét/meghaladott/zgenerációmárilyetnemhasznál technológiák mellett/helyett. Végülis, nagyot nem is lódítasz, meg a menedzserek sem most jöttek le a falvédőről értik hogy miben mesterkedsz mert ők meg minden nap ezt csinálják, de ha megtalálják benne a számításuk akkor mellé állnak. Az IT-nek is haszon, mert be tud emelni hasznos dolgokat, amiket önmagában, nem valami divatos dologhoz kapcsolva esetleg esély sem lenne. Én nem beszélnék le róla senkit, meg nem is óvatoskodnám túl, csak lássad mit nyersz vele és mibe fog kerülni. 

A microservice divatos buzzword, és a farvizén hasznos eszközök, gyakorlatok kerülhetnek be egy céges IT-ba.

Évtizedek óta vannak microservice dolgok a céges IT-ban, csak más neve volt és kurva drágán adták, lásd Enterprise Service Bus a kétezres évek elejéről... most fedezik fel ugyanezt, csak microservice a neve és ugyanazokkal a dolgokkal szopnak, ami miatt az ESB nem terjedt el. :D

Cseréld ki az ESB-t arra, hogy microservice: "ESBMicroservice provides a highly distributed approach to integration, with unique capabilities that allow individual departments or business units to build out their integration projects in incremental, digestible chunks, maintaining their own local control and autonomy, while still being able to connect together each integration project into a larger, more global integration fabric, or grid."

Egy lassan 20 éves könyv fülszövegéből idéztem: https://www.amazon.com/Enterprise-Service-Bus-Theory-Practice/dp/059600…

A marketing szerint most ez az aktuális ultimate solution. Van amikor jó választás szakmailag is nem csak PR szempontból, és van járulékos haszna. Viszont az ESB alapú vállalati alkalmazás integráció sokkal összetettebb és szerteágazóbb, mint ami egy mikroszervizekből álló alkalmazáson belül előfordul akár restapi, esemény stream vagy message broker alapú a szervizek közti kommunikáció. Ne ijesszed el az érdeklődőket, aki tapasztalt már meg bts vagy osb drámát, hibakeresését az ilyen hasonlattól könnyen elrettenhet :)

Nos ezek valóban releváns kérdések.

A fantázia azért szabadult el  mert teljesen zöldmezős a történet, és kb 2, max 3 év van rá. Lóvé van és nem csak duma hogy skálázni kell, hanem bizonyítottan valódi üzleti igény.  Itt ott jelennek meg a terhelések a jelenlegi "monolitban" - overall performance konstans gatya...

A könyvtárak 98%a már létezik - Java alapon hót ziher...golang épp lehet kérdés, de ott is van legalább 60%-os "lefedettség" első ránézésre. Go esetében nagyobb a lutri egy egy lib kapcsán mint a Java esetében ez tény. "out of the box" - azért kérdés és született meg a témanyitó - mik a tapasztalatok, mivel az internet azt mondja - sokszor okosakat, sokszor meg kuka....de ezek szerint a marketing duma alatt már nem annyira fényes a jövő. Go-kit első ránézésre, némi PoC után elég szépen néz ki - csak épp a Github-on található issue-k jelentős része már egy éve issue. Go-Micro nagyot ígér, de dokumentációt ha valaki talált hozzá normálist - na vissza ne tartsa.

A téma ugyan Golang-ra lett kihegyezve, de végül is a Spring kapcsán is lehet kérdés, mennyire alkalmas és stabil egy ilyen történethez. Szép nagy és lassú, memóriaéhes monolitokhoz tudjuk hogy kiválóan alkalmas. Valamiért a RedHat is nekiállt megcsinálni a Quarkust és teszi bele a lóvét - fene se tudja.

Max 2 nyelv...nem tervezett hogy "bárki bármiben bármit is" csinálhat és a Microsoft minden megjelenési formája is kizárva.

Authn authz - nem megoldott még - de bízunk valami normális szabványos OAuth2es szerverben - szoftvertermékben (az se baj ha drága...)

Loggolásra viszont van jó és jelenleg is production megoldás...arról tudjuk hogy kellően drága, azaz alkalmas.

Tisztelettel köszönöm hogy megosztottad a tapasztalatokat a kérdéseiden keresztül!

A téma ugyan Golang-ra lett kihegyezve, de végül is a Spring kapcsán is lehet kérdés, mennyire alkalmas és stabil egy ilyen történethez. Szép nagy és lassú, memóriaéhes monolitokhoz tudjuk hogy kiválóan alkalmas. Valamiért a RedHat is nekiállt megcsinálni a Quarkust és teszi bele a lóvét - fene se tudja.

Nekünk a podjaink Spring Bootban 10 mp alatt indultak el kb, de nem zavar minket, mert a liveness delay 1 perc... Csak, hogy biztosan elinduljanak (általában 30 sec connection timeout van nálunk beállítva, és ~10+30 < 60 sec). Plusz a horizontal auto scaler sem ült fel minden spike-ra. Memóriából 300-400 MB van nekik allokálva. A Quarkus jó dolog első ránézésre, most PoC-olják a srácok, szóval még nincs prodban. Ha lesz, akkor lejjebb csavarhatjuk valószínűleg a potikat, miután a mindenféle stressz tesztet lefuttatuk minden konfigban. Szerintem nem fogja megérni, de majd akkor megyünk át ezen a kapun, amikor odaérünk.

Loggolásra viszont van jó és jelenleg is production megoldás...arról tudjuk hogy kellően drága, azaz alkalmas.

Remélem nem csak ez a feltétel, hogy drága :D Nekem drágával a Datadoggal volt tapasztalatom, egy konferencia után hoztam be őket a céghez. Jól integrálható volt, de RabbitMQ-nál voltak problémák. Egyszer kézzel kellett populálni, egyszer meg nem ment rendesen a grafikus tracing - ez pár nap alatt béta jarban lett javítva, nagyon elégedett voltam.

>Itt ott jelennek meg a terhelések a jelenlegi "monolitban" - overall performance konstans gatya...

Általánosságban elmondható, hogy a skálázhatóság messze nem csak a frameworkről szól, hanem konkrétan skálázhatónak kell tervezni a rendszert, hogy végül valóban skálázható legyen. Monolitban is lehet skálázható rendszert csinálni, ugye a monolitból is indíthatsz több példányt, ha kell. Mármint ha úgy lett megtervezve, hogy lehessen...

Amit írsz, az nekem úgy hangzik, mint az iwiw újraírása, ha emlékszel, akkor a J2EE volt talán a buzzword, és azt mondták, hogy abban lesz újraírva és akkor majd gyors lesz. Aztán újraírták nagyon sok idő alatt, de mégsem lett gyors (csak userként láttam, nem tudok részleteket, de kívülről ez a sztori látszott). Mert nem azon múlik, hogy milyen nyelvet meg keretrendszert választunk, hanem hogy rendesen meg van-e tervezve a rendszer skálázódás szempontjából.

A mikroszervizes skálázódásról az jut még eszembe, hogy mondják, hogy így meg úgy lehet ezer példányt indítani elosztottan és húdejó, mert skálázódik, aztán kiderül, hogy a szükséges teljesítményt egyébként ha nem kellene minden függvényhívás helyett JSON-t szerializálni meg deszerializálni és HTTP-n átküldeni, akkor az egészet kiszolgálná az első laptopom is, amit 2007 körül vettem annó. És még gyorsabb is lenne, mert a latency az olyan állat, hogy összeadódik és ez sajnos fizikai törvény, ha kauzális viszony van két történés között, akkor a futásidejük összeadódik.

Igazad van. A többszálú program is hülyeség, viszi a memóriát és még várhatsz is a szemaforokra. Bezzeg régen milyen zsír per core teljesítményű procik voltak. Jó, hát befűtötte a szobát, de a lovakat etetni kell mint tudjuk. A projektben te leszel a király, hamarabb kész van, kevesebb ember kell hozzá, nem kell aki a sok szirszar környezeti komponenst pöcögteti, több marad a kalapban, hetedhét országra szóló projekt záró vacsora is kijön a maradékból. Aztán telik múlik az idő, rákapnak az ügyfelek a szolgáltatásra. Semmi baj, eszkaláljuk be az üzemeltetést, adjon erősebb procit. Per core... Hát olyan már nincs, akkor kicsi fejvakar, pár hét fejlesztés, persze teszt nélkül, tűzoltás közben ki ér rá arra? Kimegy az új sokszálú alkalmazás. Ujjak keresztbe, zsír, elbírja. Jah, versenyhelyzet probléma, nem determinisztikus eredménnyel erodálódik az adattartalom. Izzadás, pánik, pár hét-hónap kézi takarítás, amíg a javítás elkészül. Szépen szaporodnak az ügyfelek, már nem elég a 4db sokszálas proci. Üzemet újra eszkaláljuk, vegyen nagyobb vasat. Vett. Hát... Nem lett gyorsabb. Rohadjon meg aki a NUMA-t kitalálta, a cache koherenciáról nem is beszélve. Izzadás, kis szünet, amíg rá tudjuk fogni az üzemeltetésre, hogy nem elég nagy vasat vett. Kellemetlen, kaptak pénzt a világ legnagyobb vasára. De bakker, nem elég, sok ügyfélnek nincs jobb dolga mint karácsony előtt a mi rendszerünkön baszkódni. Jó, hát itt akart ajándékot venni a fantáziátlan parasztja, nem igaz, hogy nem bírja ki januárig... Közben jött valami sales sámán, hogy ez sem talált jobb munkahelyet... Képzeld, eladta a vezetőnek, hogy a mi termékünk a világpiacon is jó. Nem gondol arra a marha, hogy mire ideér a kattintás Amerikából, már meg is unta a vásárló a rendszerünket.

Meghívtak egy megbeszélésre. De valami hülye hívhatta össze, miért egy HR-essel kell beszélgetnem kubernetes-ről és mikroszolgáltatásokról?

Lásd: >>Monolitban is lehet skálázható rendszert csinálni, ugye a monolitból is indíthatsz több példányt, ha kell. Mármint ha úgy lett megtervezve, hogy lehessen...

Pont ezt mondom, hogy jól kell megtervezni az architektúrát. Ne legyen szűk keresztmetszet, ami nem skálázható. Ezt nehéz jól megtervezni és simán el lehet rontani mikroszervízekkel is. Pont ez a lényege a mondanivalómnak, hogy ha az architekt ott tart, hogy azt hiszi, hogy egy buzzword fogja megmenteni és nem a gondos tervezés és teljesítmény skálázódás tesztelés, akkor sajnos nagy az esélye a buktának.

A mikroszerviz önmagában annyit jelent, hogy a rendszer kis részeit külön gépekre telepítjük, és közöttük hálózaton kommunikálunk. Magyarul ami függvényhívás lehetne, az legyen HTTP-JSON-RPC. Van ahol szükség van rá, de csak azért csinálni mert most ez a divat, semmi értelme nincsen.

>A többszálú program is hülyeség, viszi a memóriát és még várhatsz is a szemaforokra.

A többszálúságról is egyébként eszembe jutott néhány régebbi programom, ami tök fölöslegesen volt többszálú. Sajnos a Javában elég későn jelent meg a NIO API, amióta értelmesen lehet egy szálon szervert programozni. Még egy jó light thread API kellene, hogy lehessen igazán hatékony webkiszolgálót csinálni benne.

Pont nemrégen alakítottam át egy többszálú programot egyszálúra a teljesítmény miatt: elképesztő, hogy mennyire drága a szálak közötti kommunikáció, érdemes kimérni vagy legalább utána olvasni!

Jaja, ugyan viccesre vettem a szöveget, de pont erre gondoltam, abszolút nem ördögtől való megoldások ezek, de tudd mikor melyiket miért használod és hogyan nem szorulsz be vele majd ha kell. A jó mikroszolgáltatás jó monolitból lesz, csak nagyon sokszor kell aláhúzni a "jó" szót. Ha jól tudsz strukturálni monoliton belül, kb nulla fájdalom a belső API hívást külsőre cserélni ha egyszer majd muszáj lesz. Optimalizálni is drága előre, de az még drágább ha olvashatatlan pókháló a kód és emiatt a refaktor kb esélytelen, így később az optimalizálás fizikailag nem megy. 

akkor a J2EE volt talán a buzzword, és azt mondták, hogy abban lesz újraírva és akkor majd gyors lesz

Az a baj, hogy a JavaEE/J2EE újraírás esetén valóban gyorsabb lesz sok minden, plafon a csillagos ég, viszont kurva magas a küszöb és kurva sokan vannak, akik nem értenek hozzá és ezért szar kód keletkezik, mert minden nyelven és platformon tudnak Fortran programot írni. Na, nekik lett a Spring, ahol alacsony a küszöb és nem érik el a plafont. Ha meg elérik a plafont, akkor jönnek a trükkös körbetákolások...

Szerkesztve: 2022. 12. 14., sze – 17:47

Egyetértek más hozzászólókkal, Gohoz nem kell semmilyen framework.

A Go egyébként egy érdekes nyelv. Ha mondjuk Java után a C++ valakinél idegrángást okoz, akkor a Go ahhoz képest semmi. Nincsenek osztályok, nincs öröklődés, nincs konstruktor (ha csak az általában New-val kezdődő nevű függvényeket nem vesszük ide). De még az olyan alapvetőnek tűnő dolgok, mint hogy egy függvény változója ránézésre a stacken jön létre, aztán mégis simán return-el visszaadható.

Külön epegörcs ez:

v, err := f(ctx)

Ami vagy létrehoz több változót vagy csak az egyiket vagy egyiket sem. Esetleg létrehoz, de már előtte volt egy ilyen nevű (shadowing).

Ha már itt tarunk, első körben esetleg meglepő, hogy mi a fene az a context (ctx). Eltart egy ideig, mire megérti az ember és szépen mindent átír úgy, hogy az legyen az első paraméter. Talán ez az egyik oka, amiért nem kellenek frameworkök, hanem pl. az OpenTelemetry a szerver middleware-ben elkapja a tracing headereket és a kliensig ctx-ben elutaztatja, ahol spannel magától egy kellemeset és kiküldi headerekben.

Ha valaki Pythonban unja a sok async - await-et, akkor Go-ban nagy megkönnyebbülés, hogy tízmilliószor jobb megoldások vannak, pl. alapesetben semmi ilyesmit nem kell írni. A go-routine-ok szuperek, a waitgroup igen kellemes, a mutex és atomic cuccok remekek.

Amúgy ha már microservice, első körben nem biztos, hogy a monolit szétverésével indítanék, hanem annak megértésével, hogy mi az a CNCF. Pl. ha a kódban van config management, akkor azt az utolsó szálig ki kell irtani. Config csak és kizárólag környezeti változóban jöhet, ha változás van, akkor a pod újraindul (pl. Helm upgrade, values.yaml -> configmap változik -> checksum a deploymentben változik -> rollout restart). Nyilván ebből eredően nincs olyan globális változó, amiért kár, ha elveszik. És ebből eredően annyi példány indul vagy áll le, amennyi kell a működéshez. Logot stdoutra írsz, majd vmi, pl. Fluentd összeszedi és azt kezd vele, amit csak akar. Metrikákat Prometheus-szal oldod meg, sok szép label-lel (max az üzemeltetők szablyával törnek rád a tárhelyigény miatt). Ha DB-hez mTLS hapcsolat van, akkor a cert-manager.io majd megcsinálja a certeket...