Firebase, cloud functions, backend, google cloud

Sziasztok!

Egy összetett kérdésem lenne, ezért sem tudtam pontos címet megadni. Egy elég bonyolult játék fejlesztésén dolgozunk Unity-ben, amit 3 éve csinálunk (ebbe beletartozik a Unity, c# elsajátítása) előtte kizárólag php+mysql-el foglalkoztunk, lényegesen egyszerűbb téma volt, mint ez. A játék jelenleg úgymond 50% körüli készültség alatt van és eljutottunk odáig, hogy ténylegesen foglalkoznunk kell azzal, hogy a szerverrel milyen kommunikációt válasszunk.

A játékról: (általánosságban beszélek, nem konkrétan a mi játékunkról.) Képzeljünk el egy népszerű lövöldözős játékot, ahol a játékos regisztrál, feltöltheti egyenlegét, fegyvereket vásárolhat, rengeteg tulajdonság szint van, az egyenlegből küldhet át egyenleget más játékosnak, tehát rengeteg adatbázis művelet van, és a játék lényege persze, hogy miután mindennel elkészült, beléphet egy terembe, ahol más játékosokkal realtime játszhat. Nagyjából hasonló elven működik a miénk is, bár a játék teljesen más, de ez most ebből a szempontból lényegtelen.

Mivel korábban php-vel és mysql-el foglalkoztunk, így eleinte mi is így kezdtük felépíteni a játékunkat (aztán gondoltuk majd átírjuk a végleges nyelvre). Megjegyzés: a realtime dolgot egyelőre hagyjuk ki. Ami azt jelenti, hogy unity-ben elkészítettük magát a játékot, a játékos egy php fájlt meghívva regisztrálhat, mysql adatbázisban tárolódik minden, tud vásárolni, felhasználók profiljai között böngészni, ezek mind olyan dolgok, amikhez nem szükséges az azonnali realtime adatbázis, hiszen pusztán lekérdezésekről van szó, apróbb módosításokról az adatbázisban. A session kérdéssel még nem foglalkoztunk, hiszen valószínű, hogy az egész alapja át lesz írva. Kezdetleges terv, hogy bejelentkezéskor létrehozunk egy session ID-t, mely a játékoshoz van eltárolva, amit a unity megkap és minden további kéréskor ezt továbbítja a szervernek. Fontos tudni, hogy ezek mögött php-ben a backend nagyon fontos műveleteket ellenőríz, hogy valóban van-e annyi egyenlege, stb., tehát ha valaki meghackeli a kliens oldalt, akkor se tudjon semmilyen olyan műveletet végrehajtani, amit valójában nem szabad neki. 

Ez így jelen formában működőképes is, de menjünk tovább.
Csatlakoznak egy "szobához", ahol mondjuk maximum 20 játékos tartozkódhat egyszerre. Firebase realtime szerver az első gondolatunk, természetesen már ez is elkészült, bár mivel a végleges szerver kommunikáció még nem áll rendelkezésre, nincs Firebase auth, ezért itt szimplán a felhasználó azonosítóját küldjük el a szervernek, amik alapján a játékosok tudnak mozogni, csinálni amit kell. Működőképes is, de itt még semmi biztonság nincs, hiszen nagyon könnyen hozzá lehet férni a realtime adatbázishoz mindenféle azonosítás nélkül. 

Tehát összegezve, van 2 adatbázis, az egyik a felhasználók adatai, itt kerül végre a legtöbb módosítás saját és egymás között, plusz van egy realtime adatbázis, amihez a Firebase realtime rendszerét használnánk, itt tulajdonképpen a legfontosabb adatok a mozgás koordinátái, amik valós időben frissülnek az egy szobában tartózkodók között. De itt nem fontos, hogy kapcsolatban legyen az első adatbázissal. Vagyis, csak ritkán. Ami azt jelenti, hogy ha mégis szükség van rá, akkor szintén php-vel kapcsolódunk, hogy az első adatbázisból lekérdezzük a dolgokat, addig a játékos várakozik. Tehát egyfajta kommunikáció van közöttük a mozgáson kívül, de ott nem sürgős a válaszidő. Viszont itt nem maga a firebase rendszer csatlakozik az adatbázishoz, hanem a kliens az előbb említett módon, tehát még mindig két független szerverről van szó.
Viszont, szóba jön a biztonság kérdése. Ha a Firebase realtime szerver nincs kapcsolatban a másik adatbázissal, akkor nem tudunk meggyőzödni arról, hogy ténylegesen az az user küldi az adatokat, aki az első szerveren be van jelentkezve, mivel a realtime adatbázis nem tartalmazza a session id-t. Ez akkor jenne jó, ha magán a szerver csatlakozna a másik szerverhez, lekérdezni a sessiont.

Csak hogy még jobban értsétek, jelenleg tényleg nagyon egyszerű módon működik az egész, tehát unityben kiválasztja hogy pl. fegyvert akar vásárolni, akkor meghívja a fegyvervasarlas.php-t, elküldve az user id-t és a session_id-t, a php elvégez minden fontos műveletet, módosítja a dolgokat a mysql adatbázisban, majd visszaadja, hogy sikeres volt-e. A realtime dolog meg csak annyi, hogy elküldi a szervernek az azonosítóját meg a koordinátáját minden mozgás esetén, ezek meg frissülnek folyamatosan realtime egymás között. 

Kétféle megoldáson gondolkodtunk:
1. Az egész Firebase alapú, tehát a felhasználók a Firebase auth segítségével regisztrálnak, és minden műveletet a Firebase rendszert meghívva végez el. Sajnos itt nem vagyunk nagyon tisztában a backend működésével, mert azt láttuk, hogy be lehet állítani jogosultságokat, ki mihez férjen hozzá, de nálunk például egy játékos módosíthat más felhasználó adatai között is (pl. ha egyenleget küld át.) Tehát ha az egész firebase alapú, akkor is legjobb lenne, ha például Go nyelven a backendet megírhatnánk, hogy biztonságos legyen a játék.
2. Marad így jelen formában, annyi különbséggel, hogy az első adatbázist és php-t átpakoljuk google cloud-ba, adatbázisnak Nosql, backendnek Go vagy nodejs, a gyorsabb kommunikáció érdekében. Realtime adatbázisnak használjuk továbbra is a Firebase realtime rendszert, viszont itt még mindig kérdéses, hogy amikor a realtime szerverhez kapcsolódunk, akkor az hogyan tudja visszaellenőrízni, hogy az adott azonosítóhoz az adott session_id tartozik a cloud-ban, és hogy anélkül ne engedjen semmit csinálni.

Jelenlegi rálátásunkból adódóan a második verzió tetszene a legjobban, mert így úgy gondoljuk, sokkal jobban tudjuk felügyelni, mi is történik, a biztonságra is jobban oda tudunk figyelni, számunkra ez még jobban átlátható. Ha az egész firebase, akkor tulajdonképpen a kliensben történik minden, a firebase oldalon meg tulajdonképpen ellenőrzi, van e jogosultsága, de nem vagyunk tisztában ott a backend tényleges működésével. Bár láttuk, lehetséges a firebase oldalon backend írására (https://firebase.google.com/products/functions), de mégis szeretnénk olyanoktól segítséget kérni, akik ebben már valamennyire jártasak, hogy miképpen valósítható ez meg optimálisan, és a jelenlegi működési elv nem hatalmas mértékű változtatásával.
Tisztában vagyunk vele, hogy ehhez még sokat kell megtudnunk az egész működéséről és tanulnunk, de eljött az idő, hogy ténylegesen foglalkoznunk kell ezzel is, hiszen a jelenlegi verzió nem maradhat. Még mindig úgy gondoljuk, legegyszerűbb ezt a php-t felpakolni google cloudba, esetleg átírni go-ra, esetleg nosql adatbázis és igazából készen is vagyunk, csak a realtime szerverhez való kapcsolódás biztonsági problémái a gond.
Ha valaki tud egyszerű, de jól működő megoldást, megköszönjük. :)

Hozzászólások

Szerkesztve: 2019. 11. 03., v - 03:16

Azt hiszem a kerdesem eleg bonyolult lett, ezert szeretnem leegyszerusiteni. 
 

1. verzio: ha a google cloudot hasznaljuk, vagyis berlunk egy szervert, feltoltjuk a magunk kis php fajljait (amit modosithatunk mas nyelvre, hiszen egyszeru lekerdezesekrol es adatbazis muveletekrol van szo), hogyan tudjuk elerni, hogy amikor a Firebase realtime szerverhez csatlakozik a user, akkor a szerver kapcsolatban alljon a cloudban talalhato adatbazisunkkal, hogy a sessiont ellenorizni tudjuk. Valoszinu sehogy, ha biztonsagosan szeretnenk.. 

2. verzio: ha mindenre a firebase/firestore rendszeret hasznaljuk, akkor a biztonsag adott, az auth es stb. beepitett dolgokkal, viszont ebben az esetben a kliens kozvetlenul csatlakozik a szerverhez es kuldi el a modositando adatokat. A firebase consolon belul be lehet allitani, kinek mihez van hozzaferese. De itt nem csak arrol van szo, hogy a felhasznalo csak a sajat nevet tudja modositani, hanem arrol, hogy nehany dolgot az adatbazisban levo tobbi adat ellenorzese utan tud csak megvaltoztatni. Tehat, ha a firebase cloud functiont hasznaljuk az adatbazis muveletekhez, akkor (egy egyszeru pelda), vasarolni akar valamit, hogy tudjuk megoldani, hogy csak abban az esetben engedelyezze, ha az egyenlege x-nel tobb? Nyilvan ez a legalapja az egesznek, ha csak a firebase rendszert akarjuk hasznalni, akkor ebbe meg nagyon bele kell tanulnunk, ezert erdekelne olyan megoldas, amit mi mar megcsinaltuk es osszekottetesben lehet a realtime szerverrel. 
 

igazabol ennyi a kerdes. Abbol a szempontbol jo a firebase rendszer, hogy ha jol van megirva, akkor tenyleg biztonsagos, a szerverekkel skalazassal nem kell bajlodni, de nem latjuk at a mukodeset abbol a szempontbol, amit mi szeretnenk. Ha siman berlunk egy szervert es phpben van a backend, akkor konnyeden tudjuk kezelni, mikor mit engedelyez, ez szamunkra sokkal egyszerubb. Viszont a firebase sok funkcioja hasznos lenne, mint cloud messaging, realtime database, es vagy ossze kell kotnunk valahogy a kettot, vagy egy rendszerben kell lennie az egesznek.. A problemat persze leginkabb a biztonsag jelenti, hogy barhogy is hackeli meg a klienst, barmilyen hiba van benne, csak azt engedelyezze, amire a szerveren levo backend logikank is engedelyt ad.. ezt phpvel gond nelkul megoldjuk, de firebase rendszerben ez kisse bonyodalmat jelent szamunkra.. Tehat valami olyan megoldas kellene, ha Firebase alapu az egesz, akkor oke regisztral a beepitett funkcioval, de ha peldaul vasarol, akkor nem siman a kliensben megiekuk hogy ezt erre azt arra modositsa, hanem csak elkuldjuk, hogy ezt akarja, a firebase meghiv egy phpt vagy js-t vagy barmit es az ottani lekerdezeseknek es logikanak megfeleloen hajtsa vegre a dolgokat. 

https://firebase.google.com/docs/auth

Itt elég sokat írnak a firebase authentikációs megoldásáról, ami kérdést pont te is feszegetsz...

Ha saját megoldásra mentek, akkor oauth2 és valamilyen providerrel.

A szerver oldalnál jó kérdés, hogy mit érdemes használni, a go jó lehet, de akkor, ha van ilyen tapasztalatotok, és/vagy találtok hozzá fejlesztőt. Ez utóbbi mindig a szűk keresztmetszet. Én nodejs-t javasolnék, vagy esetleg java/spring-et.

Jobban áttanulmányozva igen lehet, hogy mi is a nodejs-re szavaznánk.

De kicsit térjünk vissza.
Mivel szerver oldalon annyira nem vagyunk tisztában a dolgok működésével (mint említettem, korábbi projektünknél is php+mysql-t használtunk, ahol nem mi építettük fel a rendszert, hanem adott volt), ezért jobban preferáljuk azt a megoldást, ahol a szerver oldal úgymond tényleg csak felhőként funkcionál. Értem ezalatt, hogy tegyük fel a Facebook isten tudja hány szervert üzemeltet, az adatbázisok hogyan replikálják magukat, hogyan érik el az egyik felhasználó a világ másik szerverén található felhasználó profilját, ezek annyira összetett dolgok, hogy ezekre nagyon nincs rálátásunk, mert ilyen volumenű projecttel még nem foglalkoztunk.

Ezért is tetszett a Firebase rendszer, unityvel kapcsolódunk, ha 100 milliárd felhasználó regisztrál (tudom nincs ennyi ember a világon, de szándékosan túloztam), akkor annyit fog tudni kezelni, anélkül, hogy nekünk komolyabban bele kellene látni, hogy a szerver tulajdonképpen mit is csinál mögötte. Az adatbázisunkat és minden komolyabb dolgot is nagyon szívesen építenénk a Firebase rendszerre, csak az egyetlen baj, hogy kliens oldalra nem tehetjük, hogy mit mikor szabad csinálnia a felhasználónak. Vagyis tesszük persze, de a szerver oldalon ugyanúgy ellenőrízni kell biztonsági okokból, gondolom ezt nem kell magyaráznom. 
Ezek alapján jött a firebase cloud functions, amibe most a napokba jobban belemélyedtünk és hát sajnos ez sem az amit vártunk. Unity kliens kapcsolódik a Firebase rendszerünkhöz, auth megvan, és azt terveztük, hogy ha az adatbázisban módosítani szeretne valamit, akkor kliens oldalon kapcsolódunk az adott funkcióhoz 

FirebaseFunctions.DefaultInstance.GetHttpsCallable("addMessage")
  .CallAsync(data).ContinueWith((task) =>

az addMessage funkció pedig végrehajtja amit szeretnénk a Firebase realtime adatbázisában. Ezt npm-el firebasehoz kapcsolódva meg is valósítottuk, bár ez ugye egy üzenetet ad hozzá, mégpedig egy pushid-el ellátva, amivel nehezen kezelhető egy adatbázis. Közben rájöttünk, hogy ez tulajdonképpen nagyon nem arra való amit mi szeretnénk. Tehát mi ez alapján szerettük volna kezelni a felhasználók adatait és módosítani őket, pl. előző példámra visszatérve a fegyvervasarlas funkció ellenőrízné a felhasználó egyenlegét és az adatbázisban az adott fegyver értékét beállítani, hogy van neki. Ez szerintünk nagyon is nem alkalmas erre a célra, létrehozható más funkció is, de az meg nem hívható közvetlen a kliensből, legalábbis úgy vettük ki a google szavaiból.. 

Ezzel próbálkoztunk:
https://firebase.google.com/docs/functions/callable (Call functions from your app)

Szóval megint csak rá kellett jönnünk, nem lesz ez olyan egyszerű.
Kérlek azonnal javítsatok ki ha tévedünk és mégis megoldható.

Nagyszerűnek hangzott, hogy "serverless", tulajdonképpen csak az adatokat kezeli, hogy mit mikor csináljon, azt meg meg tudjuk adni a szerveren javascripttel, hát lehet mégsem ilyen egyszerű.

Következő lehetőség, hogy továbbra is nagyon szívesen használnánk a Firebase Auth-ot, akár a kliensen keresztül, hogy egy megbízható rendszer legyen, de akkor is szükségünk van egy olyan adatbázisra, aminek a backend logikáját mi adhatjuk meg. Mit javasoltok? Van erre megoldás még, vagy Google App Engine, nodejs létrehozása és nodejs-en keresztül csatlakozunk a Google Cloud Sql-hez, vagy Google Cloud Firestore-hoz? A Cloud Firestore-nak utánajártunk (már amennyire próba nélkül és angol tudásunk engedi), elvileg ez ugyanaz vagyis hasonló mint a Firebase realtime rendszer, annyi adatot kezel amennyit akarunk mindenféle szerver terhelés elosztás nélkül. Ugyanakkor így is felmerül egy bökkenő, hiszen maga az App Engine nodejs az már szerverfüggő, vagyis ha túl nagy a terhelés, akkor több szervert kell létrehoznunk és el kell osztanunk a felhasználókat ki melyikre csatlakozik? De az összes szerver már csatlakozhat ugyanahhoz az adatbázishoz? (Elvileg az serverless, ahogy a google mondja.) Az Auth itt megint egy kérdéses dolog, de abba most ne menjünk bele.

Tényleg nagyon az elején vagyunk és nem hiába lovagolunk a Firebase témán, mert programozói nyelveket tudunk, de szervert összerakni még nem csináltunk. Ezért kiindulási, magyarról magyarra fordítva szeretnénk segítséget kérni, melyik irányba haladhatunk. Valószínű ez még sok idő, de ha már egyetlen lekérdezés és módosítás úgy működik ahogy szeretnénk félsiker. :) Igazából ha nagyon muszáj, fogjuk az App Engine-t felpakoljuk rá a php fájljainkat amik csatlakoznak az adatbázishoz, aztán kész is, de azért hülyeséget sem akarunk, akkor már inkább nodejs. Ha befut a játék akkor persze megbíznánk valakit, hogy az összetákolt szerver oldali dolgokat rendberakja, de addig is, melyik megoldást javasoljátok, mi az ami egyszerű lehet de nem is őrültség?

Köszönjük tényleg.

Én MQTT Redis Elasticsearch Kafka körül nézelődnék. Leginkább Kafka. 

--
Gábriel Ákos

Zseniális topic-nak tűnik. :)

jól olvasom, hogy egy adatbázisban akarod tárolni a játékosok koordinátáit? Azon gondolkodtatok, hogy milyen tickrate-t (=a "játékvilág" állapotának frissítítése hányszor megy végbe egy másodpercben) tudtok így elérni? ez elegendő lehet egyeltalán egy élvezhető játékélményhez?

Hogy konstruktív is legyek én most websocket -et használnék egy ilyen projekthez.

Ez a kerdes naponta felmerul a fejunkben, de az elozo irasomban nem is errol volt szo, hanem a masik adatbazis, ahol a felhasznaloknak az adatai vannak tarolva, hogy az mikeppen valosithato meg egy normalis backenddel. Ott ertelemszeruen csak akkor van lekerdezes, ha szukseg van ra.
A masik resze a dolognak, ahol a felhasznalok mozoghatnak (de nem lovoldoznek, tehat nemi elteres meg elfogadott), ott azert a firebase realtime tetszett meg, mert meg anno a google is ugy mutatta be, hogy a gepen jatszott es a mobilon is valos idoben ugyanaz tortent. Ezt a videot mar nem talalom. Tulajdonkeppen hasonlo egy websockethez, a kliens kozvetlen csatlakozik a firebase realtime cucchoz es ha barmilyen valtozas van az osszes (abban a teremben tartozkodo) azonnal megkapja a valtozast. Egyebkent csokkentes celjabol (mivel tenyleg nem 100% pontossaggal kell tudni a masik poziciojat, arra gondoltuk masodpercenkent kuldjuk el a szervernek a poziciojat ha valtozik, es a tobbi kliensnek mar unityben oldjuk meg a mozgas latszatat.) persze ha szerinted ostobasag, lehet itt is nodejs websocket, csak ez a rendszer is azert tetszett, mert serverless. Ennek nem kell kapcsolatban lennie a masik adatbazissal, nem kell semmilyen logika szerver oldalon, annyi, hogy be legyen jelentkezve.
viszont a masik adatbazis koncepciora is szivesen hallgatnek meg velemenyeket otleteket (amit legutobb sz332-nek valaszolva irtam.)

értem. Nem mondtam, hogy feltétlenül ostobaság, ti látjátok, hogy mit bír el a játékmenet, hogy még élvezhető maradjon. A websocket egyébként nem JS (és nodejs) specifikus, van sok nyelvhez implementációja szerver és kliens oldalon is.

A másik szálhoz/kérdéshez: nem tudom, hogy ragaszkodtok-e a google cuccaihoz, de amit szeretnétek azt sok szolgáltató sokféle módon árulja, pl. az aws-nél is több megoldás létezik. Ahhoz, hogy konkrét tanácsot tudjon adni itt bárki érdemes lenne becsült felhasználószámot látni, mert egyébként egy sima postgre vagy mySQL is nagyon sok usert és query-t elbír másodpercenként ha jól vannak felépítve a táblák, csak manapság divatos a NoSQL megoldások javára utálni a relációs adatbázisokat. Ráadásul ezzel van némi tapasztalatotok, tehát nem nulláról kell megtanulni. Ha nem akarsz foglalkozni az operations részével, akkor veszel egy managelt adatbázis megoldást valahol és használjátok azt.