Serviciul de acțiune a utilizatorului: de la monolit la cloud

(Souhaib Guitouni) (23 iunie 2020)

Introducere

Din punct de vedere istoric, backend-ul BlaBlaCar era un mare monolit PHP. Ne-a permis să iterăm și să construim rapid funcții, dar pe termen lung nu a fost ușor să înțelegem, să menținem și să evoluăm. În ultimii ani, am descompus acest vechi monolit și ne-am îndreptat către o arhitectură orientată spre servicii.

Acest articol este una dintre poveștile despre modul în care gestionăm această tranziție, cu câteva detalii despre instrumente care ne-au ajutat pe parcurs. Acesta va acoperi opțiunile tehnice ale stivei, arhitectura generală și feedback-ul asupra instrumentelor pe care le-am folosit.

I – De ce

Pe măsură ce activitatea BlaBlaCar se extinde, având o arhitectură monolitică devine din ce în ce mai limitativ, în principal pentru că:

  • Pe măsură ce trăiesc, monolitii cad în cuplare;
  • Este greu de organizat echipele care lucrează pe restanțe separate pe aceeași bază de cod;
  • Monolitii sunt greu de înțeles pentru noii veniți;
  • Pentru toate cele de mai sus, orice funcționalitate nouă devine extrem de costisitoare.

Acesta este motivul pentru care, în ultimii ani, am reproiectat platforma noastră la o arhitectură SOA, căutarea:

  • Servere cu scop funcțional: un serviciu gestionează o singură funcționalitate și este pe deplin responsabil de modul în care îl implementează.
  • Servicii cuplate slab, care pot evolua independent. Echipele pot lucra și implementa în propriul ritm.
  • Mai multă proprietate a codului, astfel încât serviciile au un domeniu de aplicare definit și mai redus, permițând echipelor să le întrețină și să le opereze cu mai multă ușurință.

    II – Domeniul de aplicare și istoricul acțiunilor utilizatorilor

    Cele mai recente linii care au devenit un serviciu independent au fost acțiunile utilizatorului. Acestea ajută echipa noastră de relații cu comunitatea să diagnosticheze și să rezolve problemele utilizatorilor, cum ar fi acordarea de rambursări și detectarea anomaliilor sau urmărirea comportamentului fraudulos.

    Cantitatea de acțiuni ale utilizatorilor, așa cum v-ați putea aștepta, este colosală. Din punct de vedere istoric, ca un singur tabel SQL, această parte a codului avea probleme de performanță. Am găsit soluții de fiecare dată, dar odată cu extinderea noastră, problemele au devenit din ce în ce mai mari:

    • O primă soluție a fost crearea de indici pentru a face interogările mai rapide;
    • Altul a fost să baza de date în mai multe tabele.

    Totuși, aceste soluții și-au atins limita și, cu timpul, am început să primim probleme de performanță.

    III – Stocarea datelor

    1 – Drumul către NoSQL

    Alegerea magazinului de date s-a bazat în principal pe tehnici cerințe:

    • Există cantități uriașe de date
    • Volum mare de inserții
    • Citiri multiple pe secundă, cu necesitatea unor date și performanțe noi
    • Posibilitatea de a filtra într-un timp rezonabil

    Evident căutam o bază de date NoSQL, întrucât distribuția ne-ar permite să stocăm și să manipulăm cantități mari de date și scară atunci când necesar.

    2 – Serviciu gestionat

    De asemenea, am vrut să mergem cu un serviciu gestionat pentru a reduce costul întreținerii. Bazele de date distribuite precum Hbase și Cassandra sunt cunoscute pentru greutățile pe care le aduc echipelor de gestionare a bazelor de date. Mai important, pentru echipa de dezvoltare a aplicațiilor, am dorit să ne concentrăm pe producerea logicii de gestionare a acțiunilor utilizatorilor, mai degrabă decât să ne petrecem timpul rezolvând problemele cu infrastructura bazei de date. A fost și ocazia de a testa un produs nou, deoarece domeniul de aplicare al aplicației nu este prea larg. Am vrut să oferim ceva nou!

    3 – Alegerea finală

    Alegerea a ajuns pe Bigtable din următoarele motive:

    • Volum: a fost conceput pentru a gestiona cantități mari de date, spre deosebire de majoritatea bazelor de date SQL, o instanță poate gestiona 10.000 de inserții pe secunde, așa că am ales configurația minimă cu doar trei noduri.
    • Scalabilitate: este scalabilă și ușor de replicat, puteți gestiona și versiuni de date.
    • Cost de gestionare: este un serviciu gestionat.
    • Performanță: este un serviciu GCP, care ne va permite să avem o performanță excelentă, deoarece va fi în aceeași infrastructură ca și serviciul implementat în GKE.

    III – Salt de la un tren în mișcare la altul

    Lucrul greu despre trecerea de la un monolit la un serviciu înseamnă asigurarea continuității serviciului dintr-un punct de vedere extern și fără a pierde date.

    Pentru a furniza acest lucru, am decis să rulăm noul serviciu, să menținem vechiul sistem funcțional și să scriem noile acțiuni prin REST în ambele. Următorul pas va fi mutarea datelor istorice de la monolit la noul serviciu. Această operație ar putea crea duble, astfel încât încărcarea inițială a datelor ar trebui să gestioneze deduplicarea. Un al treilea pas va fi citirea din noul serviciu în locul vechiului sistem. Un ultim pas ar fi închiderea părții monolit și a bazei de date SQL moștenite odată ce totul funcționează în serviciu.

    IV – Mutarea datelor

    1 – De la MySQL la Bigtable

    Acum că am decis care va fi și cum va fi implementat magazinul nostru de date țintă, am început să ne gândim la modalitățile de a muta datele din monolit în noua bază de date. O astfel de operație este esențială, iar sarcina de migrare ar trebui să fie:

    • Simplă și ușor de dezvoltat: complexitatea este conectorii bazelor de date
    • Performanță ridicată: deoarece va citi enorm cantități de date, vrem să avem rezultatul cât mai rapid posibil
    • Fiabile: nu am dorit pierderi de date
    • Ușor de repornit: în cazul în care lucrurile merg prost, am vrut ceva ce am putea pur și simplu reporniți fără o mulțime de acțiuni manuale, cu scripturi shell peste tot și o procedură complexă
    • Permiterea transformărilor: trebuia să unim date din mai multe baze de date și tabele MySQL pentru a obține cele finale Bigtable, acest lucru ar putea fi greu dacă scriptat manual.

    2 – Apache Beam and Dataflow

    Am ales să folosim Dataflow, un serviciu gestionat distribuit furnizat de Google Cloud, care permite oamenilor să mute date în lot și în moduri de streaming.

    Apache Beam, pe de altă parte, este un cadru utilizat pentru codificarea scripturilor distribuite . O puteți rula apoi pe multe motoare distribuite precum Dataflow, Spark, Flink … Cu alte cuvinte, este un strat de abstractizare pentru a defini transformările dvs. care pot fi înțelese de mai multe motoare.

    Un alt lucru interesant despre Apache Beam este că are conectori din cutie pentru mai multe surse de date, printre care atât MySQL, cât și Bigtable. Așadar, am creat transformările datelor, citind din tabelele vechi Mysql, unindu-le și punând rezultatul în Bigtable.

    2 – Cum a mers?

    Am făcut câteva observații în timpul executării migrării:

    • A fost o sarcină epuizantă pentru MySQL: evitarea problemelor de performanță, prin orice mijloace trebuie să evitați rularea pe o bază de date critică. Pentru a evita această problemă, am rulat-o pe o bază de date replică realizată pentru astfel de sarcini. Am urmărit execuția în serviciul nostru de monitorizare (Prometheus / Grafana) care a arătat că mașinile paralele Dataflow evacuează MySQL.
    • Nici pentru Bigtable nu a fost ușor: am avut o instanță mică de 3 mașini, capabile să ofere 30.000 de inserții pe secunda. Dacă rulați mai multe joburi Dataflow, mergeți dincolo de asta. Așadar, gândiți-vă cu înțelepciune câte mașini doriți să aveți în paralel, deoarece dacă aveți un număr maxim, veți pierde bani.
    • Conectorul MySQL Beam nu transmite date: conectorul MySQL execută o instrucțiune SQL și așteaptă pentru a încărca întregul răspuns pentru a continua. Acest lucru vă va da probleme cu memoria RAM dacă încărcați o mulțime de date. Deci, trebuie să testați și să definiți intervalele de utilizatori pentru a evita să se încheie cu o excepție de memorie. am vrut să merg cu o arhitectură care poate evolua în viitor și pe care o putem construi pas cu pas, cu trafic live de la primul pas.

      Am decis să creăm un serviciu cu Spring WebFlux, cadrul reactiv , pentru a avea cereri fără blocare și apoi pentru o performanță mai bună cu puncte finale funcționale. Am folosit Reactor pentru cea mai bună integrare cu Spring.

      1 – Testarea integrării cu Bigtable

      Testele de integrare apelează API-ul cu mai multe sarcini utile / anteturi și verifică dacă răspunsul este așa cum era de așteptat. Pentru a face acest lucru, aveam nevoie de o instanță Bigtable în spatele serviciului nostru, deoarece doream teste reale.

      Această instanță trebuie curățată la fiecare rulare pentru a începe de la aceeași stare de fiecare dată.

      Soluția a fost utilizarea emulatorului Bigtable prezent în SDK-ul client Bigtable. SDK-ul este foarte bogat și are mai multe funcții precum gestionarea și monitorizarea administratorilor.

      2 – Implementare și infrastructură

      Infrastructura noastră GCP se află deasupra Google Kubernetes și Istio. Gestionăm totul cu Helm și Flux. Alte articole vin pe blogul nostru pentru a intra în mai multe detalii despre infrastructura noastră!

      Bineînțeles, serviciul nostru a avut finalizare clasică de monitorizare, înregistrare și alertare, fără ele nu am putea să-l rulăm să intrăm în direct , bazat pe Prometheus / Grafana și ELK.

      Gânduri finale

      Pentru a gestiona cantitățile mari de date, am mers la Bigtable datorită capacității sale de a scala.Am avut mai multe provocări, cum ar fi definirea schemei de date cu modelul de tastare Bigtable, mutarea unor cantități mari de date dintr-o bază de date SQL on premise într-un NoSQL gestionat, testarea și monitorizarea întregului lucru.

      La început, am implementat serviciul pe centrul nostru de date local și, trecând la GCP, am împărțit latența la trei. Echipele noastre de relații cu comunitatea au acum timpi de răspuns mai rapizi și sunt încântați.