Serie di progettazione di sistema la guida definitiva per la creazione di sistemi di streaming di dati ad alte prestazioni da zero!

Guida definitiva alla progettazione di sistemi per lo streaming di dati ad alte prestazioni crea il tuo sistema da zero!

Fonte: Unsplash

Configurazione di un problema di esempio: un Sistema di Raccomandazioni

“Data Streaming” suona incredibilmente complesso e “Data Streaming Pipelines” ancora di più. Prima di parlare di cosa significhi e di carico di parole, iniziamo con il motivo dell’esistenza di qualsiasi sistema software, un problema.

Il nostro problema è piuttosto semplice, dobbiamo costruire un sistema di raccomandazione per un sito di e-commerce (qualcosa come Amazon) ovvero un servizio che restituisce un insieme di prodotti per un utente specifico basandosi sulle preferenze di quell’utente. Non dobbiamo affannarci a capire come funziona proprio ora (ne parleremo più avanti), per ora ci concentreremo su come i dati vengono inviati a questo servizio e come esso restituisce i dati.

I dati vengono inviati al servizio sotto forma di “eventi”. Ciascuno di questi eventi è un’azione specifica compiuta dall’utente. Ad esempio, un clic su un determinato prodotto o una query di ricerca. In parole semplici, tutte le interazioni dell’utente sul nostro sito, dallo scorrimento semplice all’acquisto costoso, sono considerate un “evento”.

Immagine di Autore

Questi eventi ci danno informazioni sull’utente. Ad esempio, un utente interessato all’acquisto di un PC da gioco potrebbe essere interessato anche a una tastiera o un mouse per giochi.

Di tanto in tanto, il nostro servizio riceve una richiesta di ottenere raccomandazioni per un utente, il suo compito è semplice, rispondere con un elenco di prodotti di interesse per l’utente.

Immagine di Autore

Per ora, non ci interessa come viene popolato questo elenco di raccomandazioni, assumiamo che questo “Servizio di Raccomandazione” esegua alcune operazioni magiche (ne parleremo di questa magia più avanti alla fine del post, per ora non ci importa molto della logica di queste operazioni) e scopra le preferenze dei nostri utenti.

Le raccomandazioni sono solitamente un dettaglio di poco conto in molti sistemi, ma sono molto più critiche di quanto si possa pensare. Quasi tutte le applicazioni che usi si basano pesantemente su servizi di raccomandazione come questi per guidare le azioni degli utenti. Ad esempio, secondo questo articolo, il 35% delle vendite web di Amazon proviene dai loro articoli consigliati.

Il problema tuttavia risiede nella grande mole di dati. Anche se gestiamo solo un sito moderatamente popolare, potremmo comunque ricevere centinaia di migliaia di eventi al secondo (forse anche milioni) nel momento di picco! E se c’è un nuovo prodotto o una grande vendita, potremmo raggiungere cifre ancora più elevate.

E i nostri problemi non finiscono qui. Dobbiamo elaborare questi dati (effettuare la magia di cui abbiamo parlato prima) in tempo reale e fornire raccomandazioni agli utenti in tempo reale! Se c’è una vendita, anche solo pochi minuti di ritardo nell’aggiornamento delle raccomandazioni potrebbero causare significative perdite finanziarie per un’azienda.

Cosa è una Pipeline di Data Streaming?

Una Pipeline di Data Streaming è esattamente ciò che ho descritto sopra. È un sistema che riceve dati continui (come eventi), esegue più passaggi di elaborazione e memorizza i risultati per un utilizzo futuro.

Nel nostro caso, gli eventi provengono da più servizi, i nostri passaggi di elaborazione coinvolgono alcuni passaggi “magici” per calcolare le raccomandazioni sull’utente, e quindi aggiorneremo le raccomandazioni per ciascun utente in un archivio di dati. Quando riceviamo una query per le raccomandazioni per un determinato utente, recuperiamo semplicemente le raccomandazioni che abbiamo memorizzato in precedenza e le restituiamo.

Lo scopo di questo post è comprendere come gestire questa mole di dati, come riceverla, elaborarla e restituirla per un uso successivo, anziché comprendere la logica effettiva dei passaggi di elaborazione (ma ci immergeremo comunque un po’ per divertimento).

Creazione di una pipeline di streaming dei dati: Passo dopo passo

C’è molto da parlare, dall’ingestione, all’elaborazione, all’output e all’interrogazione, quindi approcciamolo un passo alla volta. Considera ogni passo come un problema più piccolo e isolato. Ad ogni passo, partiremo dalla soluzione più intuitiva, vedremo perché non funziona e costruiremo una soluzione che funziona.

Ingestione dei dati

Iniziamo dall’inizio della pipeline, l’ingestione dei dati. Il problema dell’ingestione dei dati è abbastanza facile da capire, l’obiettivo è solo quello di acquisire eventi da diverse fonti.

Immagine dell'Autore

Ma sebbene il problema sembri semplice all’inizio, presenta le sue sfumature,

  1. La quantità di dati è estremamente elevata, arrivando facilmente a centinaia di migliaia di eventi al secondo.
  2. Tutti questi eventi devono essere acquisiti in tempo reale, non possiamo avere un ritardo nemmeno di pochi secondi.

Iniziamo in modo semplice, il modo più intuitivo per raggiungere questo obiettivo è inviare ogni evento come una richiesta al sistema di raccomandazioni, ma questa soluzione presenta molti problemi,

  1. I servizi che inviano gli eventi non dovrebbero dover aspettare una risposta dal nostro servizio di raccomandazione. Ciò aumenterebbe la latenza sui servizi e li blocca finché il servizio di raccomandazione non invia loro un 200. Dovrebbero invece inviare richieste di invio e dimenticanza.
  2. Il numero di eventi sarebbe altamente volatile, aumentando e diminuendo durante il giorno (ad esempio, aumentando la sera o durante le vendite), dovremmo dimensionare il nostro servizio di raccomandazione in base alla scala degli eventi. Questo è qualcosa che dovremo gestire e calcolare.
  3. Se il nostro servizio di raccomandazione si blocca, perderemo gli eventi mentre è inattivo. In questa architettura, il nostro servizio di raccomandazione è un unico punto di fallimento.

Risolviamo questo problema utilizzando un message broker o una “piattaforma di streaming degli eventi” come Apache Kafka. Se non sai cosa sia, è semplicemente uno strumento che configuri e che può acquisire messaggi dai “pubblicatori” su determinati argomenti. I “sottoscrittori” ascoltano o si iscrivono a un argomento e ogni volta che viene pubblicato un messaggio sull’argomento, il sottoscrittore riceve il messaggio. Parleremo di più sugli argomenti Kafka nella prossima sezione.

Ciò che devi sapere su Kafka è che facilita un’architettura disaccoppiata tra produttori e consumatori. I produttori possono pubblicare un messaggio su un argomento Kafka e non devono preoccuparsi di quando, come o se il consumatore consuma il messaggio. Il consumatore può consumare il messaggio nel suo stesso tempo e elaborarlo. Kafka faciliterebbe anche una scala molto elevata poiché può scalare in modo orizzontale e lineare, fornendo una capacità di scalabilità quasi infinita (a condizione che aggiungiamo più macchine)

Immagine dell'Autore

Quindi ogni servizio invia eventi ad Apache Kafka. Il servizio di raccomandazione recupera questi eventi da Kafka. Vediamo come ciò ci aiuta:

  1. Gli eventi vengono elaborati in modo asincrono, i servizi non devono più aspettare la risposta dal servizio di raccomandazione.
  2. È più facile scalare Kafka e, se la scala degli eventi aumenta, Kafka archivierà semplicemente più eventi mentre scaliamo il nostro servizio di raccomandazione.
  3. Anche se il servizio di raccomandazione si blocca, non perderemo alcun evento. Gli eventi sono memorizzati in Kafka, quindi non perdiamo mai alcun dato.

Ora sappiamo come acquisire eventi nel nostro servizio, passiamo alla prossima parte dell’architettura, l’elaborazione dei dati.

Elaborazione dei dati

L’elaborazione dei dati è una parte integrante della nostra pipeline dati. Una volta ricevuti gli eventi, dobbiamo generare nuove raccomandazioni per l’utente. Ad esempio, se un utente cerca “Monitor”, dobbiamo aggiornare le raccomandazioni per questo utente in base a questa ricerca, forse aggiungere che l’utente è interessato ai monitor.

Prima di parlare di più sull’architettura, dimentichiamo tutto questo e parliamo un po’ di come generare raccomandazioni. Qui entra in gioco anche il machine learning, non è molto importante capire questo per continuare con il post, ma è abbastanza divertente, quindi cercherò di dare una breve descrizione di base di come funziona.

Proviamo a capire meglio le interazioni degli utenti e cosa significano. Quando l’utente interagisce con il nostro sito web con una ricerca, un click o uno scroll, ci sta comunicando qualcosa sui suoi interessi. Il nostro obiettivo è capire queste interazioni e usarle per comprendere l’utente.

Quando pensi a un utente, probabilmente pensi a una persona, con un nome, un’età, ecc. ma per i nostri scopi è più facile pensare ad ogni utente come a un vettore, o semplicemente a un insieme di numeri. Può sembrare confuso (come può un utente essere rappresentato come un insieme di numeri, dopotutto), ma seguimi e vediamo come funziona.

Supponiamo di poter rappresentare ogni utente (o i suoi interessi) come un punto in uno spazio bidimensionale. Ogni asse rappresenta una caratteristica del nostro utente. Supponiamo che l’asse X rappresenti quanto gli piace viaggiare, e l’asse Y rappresenti quanto gli piace la fotografia. Ogni azione dell’utente influenza la posizione di questo utente nello spazio bidimensionale.

Supponiamo che un utente parta dal seguente punto nel nostro spazio bidimensionale —

Immagine di Autore

Quando l’utente cerca una “borsa da viaggio”, spostiamo il punto verso destra perché ciò fa pensare che l’utente ami viaggiare.

Immagine di Autore

Se l’utente avesse cercato una fotocamera, invece, avremmo spostato l’utente verso l’alto sull’asse Y.

Rappresentiamo anche ogni prodotto come un punto nello stesso spazio bidimensionale,

Immagine di Autore

La posizione dell’utente nel diagramma precedente indica che l’utente ama viaggiare e gli piace anche un po’ la fotografia. Ogni prodotto viene posizionato in base a quanto è rilevante per la fotografia e i viaggi.

Dato che l’utente e i prodotti sono solo punti in uno spazio bidimensionale, possiamo confrontarli e eseguire operazioni matematiche su di essi. Ad esempio, dal diagramma precedente, possiamo trovare il prodotto più vicino all’utente, in questo caso la valigia, e affermare con fiducia che è una buona raccomandazione per l’utente.

Quanto sopra è una breve introduzione ai sistemi di raccomandazione (ne parlerò di più alla fine del post). Questi vettori (solitamente molto più grandi di 2 dimensioni) sono chiamati embedding (embedding degli utenti che rappresentano i nostri utenti, e embedding dei prodotti che rappresentano i prodotti sul nostro sito web). Possiamo generarli utilizzando diversi tipi di modelli di apprendimento automatico e ci sono molte altre cose su di loro di cui non ho parlato, ma il principio fondamentale rimane lo stesso.

Torniamo al nostro problema. Per ogni evento, dobbiamo aggiornare gli embedding degli utenti (spostare l’utente sulla nostra griglia a n dimensioni) e restituire prodotti correlati come raccomandazioni.

Pensiamo a pochi passaggi di base per ogni evento che dobbiamo eseguire per generare questi embedding:

  1. update-embeddings: Aggiorna gli embedding dell’utente
  2. gen-recommendations: Recupera i prodotti correlati (o vicini) agli embedding dell’utente
  3. save: Salva le raccomandazioni e gli eventi generati

Possiamo creare un servizio Python per ogni tipo di evento.

Immagine di Autore

Ognuno di questi microservizi ascolterebbe un topic di Kafka, elaborerebbe l’evento e lo invierebbe al topic successivo, dove un servizio diverso sarebbe in ascolto.

Immagine di Autore

Dato che stiamo di nuovo usando Kafka anziché inviare richieste, questa architettura ci offre tutti i vantaggi che abbiamo discusso in precedenza. Nessun singolo microservizio Python è un punto singolo di errore ed è molto più facile gestire la scala. L’ultimo servizio save-worker deve salvare le raccomandazioni per un uso futuro. Vediamo come funziona.

Data Sinks

Una volta elaborato un evento e generato le raccomandazioni ad esso associate, dobbiamo archiviare i dati relativi all’evento e alle raccomandazioni. Prima di decidere dove archiviare i dati degli eventi e delle raccomandazioni, consideriamo i requisiti per il data store

  1. Scalabilità e velocità di scrittura elevata: Ricordiamo che abbiamo molti eventi in arrivo e ogni evento aggiorna anche le raccomandazioni dell’utente. Questo significa che il nostro data store deve essere in grado di gestire un numero molto elevato di scritture. Il nostro database deve essere altamente scalabile e in grado di scalare in modo lineare.
  2. Query semplici: Non eseguiremo JOIN complessi o tipi diversi di query. Le nostre esigenze di query sono relativamente semplici, dato un utente, restituiamo l’elenco delle raccomandazioni precalcolate
  3. Nessun requisito ACID: Il nostro database non ha bisogno di una forte conformità ACID. Non ha bisogno di garanzie di consistenza, atomicità, isolamento e durabilità.

In parole semplici, ci interessa un database in grado di gestire un’enorme quantità di scala, senza extra inutili.

Cassandra è una scelta perfetta per questi requisiti. Si scala linearmente grazie alla sua architettura decentralizzata e può scalare per gestire una velocità di scrittura molto elevata, che è esattamente ciò di cui abbiamo bisogno.

Possiamo utilizzare due tabelle, una per memorizzare le raccomandazioni per ogni utente e l’altra per memorizzare gli eventi. L’ultimo microservizio Python, il save worker, salverà i dati dell’evento e delle raccomandazioni in Cassandra.

Immagine di Author

Interrogazione

L’interrogazione è piuttosto semplice. Abbiamo già calcolato e memorizzato le raccomandazioni per ogni utente. Per interrogare queste raccomandazioni, dobbiamo semplicemente interrogare il nostro database e recuperare le raccomandazioni per l’utente specifico.

Immagine di Author

Architettura completa

E questo è tutto! Abbiamo completato l’intera architettura, disegniamo l’architettura completa e vediamo com’è.

Immagine di Author

Per ulteriori approfondimenti

Kafka

Kafka è uno strumento straordinario sviluppato da LinkedIn per gestire una quantità estrema di scala (questo articolo sul blog di LinkedIn del 2015 ha parlato di circa 13 milioni di messaggi al secondo!).

Kafka è incredibile nel scalare in modo lineare e gestire una scala estremamente elevata, ma per costruire tali sistemi, gli ingegneri devono conoscere e capire Kafka, cos’è, come funziona e come si confronta con altri strumenti.

Ho scritto un articolo sul blog in cui spiego cosa è Kafka, come si differenzia dai message broker e estratti dal paper originale su Kafka scritto dagli ingegneri di LinkedIn. Se ti è piaciuto questo post, dai un’occhiata al mio post su Kafka –

Serie di progettazione di sistema: Apache Kafka a 10.000 piedi

Diamo un’occhiata a cosa è Kafka, come funziona e quando dovremmo usarlo!

betterprogramming.pub

Cassandra

Cassandra è un database unico progettato per gestire una velocità di scrittura molto elevata. Il motivo per cui può gestire tale velocità è la sua architettura decentralizzata altamente scalabile. Recentemente ho scritto un articolo sul blog in cui discuto di Cassandra, come funziona e, soprattutto, quando usarlo e quando non —

Soluzioni di Progettazione di Sistema: Quando utilizzare Cassandra e quando no

Tutto ciò che devi sapere su quando utilizzare Cassandra e quando no

VoAGI.com

Sistemi di Raccomandazione

I sistemi di raccomandazione sono un’incredibile tecnologia e vengono utilizzati in quasi tutte le applicazioni che tu ed io utilizziamo oggi. In qualsiasi sistema, la personalizzazione e i sistemi di raccomandazione sono la base della ricerca e del flusso di scoperta per gli utenti.

Ho scritto parecchio sui sistemi di ricerca e ho toccato anche un po’ l’argomento della personalizzazione di base nei sistemi di ricerca, ma il mio prossimo argomento sarà approfondire i dettagli degli engine di raccomandazione, come funzionano e come sono progettati. Se ti sembra interessante, seguimi su VoAGI per altri contenuti! Pubblico anche molto contenuto breve su LinkedIn per una lettura regolare, ad esempio, questo post su Kafka Connect che descrive come funziona e perché è così popolare con un semplice diagramma.

Conclusione

Spero tu abbia apprezzato questo post, se hai dei feedback sul post o dei pensieri su cosa dovrei parlare prossimamente, puoi lasciarli come commento!