Ottimizzazione dell'utilizzo della memoria di Elasticsearch per prestazioni massime

Padroneggia la gestione della memoria di Elasticsearch per prestazioni massime. Questa guida esplora tecniche fondamentali tra cui il dimensionamento dello heap JVM, l'ottimizzazione dell'indicizzazione e della ricerca, lo sfruttamento del caching e l'implementazione di circuit breaker per prevenire errori OutOfMemory. Scopri strategie pratiche per garantire che il tuo cluster Elasticsearch rimanga stabile e reattivo, anche sotto carico pesante.

Ottimizzazione dell'Utilizzo della Memoria di Elasticsearch per Prestazioni Ottimali

I problemi di memoria di Elasticsearch di solito si manifestano come ricerche lente, lunghe pause di garbage collection, errori degli interruttori automatici o nodi che lasciano il cluster. Ottimizzare l'utilizzo della memoria di Elasticsearch significa bilanciare l'heap JVM, la cache del filesystem, il numero di shard, il comportamento delle query e la pressione dell'indicizzazione, invece di limitarsi ad aumentare -Xmx.

L'obiettivo è semplice: fornire a Elasticsearch heap sufficiente per il lavoro del cluster e delle query, lasciando abbastanza RAM al sistema operativo per memorizzare nella cache i file dei segmenti di Lucene.

Comprendere i Componenti della Memoria di Elasticsearch

Elasticsearch utilizza la memoria in due aree principali:

  • Heap JVM: Contiene metadati del cluster, buffer di indicizzazione, strutture delle query, fielddata quando abilitato, cache e altri oggetti Java. Troppo poco heap causa pressione e interventi degli interruttori. Troppo heap può allungare la garbage collection e privare la cache del filesystem.
  • Cache del filesystem e memoria nativa: Il sistema operativo memorizza nella cache i file degli indici Lucene al di fuori dell'heap JVM. Elasticsearch utilizza anche memoria nativa per la rete, gli stack dei thread e i file mappati in memoria.

Configurare la Dimensione dell'Heap JVM

La dimensione dell'heap è la prima impostazione da controllare. Elasticsearch utilizza file jvm.options o opzioni JVM specifiche dell'ambiente a seconda di come è stato installato.

Impostare Xms e Xmx Insieme

Imposta -Xms e -Xmx allo stesso valore in modo che la JVM non ridimensioni l'heap mentre il nodo è in esecuzione.

Come regola generale, mantieni l'heap pari o inferiore a circa la metà della RAM fisica ed evita di superare la soglia del puntatore a oggetti ordinario compresso. In pratica, molti nodi di produzione rimangono al di sotto di circa 30 GB di heap, ma dovresti verificare la soglia esatta e le linee guida per la tua versione di Elasticsearch e JVM.

Ad esempio:

-Xms4g
-Xmx4g

Questo imposta sia l'heap iniziale che quello massimo a 4 GB.

Monitorare l'Utilizzo dell'Heap

Utilizza Kibana Stack Monitoring, gli esportatori Prometheus o l'API Nodes Stats:

curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"

Osserva heap_used_percent, il tempo di garbage collection, la pressione della vecchia generazione e gli interventi degli interruttori automatici. Un heap che rimane alto per lunghi periodi dopo la garbage collection di solito significa che devi ridurre i consumatori di heap o aggiungere capacità.

Ridurre la Pressione della Memoria di Shard e Query

Il layout dell'indice e la forma delle query hanno un effetto diretto sulla memoria.

Dimensione e Numero di Shard

Ogni shard ha un overhead. Troppi shard piccoli sprecano heap e rallentano le operazioni del cluster. Shard molto grandi possono rendere dolorosi il recupero e la rilocazione. Molti cluster funzionano bene con dimensioni degli shard nell'ordine delle decine di gigabyte, ma i log, i dati di serie temporali e gli indici con carichi di ricerca elevati possono richiedere obiettivi diversi.

Ad esempio, se un indice di log giornaliero crea 30 shard primari per 20 GB di dati, stai pagando un overhead per molti shard piccoli. Uno o due primari potrebbero essere più facili da gestire, a seconda dei modelli di conservazione e query.

Unione dei Segmenti

Elasticsearch utilizza i segmenti Lucene per l'indicizzazione. I segmenti più piccoli vengono uniti in segmenti più grandi nel tempo. Questo processo può richiedere molta memoria. Sebbene Elasticsearch gestisca l'unione automaticamente, comprenderne l'impatto può essere utile, specialmente durante carichi di indicizzazione pesanti.

Ottimizzazione della Ricerca e delle Aggregazioni

  • Utilizza campi keyword per le aggregazioni: Aggrega e ordina su campi keyword, numerici, data o altri campi supportati da doc-values. Evita di abilitare fielddata su grandi campi text a meno che tu non comprenda il costo in termini di heap.
  • Limita le query costose: Le query con wildcard iniziali e le espressioni regolari ampie possono essere costose. Preferisci campi strutturati, prefissi, n-grammi o mapping di tipo "search-as-you-type" quando il caso d'uso richiede corrispondenze parziali.
  • Analizza le ricerche lente: Utilizza l'API di profilazione in un ambiente di staging per trovare le clausole di query che creano più lavoro.

Utilizzare le Cache in Modo Consapevole

Elasticsearch ha diverse cache. Aiutano per il lavoro ripetuto, ma consumano anche memoria.

  • Cache delle richieste degli shard: Memorizza nella cache i risultati della ricerca a livello di shard per richieste idonee, spesso utile per query di aggregazione ripetute su dati per lo più invariati. La sua dimensione è controllata con:

    indices.requests.cache.size: 5%
    

    Questo esempio imposta la dimensione della cache delle richieste degli shard al 5% dell'heap.

  • Cache delle query del nodo: Memorizza nella cache i risultati del contesto del filtro. La sua dimensione è controllata separatamente:

    indices.queries.cache.size: 10%
    
  • Cache Fielddata: Consuma heap e può crescere rapidamente se abiliti fielddata su campi di testo. Preferisci mappare correttamente i campi invece di fare affidamento su una cache fielddata più grande.

Prevenire gli Errori di Memoria Insufficiente

Gli errori di memoria insufficiente sono di solito il risultato finale di una pressione sostenuta. La soluzione raramente è "alzare tutti i limiti".

Trattare la Garbage Collection come un Sintomo

Le versioni recenti di Elasticsearch scelgono per te le impostazioni predefinite JVM supportate. Evita di personalizzare la messa a punto del garbage collector a meno che tu non abbia indicazioni e misurazioni specifiche per la versione. Le pause lunghe di solito indicano un eccesso di shard, aggregazioni costose, fielddata, troppa pressione sull'heap o nodi insufficienti.

Gli indicatori chiave dei problemi di GC includono:

  • Tempo di GC elevato.
  • Lunghe pause stop-the-world.
  • Utilizzo dell'heap che risale vicino al limite dopo ogni raccolta.
  • Errori OOM durante ricerche di grandi dimensioni, indicizzazione in blocco o aggregazioni.

Rispettare gli Interruttori Automatici

Gli interruttori automatici stimano l'utilizzo della memoria e rifiutano le operazioni prima che possano esaurire il nodo.

  • Interruttore Fielddata: Limita l'heap utilizzato per fielddata.
  • Interruttore delle Richieste: Limita la memoria utilizzata per completare le strutture dati delle richieste.
  • Interruttore Principale: Tiene traccia delle stime combinate degli interruttori.

Visualizza le statistiche degli interruttori con:

curl -X GET "localhost:9200/_nodes/stats/breaker?pretty"

Puoi modificare alcune impostazioni degli interruttori tramite le impostazioni del cluster, ma fallo solo dopo aver capito perché l'interruttore scatta. Un interruttore che scatta spesso protegge il nodo da un OOM.

Monitorare e Avvisare

Avvisa su:

  • Utilizzo dell'heap JVM dopo la garbage collection.
  • Tempo di garbage collection e pause lunghe.
  • Interventi degli interruttori automatici.
  • Pressione dell'indicizzazione e attività rifiutate dal pool di thread.
  • Pressione della memoria del sistema operativo e utilizzo dello swap.
  • Numero di shard per nodo e aggregazioni insolitamente grandi.

Conclusione

Inizia con la dimensione dell'heap, poi esamina il numero di shard, i mapping dei campi, le aggregazioni di grandi dimensioni e gli interventi ripetuti degli interruttori automatici. Se il tuo nodo è ancora sotto pressione dopo la pulizia, aggiungi capacità o suddividi i carichi di lavoro invece di nascondere i segnali di avvertimento con limiti più grandi.