Servizio azioni utente: dal monolite al cloud

(Souhaib Guitouni) (23 giugno 2020)

Introduzione

Storicamente, il backend di BlaBlaCar era un grande monolite PHP. Ci ha permesso di iterare e creare funzionalità rapidamente, ma a lungo termine non è stato facile apprendere, mantenere ed evolvere. Negli ultimi anni abbiamo smontato questo vecchio monolite e ci siamo spostati verso unarchitettura orientata ai servizi.

Questo articolo è una delle storie di come stiamo gestendo questa transizione, con alcuni dettagli sul strumenti che ci hanno aiutato lungo il percorso. Coprirà le scelte dello stack tecnico, larchitettura generale e il feedback sugli strumenti che abbiamo utilizzato.

I – I perché

Man mano che lattività di BlaBlaCar si espande, avere unarchitettura monolitica diventa sempre più limitante, principalmente perché:

  • Mentre vivono, i monoliti si accoppiano;
  • Avere team che lavorano su backlog separati è difficile da organizzare sulla stessa base di codice;
  • I monoliti sono difficili da apprendere per i nuovi arrivati;
  • Per tutto quanto sopra, qualsiasi nuova funzionalità diventa estremamente costosa.

Questo è il motivo per cui, negli ultimi anni, abbiamo ridisegnato la nostra piattaforma a unarchitettura SOA, cercando:

  • Server con ambito funzionale: un servizio gestisce una singola funzionalità ed è pienamente responsabile di come la implementa.
  • Servizi liberamente accoppiati che possono evolversi in modo indipendente. I team possono lavorare e distribuire al proprio ritmo.
  • Più proprietà del codice, quindi i servizi hanno un ambito definito e più ridotto, consentendo ai team di mantenerli e gestirli con più facilità.

II – Ambito e cronologia delle azioni dellutente

Lultima in linea ad essere trasformata in un servizio indipendente sono state le azioni dellutente. Aiutano il nostro team per le relazioni con la comunità a diagnosticare e risolvere i problemi degli utenti, come concedere rimborsi e rilevare anomalie o rintracciare comportamenti fraudolenti.

La quantità di azioni degli utenti, come ci si potrebbe aspettare, è colossale. Storicamente come una tabella SQL, questa parte del codice presentava problemi di prestazioni. Abbiamo trovato soluzioni ogni volta, ma con la nostra espansione i problemi sono diventati sempre più grandi:

  • Una prima soluzione era creare indici per rendere più veloci le query;
  • Unaltra era lo shard il database in più tabelle.

Tuttavia, queste soluzioni hanno raggiunto il limite e con il tempo abbiamo iniziato a riscontrare problemi di prestazioni.

III – Archiviazione dei dati

1 – La strada per NoSQL

La scelta dellarchivio dati si è basata principalmente su dati tecnici requisiti:

  • Ci sono enormi quantità di dati
  • Grande volume di inserimenti
  • Più letture al secondo, con la necessità di nuovi dati e prestazioni
  • Possibilità di filtrare in un tempo ragionevole

Ovviamente stavamo cercando un database NoSQL, poiché la distribuzione ci avrebbe permesso di memorizzare e manipolare grandi quantità di dati e scalare quando necessario.

2 – Servizio gestito

Volevamo anche andare con un servizio gestito per ridurre i costi di manutenzione. I database distribuiti come Hbase e Cassandra sono famosi per le difficoltà che procurano ai team di gestione dei database. Ancora più importante, per il team di sviluppo delle applicazioni, volevamo concentrarci sulla produzione della logica di gestione delle azioni dellutente piuttosto che dedicare il nostro tempo alla risoluzione dei problemi con linfrastruttura del database. È stata anche loccasione per testare un nuovo prodotto, poiché lambito dellapplicazione non è troppo ampio. Volevamo provare qualcosa di nuovo!

3 – Scelta finale

La scelta è caduta su Bigtable per i seguenti motivi:

  • Volume: è stato progettato per gestire grandi quantità di dati, a differenza della maggior parte dei database SQL, unistanza può gestire 10.000 inserimenti al secondo, quindi abbiamo scelto la configurazione minima con solo tre nodi.
  • Scalabilità: è scalabile e facile da replicare, puoi anche gestire le versioni dei dati.
  • Costo di gestione: è un servizio gestito.
  • Prestazioni: è un servizio GCP, che ci consentirà di avere prestazioni eccellenti poiché si troverà nella stessa infrastruttura del servizio distribuito in GKE.

III – Saltare da un treno in movimento a un altro

La cosa difficile di passare da un monolite a un servizio significa fornire continuità di servizio da un punto di vista esterno e non avere perdite di dati.

Per fornire ciò abbiamo deciso di eseguire il nuovo servizio, mantenere il vecchio sistema funzionante e scrivere le nuove azioni tramite REST in entrambi. Il prossimo passo sarà lo spostamento dei dati storici dal monolite al nuovo servizio. Questa operazione potrebbe creare doppioni, quindi il caricamento iniziale dei dati dovrebbe gestire la deduplicazione. Un terzo passo sarà leggere dal nuovo servizio invece che dal vecchio sistema. Un ultimo passaggio sarebbe chiudere la parte monolite e il database SQL legacy una volta che tutto funziona nel servizio.

IV – Spostamento dei dati

1 – Da MySQL a Bigtable

Ora che abbiamo deciso quale sarà il nostro datastore di destinazione e come verrà distribuito, abbiamo iniziato a pensare i modi per spostare i dati dal monolite al nuovo database. Tale operazione è fondamentale e il lavoro di migrazione dovrebbe essere:

  • Semplice e facile da sviluppare: la complessità è data dai connettori dei database
  • Ad alte prestazioni: poiché leggerà enorme quantità di dati, vogliamo che il risultato sia il più veloce possibile
  • Affidabile: non volevamo perdita di dati
  • Facile da riavviare: nel caso in cui le cose andassero male, volevamo qualcosa che potevamo riavvia semplicemente senza molte azioni manuali, con script di shell ovunque e una procedura complessa
  • Consentire le trasformazioni: avevamo bisogno di unire i dati da più database e tabelle MySQL per ottenere quelli finali Bigtable, questo potrebbe essere difficile se scriptato manualmente.

2 – Apache Beam e Dataflow

Abbiamo scelto di utilizzare Dataflow, un servizio gestito distribuito fornito da Google Cloud, che consente alle persone di spostare i dati in modalità Batch e in streaming.

Apache Beam invece è un Framework utilizzato per codificare script distribuiti . Puoi quindi eseguirlo su molti motori distribuiti come Dataflow, Spark, Flink … In altre parole, è un livello di astrazione per definire le tue trasformazioni che possono essere comprese da più motori.

Unaltra cosa interessante di Apache Beam è che dispone di connettori pronti alluso a più origini dati, tra cui MySQL e Bigtable. Quindi abbiamo creato le trasformazioni dei dati, leggendo dalle tabelle legacy Mysql, unendole e inserendo il risultato in Bigtable.

2 – Come è andata?

Abbiamo fatto alcune osservazioni durante lesecuzione della migrazione:

  • Era un compito estenuante per MySQL: per evitare problemi di prestazioni, è assolutamente necessario evitare di eseguirlo su un database critico. Per evitare questo problema, lo abbiamo eseguito su un database di replica creato per tali attività. Abbiamo seguito lesecuzione sul nostro servizio di monitoraggio (Prometheus / Grafana) che mostrava che le macchine parallele Dataflow esauriscono MySQL.
  • Non è stato facile neanche per Bigtable: avevamo una piccola istanza di 3 macchine, in grado di fornire 30.000 inserti al secondo. Se esegui più lavori Dataflow, vai molto oltre. Quindi, pensa saggiamente a quante macchine vuoi avere in parallelo, perché avere il numero massimo ti farà perdere denaro.
  • Il connettore MySQL Beam non trasmette dati: il connettore MySQL esegue unistruzione SQL e attende per caricare lintera risposta per continuare. Questo ti darà problemi con la RAM se carichi molti dati. Quindi è necessario testare e definire gli intervalli di utenti per evitare di ritrovarsi con uneccezione di memoria.

V – Il servizio di backend

Più modelli di architettura erano possibili, noi volevamo optare per unarchitettura in grado di evolversi in futuro e che possiamo costruire passo dopo passo, con traffico live sin dal primo passaggio.

Abbiamo deciso di creare un servizio con Spring WebFlux, il framework reattivo , per avere richieste non bloccanti e quindi prestazioni migliori con endpoint funzionali. Abbiamo utilizzato Reactor per la migliore integrazione con Spring.

1 – Test di integrazione con Bigtable

I test di integrazione chiamano lAPI con più payload / intestazioni e verificano se la risposta è quella prevista. Per fare ciò, avevamo bisogno di unistanza Bigtable dietro il nostro servizio, poiché volevamo test di vita reale.

Questa istanza deve essere pulita a ogni esecuzione per iniziare ogni volta dallo stesso stato.

La soluzione era utilizzare lemulatore Bigtable presente nellSDK del client Bigtable. LSDK è molto ricco e ha più funzioni come la gestione e il monitoraggio dellamministratore.

2 – Distribuzione e infrastruttura

La nostra infrastruttura GCP è in cima a Google Kubernetes e Istio. Gestiamo tutto con Helm e Flux. Altri articoli stanno arrivando sul nostro blog per entrare in maggiori dettagli sulla nostra infrastruttura!

Ovviamente, il nostro servizio aveva le classiche terminazioni di monitoraggio, registrazione e avviso, senza di esse non saremmo in grado di eseguirlo dal vivo , basato su Prometheus / Grafana e ELK.

Considerazioni finali

Per gestire le grandi quantità di dati, siamo passati a Bigtable grazie alla sua capacità di scalabilità.Abbiamo dovuto affrontare diverse sfide come la definizione dello schema dei dati con il pattern di codifica Bigtable, lo spostamento di grandi quantità di dati da un database SQL on premise a un NoSQL gestito, il test e il monitoraggio dellintera operazione.

Allinizio abbiamo implementato il servizio nel nostro datacenter on-premise e passando a GCP abbiamo diviso la latenza per tre. I nostri team per le relazioni con la comunità ora hanno tempi di risposta più rapidi e sono entusiasti.