Kai reikia sujungti du servisus tarpusavyje arba paruošti API klientinei aplikacijai, anksčiau ar vėliau atsiduri prie to paties kryžkelės klausimo: kurį protokolą rinktis. REST jau senokai tapo tokiu standartu, kad apie jį net negalvoji – tiesiog darai. Bet paskutinius kokius aštuonerius metus GraphQL ir gRPC vis stipriau įsibrauna į pokalbį, ir dažnai komandos ginčijasi valandų valandas, kol apsisprendžia. Pabandysiu paaiškinti, kuo šitos trys architektūros iš tikrųjų skiriasi, ir kada kuri turėtų laimėti.
REST – senas draugas, kuris niekur nedingsta
REST (Representational State Transfer) niekada oficialiai nebuvo „protokolas” – tai greičiau architektūrinis stilius, aprašytas Roy Fielding disertacijoje 2000 metais. Esmė paprasta: turi resursus (vartotojus, užsakymus, produktus), ir su jais dirbi per HTTP metodus – GET, POST, PUT, DELETE. Kiekvienas resursas turi savo URL, ir viskas atrodo gana intuityviai.
Kodėl REST vis dar dominuoja? Todėl, kad jis paprastas kaip duonos riekė. Beveik kiekvienas programuotojas, kad ir koks jaunas, žino, kaip su juo dirbti. Naršyklės, tinklo įrankiai, dokumentacijos generatoriai – viskas jau prisiderinę prie REST logikos. Jeigu darai paprastą CRUD sistemą, kur reikia sukurti, perskaityti, atnaujinti ir ištrinti duomenis – REST tikrai atliks darbą be jokių problemų.
Bet turi ir savo skaudulius. Vienas didžiausių – overfetching ir underfetching. Įsivaizduok, kad mobiliajai aplikacijai reikia tik vartotojo vardo ir nuotraukos, bet REST endpointas grąžina visą vartotojo objektą su dvidešimčia laukų. Tai reiškia papildomą tinklo apkrovą, lėtesnį veikimą, didesnes duomenų sąnaudas. O jeigu reikia susieti kelis resursus – pavyzdžiui, vartotoją, jo užsakymus ir tų užsakymų prekes – dažnai tenka daryti kelis atskirus užklausas iš eilės, kas vadinama „N+1 problema”.
GraphQL – kai kliento reikmės diktuoja atsakymą
GraphQL atsirado Facebook viduje 2012 metais, o viešai paskelbtas 2015-aisiais. Idėja buvo išspręsti būtent tas problemas, kurias minėjau aukščiau – kliento programa pati nusprendžia, kokius duomenis nori gauti, ir serveris grąžina lygiai tiek, kiek prašoma. Nei daugiau, nei mažiau.
Vietoj daugybės endpointų turi vieną vienintelį – dažniausiai /graphql. Užklausos formuluojamos specialia sintaksę, kuri primena JSON struktūrą, ir serveris atsako tokia pat forma. Tai iš esmės išsprendžia overfetching problemą – jei nori tik vardo ir el. pašto, tai ir gausi, nesvarbu, kiek dar laukų turi tas objektas duomenų bazėje.
Kitas didelis pliusas – gali vienoje užklausoje gauti susietus duomenis iš kelių „resursų”. Nori vartotojo, jo paskutinių penkių užsakymų ir kiekvieno užsakymo prekių sąrašo? Viena užklausa, vienas tinklo apsikeitimas. Tai ypač aktualu mobiliosioms aplikacijoms, kur kiekvienas papildomas HTTP kvietimas kainuoja baterijos energiją ir laiką.
Bet ir čia yra spąstų. GraphQL schemų projektavimas reikalauja gerokai daugiau planavimo nei REST endpointų kūrimas. Serverio pusėje reikia atidžiai stebėti, kad viena „graži” užklausa neišprovokuotų šimtų duomenų bazės kreipinių apačioje (tai vadinama N+1 problema GraphQL kontekste, ir ji sprendžiama per DataLoader ar panašius mechanizmus). Be to, HTTP kešavimas, kuris REST atveju veikia beveik automatiškai per URL struktūrą, GraphQL atveju tampa sudėtingesnis, nes visos užklausos eina per tą patį endpointą su POST metodu.
gRPC – kai kalba eina apie greitį tarp servisų
Jeigu REST ir GraphQL orientuoti daugiausia į klientą – naršyklę ar mobiliąją aplikaciją, tai gRPC (Google Remote Procedure Call) yra visai kitokio žanro sprendimas. Jis sukurtas 2015 metais Google ir skirtas visų pirma mikroservisų tarpusavio bendravimui, kur svarbiausia yra greitis ir mažas resursų suvartojimas.
gRPC veikia ant HTTP/2 protokolo ir naudoja Protocol Buffers (protobuf) duomenų serializacijai vietoj JSON teksto. Tai reiškia, kad duomenys perduodami binariniu formatu – daug kompaktiškiau, greičiau apdorojami ir mažiau apkraunantys tinklą. Skirtumas gali būti gana ženklus, ypač kai kalba eina apie tūkstančius užklausų per sekundę tarp mikroservisų.
Dar viena gRPC savybė – streaming palaikymas. Gali turėti ne tik vieną užklausą-vieną atsakymą modelį, bet ir server streaming, client streaming ar net bidirectional streaming, kur abi pusės nuolat siunčia duomenis viena kitai per tą pačią atidarytą jungtį. Tai neįkainojama, jei kuri realaus laiko sistemas – pavyzdžiui, vietos sekimo servisą ar chat backend’ą.
Minusas – gRPC nėra draugiškas naršyklėms. Reikia specialaus gRPC-Web sluoksnio, kad būtų galima naudoti tiesiogiai iš front-end kodo, ir tai vis dar turi tam tikrų apribojimų. Be to, protobuf failų (.proto) generavimas ir jų versionavimas reikalauja papildomos tvarkos – nebegali tiesiog atsidaryti Postman ir tuoj pat išbandyti endpointo taip lengvai, kaip su REST.
Kaip praktiškai palyginti šiuos tris variantus
Skaičiai visada padeda geriau suprasti situaciją, todėl pažiūrėkim į praktinius aspektus vienas prieš kitą.
Greitis ir efektyvumas. gRPC šioje kategorijoje laimi be didelių abejonių – binarinė serializacija ir HTTP/2 multiplexing suteikia jam pranašumą prieš tekstinį JSON, kurį naudoja tiek REST, tiek GraphQL. Testai dažnai rodo, kad gRPC gali būti 5-10 kartų greitesnis panašiomis sąlygomis, ypač didelio kiekio duomenų perdavimo scenarijuose.
Mokymosi kreivė. REST laimi be jokių ginčų. Jeigu žinai HTTP, žinai REST. GraphQL reikalauja suprasti schemas, resolverius, tipus. gRPC reikalauja suprasti protobuf sintaksę, kodo generavimą ir streaming koncepcijas.
Tinklo efektyvumas kliento pusėje. GraphQL laimi, kai kalbame apie mobiliąsias aplikacijas su ribotu ryšiu, nes leidžia tiksliai kontroliuoti, kiek duomenų atkeliauja.
Ekosistema ir įrankiai. REST turi didžiausią bendruomenę, daugiausiai dokumentacijos, Postman, Swagger/OpenAPI integracijas. GraphQL turi savo stiprią ekosistemą su Apollo, Relay. gRPC įrankiai vis dar labiau orientuoti į backend inžinierius.
Kešavimas. REST čia neabejotinai laimi, nes HTTP kešavimo mechanizmai (ETag, Cache-Control) veikia iš karto be papildomų pastangų. GraphQL ir gRPC reikalauja custom sprendimų.
Realūs scenarijai, kur kiekvienas iš jų atrodo geriausiai
Teorija teorija, bet realybėje sprendimas dažnai priklauso nuo konkretaus projekto konteksto. Štai keletas situacijų, kur pasirinkimas tampa akivaizdus:
Jeigu kuri paprastą internetinę parduotuvę su standartiniu produktų katalogu, krepšeliu ir užsakymų sistema – REST bus tavo geriausias draugas. Nėra prasmės komplikuoti architektūros, kai paprastas CRUD atlieka visą darbą.
Jeigu darai mobiliąją aplikaciją, kuri turi rodyti sudėtingus, tarpusavyje susietus duomenis skirtinguose ekranuose, ir nori sumažinti tinklo užklausų skaičių bei duomenų kiekį – GraphQL bus protingas pasirinkimas. Socialiniai tinklai, naujienų agregatoriai, dashboard’ai su daugybe skirtingų duomenų šaltinių – čia GraphQL tikrai atsiperka.
Jeigu statai mikroservisų architektūrą, kur dešimtys ar šimtai servisų nuolat bendrauja tarpusavyje vidiniame tinkle, ir kiekviena milisekundė turi reikšmę – gRPC bus akivaizdus laimėtojas. Taip pat, jeigu reikia realaus laiko duomenų srautų (pavyzdžiui, IoT sistemose ar finansų sektoriuje, kur kainos keičiasi kas sekundę), gRPC streaming galimybės čia neturi konkurentų.
Ar būtina rinktis tik vieną?
Vienas dažniausiai pamirštamas faktas – nereikia visame projekte naudoti vieno vienintelio sprendimo. Daugelis didelių kompanijų faktiškai naudoja hibridinį modelį. Pavyzdžiui, tarp mikroservisų vidiniame tinkle gali tekėti gRPC srautas dėl greičio, o išorinis API sluoksnis, kuris pasiekiamas iš mobiliosios aplikacijos ar naršyklės, gali būti GraphQL arba REST – priklausomai nuo to, kokie kliento poreikiai.
Netflix, pavyzdžiui, viduje aktyviai naudoja gRPC tarp savo šimtų mikroservisų, tuo pačiu turėdami GraphQL sluoksnį (per savo GraphQL Federation sprendimą) klientų sąsajai. Tai visiškai normali ir netgi rekomenduojama praktika – nereikia jaustis, kad turi rinktis vieną „tiesą” visam laikui.
Praktiniai patarimai prieš pradedant projektą
Pirmiausia, pagalvok apie savo klientus. Jei tavo API vartotojai – trečiųjų šalių programuotojai, kurie tikisi standartinės, gerai dokumentuotos sąsajos, REST su OpenAPI specifikacija tikriausiai bus mažiausiai trinties keliantis sprendimas. Žmonės žino, kaip su juo dirbti, be papildomo mokymosi.
Antra, įvertink savo komandos patirtį. GraphQL ir gRPC turi statesnę mokymosi kreivę. Jeigu komanda niekada nedirbo su schemomis ar protobuf failais, pirmieji du-trys mėnesiai gali užtrukti ilgiau nei planuota vien dėl mokymosi proceso. Tai nereiškia, kad reikia bijoti naujų technologijų, bet reikia realistiškai įvertinti terminus.
Trečia, pagalvok apie infrastruktūrą, kurioje veiks tavo sistema. gRPC prastai veikia per tam tikrus load balancerius ir proxy serverius, kurie nepalaiko HTTP/2 pilnai. Prieš pasirenkant, patikrink, ar tavo debesijos infrastruktūra (AWS, GCP, Azure) ir vartai (API Gateway) tinkamai palaiko HTTP/2 srautą – dažnai tai reikalauja papildomos konfigūracijos.
Ketvirta, neignoruok stebėjimo (monitoring) ir derinimo (debugging) aspekto. REST užklausas lengva stebėti bet kokiu tinklo analizatoriumi – tiesiog atidarai Chrome DevTools ir matai viską aiškiai. GraphQL užklausos, nors ir eina per HTTP, būna suspaustos į vieną endpointą, todėl reikia specialių įrankių, kaip Apollo Studio, kad suprastum, kas iš tikrųjų vyksta. gRPC binariniai duomenys iš viso nėra žmogui skaitomi be tam skirtų dekoderių, tad debug’inimas produkcijoje reikalauja rimtesnio pasiruošimo.
Vietoj galutinio verdikto – kelrodė mintimis, o ne taisyklėmis
Jei ieškai vieno universalaus atsakymo „kas geriausia” – jo tiesiog nėra, ir tai nėra nusivylimo priežastis, o realybė, su kuria verta susitaikyti nuo pat pradžių. REST liks aktualus dar ilgai, nes paprastumas visada turi savo vertę, ypač kai projektas nedidelis arba komanda pradedanti. GraphQL puikiai tinka, kai klientų reikmės skiriasi, duomenys tarpusavyje glaudžiai susiję, o tinklo efektyvumas svarbus. gRPC neturi lygių, kai kalba eina apie greitį tarp vidinių servisų arba realaus laiko duomenų srautus.
Vietoj to, kad ieškotum „geriausios” technologijos apskritai, verčiau užduok sau klausimą: kas šitą API naudos, kokie duomenų kiekiai ir dažnumas, ir kokia infrastruktūra jau egzistuoja. Atsakymai į šiuos klausimus dažniausiai patys nuves prie teisingo sprendimo, be jokių ilgų diskusijų komandoje. Ir svarbiausia – nebijok mišraus modelio. Technologijos čia yra įrankiai, o ne religija, todėl visai normalu vienoje sistemoje naudoti kelias skirtingas architektūras, jei kiekviena iš jų sprendžia savo konkrečią problemą geriausiai.






