Ottimizzazione del carico su un progetto Highload con ElasticSearch

Ehi Habr! Mi chiamo Maxim Vasiliev, lavoro come analista e project manager presso FINCH. Oggi vorrei raccontarvi come, utilizzando ElasticSearch, siamo riusciti a processare 15 milioni di richieste in 6 minuti e ad ottimizzare i caricamenti giornalieri sul sito di un nostro cliente. Purtroppo dovremo fare a meno dei nomi, visto che abbiamo un NDA, speriamo che il contenuto dell'articolo non ne risenta. Andiamo.

Come funziona il progetto

Sul nostro backend, creiamo servizi che garantiscono le prestazioni dei siti Web e dell'applicazione mobile dei nostri clienti. La struttura generale è visibile nel diagramma:

Ottimizzazione del carico su un progetto Highload con ElasticSearch

Nel processo di lavoro, elaboriamo un gran numero di transazioni: acquisti, pagamenti, operazioni con saldi utente, per i quali memorizziamo molti registri, nonché importiamo ed esportiamo questi dati su sistemi esterni.

Esistono anche processi inversi quando riceviamo dati dal cliente e li trasferiamo all'utente. Inoltre, ci sono ancora processi per lavorare con pagamenti e programmi bonus.

Breve sfondo

Inizialmente, abbiamo utilizzato PostgreSQL come unico archivio dati. I suoi vantaggi standard per un DBMS: la presenza di transazioni, un linguaggio di campionamento dei dati sviluppato, un'ampia gamma di strumenti per l'integrazione; unito a buone prestazioni ha soddisfatto a lungo le nostre esigenze.

Abbiamo archiviato assolutamente tutti i dati in Postgres: dalle transazioni alle notizie. Ma il numero di utenti è cresciuto e con esso il numero di richieste.

Per capire, il numero annuale di sessioni nel 2017 solo sul sito desktop è di 131 milioni. Nel 2018 - 125 milioni. Nel 2019 ancora 130 milioni. Aggiungi altri 100-200 milioni dalla versione mobile del sito e dall'applicazione mobile, e tu riceverà un numero enorme di richieste.

Con la crescita del progetto, Postgres ha smesso di far fronte al carico, non abbiamo avuto tempo: è apparso un gran numero di varie query, per le quali non siamo riusciti a creare un numero sufficiente di indici.

Abbiamo capito che c'era bisogno di altri archivi dati che soddisfacessero le nostre esigenze e alleggerissero PostgreSQL. Elasticsearch e MongoDB sono stati considerati come possibili opzioni. Quest'ultimo ha perso sui seguenti punti:

  1. Rallenta la velocità di indicizzazione man mano che aumenta la quantità di dati negli indici. Con Elastic, la velocità non dipende dalla quantità di dati.
  2. Nessuna ricerca a testo integrale

Quindi abbiamo scelto Elastic per noi stessi e ci siamo preparati per la transizione.

Transizione all'elastico

1. Abbiamo avviato la transizione dal servizio di ricerca del punto vendita. Il nostro cliente ha un totale di circa 70 punti vendita, e questo richiede diversi tipi di ricerche sul sito e nell'applicazione:

  • Ricerca testuale per nome di città
  • Geosearch all'interno di un dato raggio da un certo punto. Ad esempio, se l'utente vuole vedere quali sono i punti vendita più vicini a casa sua.
  • Cerca per un dato quadrato: l'utente disegna un quadrato sulla mappa e gli vengono mostrati tutti i punti in questo raggio.
  • Cerca con filtri aggiuntivi. I punti vendita differiscono l'uno dall'altro nell'assortimento

Se parliamo dell'organizzazione, in Postgres abbiamo una fonte di dati sia per la mappa che per le notizie, e in Elastic Snapshots sono presi dai dati originali. Il fatto è che inizialmente Postgres non poteva far fronte alla ricerca secondo tutti i criteri. Non solo c'erano molti indici, ma potevano anche sovrapporsi, quindi lo scheduler di Postgres si perdeva e non capiva quale indice usare.

2. Il prossimo in linea era la sezione delle notizie. Le pubblicazioni compaiono sul sito ogni giorno in modo che l'utente non si perda nel flusso di informazioni, i dati devono essere ordinati prima dell'emissione. Ecco a cosa serve la ricerca: puoi cercare nel sito per corrispondenza di testo, e allo stesso tempo collegare filtri aggiuntivi, visto che sono realizzati anche tramite Elastic.

3. Quindi abbiamo spostato l'elaborazione della transazione. Gli utenti possono acquistare un determinato prodotto sul sito e partecipare a un'estrazione a premi. Dopo tali acquisti, elaboriamo una grande quantità di dati, soprattutto nei fine settimana e nei giorni festivi. Per fare un confronto, se nei giorni ordinari il numero di acquisti è compreso tra 1,5 e 2 milioni, nei giorni festivi la cifra può raggiungere i 53 milioni.

Allo stesso tempo, i dati devono essere elaborati nel più breve tempo possibile: agli utenti non piace aspettare il risultato per diversi giorni. Non c'è modo di rispettare tali scadenze tramite Postgres: spesso ricevevamo blocchi e mentre elaboravamo tutte le richieste, gli utenti non potevano verificare se ricevevano premi o meno. Questo non è molto piacevole per le aziende, quindi abbiamo spostato l'elaborazione su Elasticsearch.

periodicità

Ora gli aggiornamenti sono configurati in base agli eventi, secondo le seguenti condizioni:

  1. Punti vendita. Non appena riceviamo i dati da una fonte esterna, avviamo immediatamente l'aggiornamento.
  2. Notizia. Non appena una notizia viene modificata sul sito, viene automaticamente inviata ad Elastic.

Anche in questo caso vale la pena menzionare i vantaggi di Elastic. In Postgres, quando invii una richiesta, devi attendere che elabori onestamente tutti i record. Puoi inviare 10 record a Elastic e iniziare a lavorare immediatamente, senza attendere che i record vengano distribuiti su tutti gli Shard. Ovviamente, alcuni Shard o Replica potrebbero non vedere subito i dati, ma tutto sarà disponibile molto presto.

Metodi di integrazione

Ci sono 2 modi per integrare con Elastic:

  1. Attraverso un client nativo su TCP. Il driver nativo sta gradualmente scomparendo: non è più supportato, ha una sintassi molto scomoda. Pertanto, praticamente non lo usiamo e cerchiamo di abbandonarlo completamente.
  2. Attraverso un'interfaccia HTTP che può utilizzare sia le richieste JSON che la sintassi Lucene. L'ultimo è un motore di testo che utilizza Elastic. In questa versione, abbiamo la possibilità di Batch tramite richieste JSON su HTTP. Questa è l'opzione che stiamo cercando di utilizzare.

Grazie all'interfaccia HTTP, possiamo utilizzare librerie che forniscono un'implementazione asincrona del client HTTP. Possiamo sfruttare Batch e l'API asincrona, che si traduce in prestazioni elevate, che hanno aiutato molto nei giorni della grande promozione (ne parleremo più avanti)

Alcuni numeri per il confronto:

  • Salvataggio utenti bounty Postgres in 20 thread senza raggruppamento: 460713 record in 42 secondi
  • Client elastico + reattivo per 10 thread + batch per 1000 elementi: 596749 record in 11 secondi
  • Client elastico + reattivo per 10 thread + batch per 1000 elementi: 23801684 voci in 4 minuti

Ora abbiamo scritto un gestore di richieste HTTP che compila JSON come Batch / not Batch e lo invia tramite qualsiasi client HTTP, indipendentemente dalla libreria. Puoi anche scegliere di inviare le richieste in modo sincrono o asincrono.

In alcune integrazioni, utilizziamo ancora il client di trasporto ufficiale, ma questa è solo una questione del prossimo refactoring. In questo caso, per l'elaborazione viene utilizzato un client personalizzato costruito sulla base di Spring WebClient.

Ottimizzazione del carico su un progetto Highload con ElasticSearch

grande promozione

Una volta all'anno, il progetto ospita una grande promozione per gli utenti: questo è lo stesso Highload, poiché in questo momento lavoriamo con decine di milioni di utenti contemporaneamente.

Di solito i picchi di carico si verificano durante le festività, ma questa promozione è su un livello completamente diverso. L'anno prima, il giorno della promozione, abbiamo venduto 27 unità di merce. I dati sono stati elaborati per più di mezz'ora, il che ha causato disagi agli utenti. Gli utenti hanno ricevuto premi per la partecipazione, ma è diventato chiaro che il processo doveva essere accelerato.

All'inizio del 2019, abbiamo deciso che avevamo bisogno di ElasticSearch. Per un anno intero, abbiamo organizzato l'elaborazione dei dati ricevuti in Elastic e la loro emissione nell'API dell'applicazione mobile e del sito web. Di conseguenza, l'anno successivo durante la campagna, abbiamo elaborato 15 voci in 131 minuti.

Poiché abbiamo molte persone che vogliono acquistare beni e partecipare all'estrazione di premi nelle promozioni, questa è una misura temporanea. Ora stiamo inviando informazioni aggiornate a Elastic, ma in futuro prevediamo di trasferire le informazioni archiviate negli ultimi mesi su Postgres come memoria permanente. Per non intasare l'indice elastico, che ha anche i suoi limiti.

Conclusione/Conclusioni

Al momento, abbiamo trasferito tutti i servizi che volevamo su Elastic e per ora ci siamo soffermati su questo. Ora stiamo costruendo un indice in Elastic sopra l'archiviazione persistente principale in Postgres, che assume il carico dell'utente.

In futuro, prevediamo di trasferire i servizi se comprendiamo che la richiesta di dati diventa troppo diversificata e viene cercata per un numero illimitato di colonne. Questo non è più un compito per Postgres.

Se abbiamo bisogno di una ricerca full-text in funzionalità o se abbiamo molti criteri di ricerca diversi, allora sappiamo già che questo deve essere tradotto in Elastic.

?

Grazie per aver letto. Se anche la tua azienda utilizza ElasticSearch e ha i propri casi di implementazione, comunicacelo. Sarà interessante sapere come stanno gli altri 🙂

Fonte: habr.com

Aggiungi un commento