Come scalare Elasticsearch per risolvere i problemi di scalabilità

Con l’evoluzione delle moderne applicazioni che servono esigenze sempre maggiori di elaborazione e recupero di dati in tempo reale, cresce anche la scalabilità. Un motore di ricerca e analisi distribuito open-source è Elasticsearch, che è molto efficiente nel gestire dati in grandi set e query ad alta velocità. Tuttavia, il processo per scalare Elasticsearch in modo efficace può essere sfumato, poiché è necessaria una corretta comprensione dell’architettura che lo sostiene e dei compromessi prestazionali.

Anche se la natura distribuita di Elasticsearch consente di scalare in modo orizzontale, ciò introduce anche più complessità nel modo in cui i dati sono distribuiti e le query sono elaborate. Una delle sfide teoriche associate alla scalabilità di Elasticsearch è la sua natura intrinsecamente distribuita. Nella maggior parte dei casi pratici, le letture su un singolo nodo saranno sempre più performanti rispetto alle letture in un cluster sharded. Questo perché, in un cluster sharded, la proprietà dei dati è distribuita su più nodi. Ciò significa che ogni query potrebbe dover inviare molteplici richieste a nodi diversi, aggregare i risultati di nuovo presso il nodo coordinatore e restituire il risultato. Questo overhead di rete aggiuntivo facilmente comporterà un aumento della latenza rispetto a un’architettura a singolo nodo in cui l’accesso ai dati è diretto.

In questo senso, i cluster sharded sono fondamentali per scalare Elasticsearch a grandi insiemi di dati, alto traffico e indicizzazione quasi in tempo reale. Conoscere il giusto equilibrio tra la distribuzione dei dati tra i nodi e il mantenimento di una bassa latenza delle query è fondamentale per ottenere prestazioni ottimali. Inoltre, l’articolo tratta gli aspetti teorici della scalabilità di Elasticsearch, le strategie pratiche di ottimizzazione delle prestazioni del cluster e le lezioni apprese dalle esperienze di implementazione nel mondo reale.

A Swoo, la nostra app di live streaming e gaming, Elasticsearch era la spina dorsale di tutte le ricerche, e funzionava bene man mano che cresceva il numero degli utenti. Nel momento in cui il numero di utenti simultanei superò i 150.000, la pagina di ricerca iniziò a fallire di tanto in tanto, ed era abbastanza chiaro che c’era un collo di bottiglia nel cluster Elasticsearch. Ciò divenne presto inaccettabile per un ambiente di gioco in diretta e ci portò a effettuare una serie di ottimizzazioni, che alla fine stabilizzarono sia la ricerca che l’esperienza della home page.

Comprensione dell’Architettura di Elasticsearch per la Scalabilità

Elasticsearch supporta nativamente un’architettura distribuita, rendendo il sistema altamente scalabile ma, allo stesso tempo, più complesso rispetto alle soluzioni tradizionali a singolo nodo. Elasticsearch divide i dati in indici, con ciascun indice diviso a sua volta in shard. Il shard è l’unità di base dello storage dei dati e dell’indicizzazione in Elasticsearch poiché il sistema distribuisce e parallelizza le operazioni di ricerca su più nodi del cluster.

Un cluster tipico conterrà un certo numero di nodi dati che ospitano un sottoinsieme dei dati che eseguono le query di ricerca. Per impostazione predefinita, Elasticsearch può distribuire automaticamente i dati tra i nodi, in modo che ciascun nodo esegua solo una parte del carico di query. In questo modo, Elasticsearch scala orizzontalmente: elabora sempre più dati e gestisce sempre più richieste semplicemente aggiungendo nodi ad esso.

Questo compromesso tra scalabilità e prestazioni delle query è, naturalmente, una delle cose più importanti da considerare quando si progettano cluster Elasticsearch, soprattutto per quelle applicazioni che richiedono un’elevata capacità di scrittura combinata con basse latenze di lettura. Una sfida del genere richiede senza dubbio una configurazione attenta del cluster insieme a una combinazione di tecniche di ottimizzazione.

Quindi, in sostanza, il nostro cluster Elasticsearch aveva alcuni nodi dati per il caso di Swoo e tre nodi master dedicati. Ogni nodo era basato su una CPU con 8 core e 16 GB di RAM, principalmente mirata all’indicizzazione in tempo reale e alle ricerche istantanee degli eventi di gioco in corso. Poiché lavoriamo con un’elevata concorrenza, è necessario dedicare una larghezza di banda di rete veramente sostanziale per garantire una latenza minima tra i nodi.

Pianificazione della strategia di scalabilità

In altre parole, scalare Elasticsearch in modo efficace richiede l’analisi delle attuali metriche delle prestazioni, l’individuazione dei colli di bottiglia e degli obiettivi chiari in termini di scalabilità. Ad esempio, sarà utile monitorare la latenza delle query, il throughput e lo stato del cluster al fine di comprendere i limiti del tuo cluster. Sarai in grado di creare una tabella di marcia per l’ottimizzazione identificando i nodi caldi, i picchi di utilizzo della CPU e i problemi di memoria.

Un’altra attività importante che richiede attenzione con la scalabilità di Elasticsearch è la pianificazione della capacità. Stimare l’utilizzo del disco, il modello del traffico e i requisiti di conservazione dei dati garantiranno che il tuo cluster abbia le dimensioni corrette. In generale, il scaling orizzontale (aggiunta di nodi al cluster) è generalmente il miglior approccio per aumentare i dati e il volume del traffico. In questo caso, tuttavia, il scaling verticale – l’aggiornamento delle risorse dei singoli nodi – potrebbe essere efficace.

Le nostre previsioni indicavano una crescita degli utenti attivi di circa il 10-15% al mese, con ciascun utente che genera un volume considerevole di dati sugli eventi durante l’utilizzo del gioco. Sulla base di queste previsioni, ci aspettavamo che il nostro cluster sostenesse un sano aumento delle interrogazioni simultanee insieme a un aumento del volume dei documenti indicizzati. Pertanto, abbiamo analizzato se scalare in modo orizzontale aggiungendo più nodi dati o scalare in verticale aggiornando i nostri nodi attuali sarebbe più adatto per questo aumento.

Tecniche di Scalabilità Principali

L’ottimizzazione di Elasticsearch coinvolgerà una serie di strategie, ognuna mirata a diversi aspetti del sistema. Tra queste, le tecniche più efficaci includono l’ottimizzazione dell’ingestione dei dati, la gestione degli shard e l’ottimizzazione dell’utilizzo della memoria.

Le principali aree di focus saranno l’ingestione dei dati. Elasticsearch supporta nativamente l’indicizzazione bulk, il che significa che puoi inviare batch di documenti molto grandi in una singola richiesta. Questo riduce l’overhead e generalmente accelera il processo di indicizzazione. In secondo luogo, ottimizzare l’intervallo di aggiornamento può fare la differenza quando si ingeriscono dati rapidamente. Si può sovrascrivere l’intervallo di aggiornamento predefinito di un secondo con un valore più alto, ad esempio dieci secondi, poiché ciò ridurrà lo stress dei troppi aggiornamenti frequenti sul cluster e le scritture saranno più veloci.

Altre importanti ragioni che costituiscono la scalabilità di Elasticsearch includono la gestione delle shard. Sebbene Elasticsearch possa scalare in modo orizzontale attraverso lo sharding, una dimensione delle shard inappropriata porta effettivamente a una performance degradata. Un numero di shard troppo alto o troppo basso porta a una velocità di indicizzazione e/o performance delle query ridotte. Il trucco sta nell’equilibrio per ottenere le migliori performance in Elasticsearch.

Ovviamente, la gestione della memoria è un altro fattore molto importante nella scalabilità di Elasticsearch. Si può certamente ridurre il consumo di risorse e migliorare le performance delle query ottimizzando la dimensione del heap JVM, configurando la cache dei dati dei campi e abilitando la cache delle query. Un uso corretto della memoria e delle impostazioni di caching adeguate può prevenire errori di memoria esaurita e ridurre al minimo l’overhead della garbage collection.

Una buona quantità di stress su Elasticsearch era dovuta all’ingestione continua dei dati di gioco in tempo reale. Abbiamo ottimizzato i flussi di ingestione mediante il raggruppamento dei documenti tramite la Bulk API. Durante periodi di carico di picco, potevamo aumentare ulteriormente le dimensioni dei gruppi e prolungare il periodo di aggiornamento per ottenere un giusto compromesso tra l’indicizzazione quasi in tempo reale e la stabilità generale del cluster.

Soluzioni di Scalabilità Avanzate

Quando la scala diventa enorme, Elasticsearch richiede tecniche più avanzate per essere performante. Tra queste, spicca l’ottimizzazione delle query. È possibile ridurre notevolmente la latenza delle query scrivendo query efficienti che minimizzano il numero di shard coinvolti nella ricerca. Ad esempio, è possibile eseguire un routing personalizzato per indirizzare le query ai shard specifici utilizzando una chiave, come l’ID del cliente o la categoria del prodotto. Ciò evita a Elasticsearch di cercare in tutti i shard; quindi, il tempo e le risorse utilizzate vengono ridotti.

ILM, ovvero Gestione del Ciclo di Vita dell’Indice, è un’altra fantastica funzionalità per ottimizzare Elasticsearch man mano che il tuo dataset invecchia. Sarai in grado di spostare i dati più vecchi su storage più lenti e più economici mantenendo i più rilevanti su storage più veloci e accessibili scalando un’architettura calda-fredda. Mantenendo la performance del cluster eccellente man mano che il cluster cresce.

Ultimi argomenti di discussione riguardanti la scalabilità di Elasticsearch sono le considerazioni sull’hardware. Man mano che il tuo cluster cresce, vorrai assicurarti che l’hardware sia adeguatamente fornito per il carico aumentato. Ciò significa assicurarsi che i nodi abbiano CPU, memoria e I/O disco appropriati per operare in modo efficiente. Le unità SSD o NVMe miglioreranno notevolmente le performance, soprattutto per operazioni di indicizzazione e ricerca, che richiedono elevate velocità di accesso ai dati.

Una delle lezioni apprese con fatica è che assegnare solo il conteggio predefinito degli shard agli indici più recenti ci avrebbe messo nei guai con il sovraffollamento. Abbiamo anche individuato un punto ottimale in cui nessuno shard fosse davvero sovraccaricato con la maggior parte degli aggiornamenti in tempo reale provenienti dalla nostra piattaforma di gioco, distribuendo gli indici ad alto scrittura su più shard più piccoli, regolando di conseguenza le repliche.

Approfondimenti Teorici e Compromessi di Ottimizzazione

Oltre alle ottimizzazioni pratiche sopra menzionate, ci sono alcune interessanti considerazioni teoriche riguardanti lo scalabilità di Elasticsearch. Una chiave di lettura coinvolge i compromessi tra scalabilità e prestazioni delle query all’interno di un sistema distribuito. In particolare, si nota che mentre i cluster shardati sono scalabili in modo orizzontale, aumentano il sovraccarico delle query poiché i risultati da nodi multipli devono essere combinati. Questo è in contrasto con un singolo nodo in cui i dati risiedono sulla macchina locale e le query possono essere eseguite senza dover ‘parlare’ con altri nodi. Comprendere questo compromesso è importante se si progetta un cluster Elasticsearch che deve bilanciare le prestazioni con la scalabilità.

Un altro aspetto più teorico della scalabilità di Elasticsearch è il concetto di località dei dati. È possibile eseguire query solo contro il nodo locale che ospita i dati shard rilevanti utilizzando il parametro di query preference=local. Questo riduce al minimo la comunicazione tra nodi e riduce la latenza delle query. Ciò può ridurre le sfide legate alla replicazione dei dati e al bilanciamento del carico. L’algoritmo di Selezione della Replica Adattiva di Elasticsearch cerca di ottimizzare l’esecuzione delle query scegliendo il miglior nodo replica nelle condizioni attuali. Tuttavia, ciò non garantisce necessariamente l’esecuzione più efficace di una query.

La prima ondata di fallimenti che abbiamo sperimentato nel nostro ambiente riguarda l’alta pressione sul JVM heap. I server Elasticsearch sono stati inizialmente eseguiti con assegnazioni di heap minime, il che ha comportato cicli di garbage collection piuttosto frequenti sotto un carico di query elevato. Abbiamo risolto questo problema ottimizzando il JVM, in particolare allineando la dimensione minima e massima dell’heap a 8 GB, il che ha dato a Elasticsearch abbastanza spazio per elaborare le query senza sovraccaricare l’heap.

Errori comuni e Soluzioni

Certo, scalare Elasticsearch non è privo di sfide. Tra gli errori comuni da evitare ci sono dimensioni di shard scadenti, mancanza di monitoraggio, eccessiva dipendenza dalla memorizzazione nella cache e mancato utilizzo della corretta Gestione del Ciclo di Vita dell’Indice. Questi risparmiano molto tempo e risorse se individuati precocemente attraverso una taratura proattiva della configurazione.

Uno dei principali problemi era non aver regolato le impostazioni predefinite di Elasticsearch, sia per quanto riguarda l’allocazione della memoria che la gestione degli shard. Le impostazioni predefinite funzionavano bene in condizioni di traffico moderato ma cedevano sotto il traffico di picco. La nostra soluzione è stata articolata: ha rivisto l’allocazione dell’heap, la replica dell’indice caldo e la memorizzazione nella cache a breve termine per le query ripetute. Nel complesso, ha impedito fallimenti ripetuti nell’intero cluster e ha ridotto significativamente i tempi di attesa.

Guida all’Implementazione nel Mondo Reale

Scalare Elasticsearch comporterà pianificazione, test, distribuzione e manutenzione successiva. Ne deriva che buone pratiche, modelli di configurazione e test approfonditi del cluster prima di implementare nuove modifiche in produzione garantiranno una scalabilità senza problemi in un cluster stabile nel lungo termine.

  • Perfezionare i parametri JVM. Abbiamo impostato sia Xms che Xmx su 8 GB su ciascun server Elasticsearch, trovando un equilibrio tra la memoria di sistema disponibile e i requisiti di heap.
  • Ottimizzazione della distribuzione degli shard. Gli indici di grandi dimensioni sono stati suddivisi in shard di dimensioni più piccole per evitare i punti caldi e scalare le repliche per gli indici più attivi. Ciò ha garantito che il traffico delle query fosse distribuito uniformemente nell’intero cluster.
  • Abilitare la cache con TTL breve. Abbiamo applicato una finestra di cache di 1 secondo alle query statiche frequentemente utilizzate sulla homepage e abbiamo notato che ciò riduce notevolmente il carico su Elasticsearch per le richieste ripetitive senza perdere reattività in tempo reale.
  • Monitoraggio e iterazione. Abbiamo utilizzato Kibana, con alcuni cruscotti personalizzati per l’osservazione in tempo reale dello stato degli shard, delle prestazioni JVM e delle latenze delle query. Sulla base di queste metriche, sono stati effettuati continui perfezionamenti.

Piani futuri o Espansioni della tecnologia

Inoltre, per favorire la crescita, vorremmo esplorare la gestione di un ciclo di vita dell’indice hot-warm-cold spostando i dati meno frequentemente accessibili su nodi più economici mantenendo hardware di alta qualità per l’indicizzazione e le query in tempo reale. Stiamo esaminando soluzioni di monitoraggio avanzate e rilevamento di anomalie guidato dall’IA per assicurarci che picchi o rallentamenti nelle query insolite siano previsti con largo anticipo rispetto all’impatto sull’esperienza utente.

Conclusione

Il dimensionamento di Elasticsearch richiede la comprensione dell’architettura, una pianificazione attenta e l’applicazione delle migliori pratiche. Per quanto Elasticsearch si scalini orizzontalmente attraverso la suddivisione in shard, presenta diverse sfide che devono essere gestite per garantire prestazioni ottimali. L’alta scalabilità e le prestazioni di un cluster Elasticsearch possono essere garantite tramite una corretta acquisizione dei dati, la gestione degli shard, l’utilizzo della memoria e l’ottimizzazione delle query.

Nel nostro caso, la migrazione a Elasticsearch era necessaria anche per Solr, senza dubbio, oltre alle sole questioni tecniche, un contributo importante è stato dato per comprendere le difficoltà teoriche che sono effettivamente nascoste nei Sistemi Distribuiti. Questo tipo di sintonizzazione attenta e la risoluzione creativa dei problemi potrebbero consentire una crescita significativa: un cluster Elasticsearch singolo multi-fornitore, che dovrebbe ricevere milioni di query al giorno migliorando le prestazioni delle query con tempi di risposta molto ridotti. Gli elementi teorici e pratici si fondono quando si scala la distribuzione di Elasticsearch per garantire il successo a lungo termine.

Source:
https://dzone.com/articles/how-to-scale-elasticsearch-to-solve-scalability-issues