Otimizando o Uso de Memória do Elasticsearch para Desempenho Máximo
Domine o gerenciamento de memória do Elasticsearch para obter o máximo desempenho. Este guia explora técnicas vitais, incluindo dimensionamento do heap da JVM, otimização da indexação e busca, aproveitamento de cache e implantação de circuit breakers para prevenir erros de OutOfMemory. Aprenda estratégias práticas para garantir que seu cluster Elasticsearch permaneça estável e responsivo, mesmo sob carga pesada.
Otimizando o Uso de Memória do Elasticsearch para Desempenho Máximo
Problemas de memória no Elasticsearch geralmente se manifestam como pesquisas lentas, longas pausas de coleta de lixo, erros de disjuntor ou nós que saem do cluster. Otimizar o uso de memória do Elasticsearch significa equilibrar o heap JVM, o cache do sistema de arquivos, a quantidade de shards, o comportamento das consultas e a pressão de indexação, em vez de apenas aumentar -Xmx.
O objetivo é simples: fornecer ao Elasticsearch heap suficiente para o trabalho do cluster e das consultas, deixando RAM suficiente para que o sistema operacional armazene em cache os arquivos de segmento do Lucene.
Entenda os Componentes de Memória do Elasticsearch
O Elasticsearch usa memória em duas áreas principais:
- Heap JVM: Armazena metadados do cluster, buffers de indexação, estruturas de consulta, fielddata quando ativado, caches e outros objetos Java. Pouco heap causa pressão e disparos do disjuntor. Muito heap pode prolongar a coleta de lixo e prejudicar o cache do sistema de arquivos.
- Cache do sistema de arquivos e memória nativa: O sistema operacional armazena em cache os arquivos de índice do Lucene fora do heap JVM. O Elasticsearch também usa memória nativa para rede, pilhas de threads e arquivos mapeados em memória.
Configure o Tamanho do Heap JVM
O dimensionamento do heap é a primeira configuração a verificar. O Elasticsearch usa arquivos jvm.options ou opções JVM específicas do ambiente, dependendo de como foi instalado.
Defina Xms e Xmx Juntos
Defina -Xms e -Xmx com o mesmo valor para que a JVM não redimensione o heap enquanto o nó estiver em execução.
Como regra geral, mantenha o heap em ou abaixo de cerca de metade da RAM física e evite ultrapassar o limite do ponteiro de objeto comum comprimido. Na prática, muitos nós de produção ficam abaixo de aproximadamente 30 GB de heap, mas você deve verificar o limite exato e as orientações para sua versão do Elasticsearch e da JVM.
Por exemplo:
-Xms4g
-Xmx4g
Isso define o heap inicial e máximo como 4 GB.
Monitore o Uso do Heap
Use o Kibana Stack Monitoring, exportadores Prometheus ou a API Nodes Stats:
curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"
Observe heap_used_percent, tempo de coleta de lixo, pressão da geração antiga e disparos do disjuntor. O heap que permanece alto por longos períodos após a coleta de lixo geralmente significa que você precisa reduzir os consumidores de heap ou adicionar capacidade.
Reduza a Pressão de Memória de Shards e Consultas
O layout do índice e a forma da consulta têm um efeito direto na memória.
Tamanho e Quantidade de Shards
Cada shard tem sobrecarga. Muitos shards minúsculos desperdiçam heap e retardam as operações do cluster. Shards muito grandes podem tornar a recuperação e a realocação problemáticas. Muitos clusters funcionam bem com tamanhos de shard na casa das dezenas de gigabytes, mas logs, dados de séries temporais e índices com muitas pesquisas podem precisar de alvos diferentes.
Por exemplo, se um índice de log diário cria 30 shards primários para 20 GB de dados, você está pagando pela sobrecarga de muitos shards pequenos. Um ou dois primários podem ser mais fáceis de gerenciar, dependendo da retenção e dos padrões de consulta.
Mesclagem de Segmentos
O Elasticsearch usa segmentos Lucene para indexação. Segmentos menores são mesclados em maiores ao longo do tempo. Esse processo pode consumir muita memória. Embora o Elasticsearch lide com a mesclagem automaticamente, entender seu impacto pode ser benéfico, especialmente durante cargas pesadas de indexação.
Otimização de Pesquisa e Agregação
- Use campos keyword para agregações: Agregue e classifique em campos
keyword, numéricos, de data ou outros campos com suporte a doc-values. Evite ativarfielddataem campostextgrandes, a menos que você entenda o custo do heap. - Limite consultas caras: Consultas curinga iniciais e de expressão regular amplas podem ser caras. Prefira campos estruturados, prefixos, n-gramas ou mapeamentos de pesquisa conforme você digita quando o caso de uso precisar de correspondência parcial.
- Perfile pesquisas lentas: Use a API de perfil em um ambiente de teste para encontrar as cláusulas de consulta que criam mais trabalho.
Use Caches Deliberadamente
O Elasticsearch tem vários caches. Eles ajudam no trabalho repetido, mas também consomem memória.
Cache de solicitação de shard: Armazena em cache os resultados de pesquisa no nível do shard para solicitações elegíveis, geralmente útil para consultas repetidas de estilo de agregação em dados praticamente inalterados. Seu tamanho é controlado com:
indices.requests.cache.size: 5%Este exemplo define o tamanho do cache de solicitação de shard como 5% do heap.
Cache de consulta do nó: Armazena em cache os resultados do contexto do filtro. Seu tamanho é controlado separadamente:
indices.queries.cache.size: 10%Cache de fielddata: Consome heap e pode crescer rapidamente se você ativar fielddata em campos de texto. Prefira mapear campos corretamente em vez de confiar em um cache de fielddata maior.
Previna Erros de Falta de Memória
Erros de falta de memória geralmente são o resultado final de pressão sustentada. A correção raramente é "aumentar todos os limites".
Trate a Coleta de Lixo como um Sintoma
Versões recentes do Elasticsearch escolhem os padrões JVM suportados para você. Evite ajustes personalizados do coletor de lixo, a menos que você tenha orientações e medições específicas da versão. Pausas longas geralmente apontam para excesso de sharding, agregações caras, fielddata, muita pressão no heap ou nós insuficientes.
Indicadores principais de problemas de GC incluem:
- Alto tempo de GC.
- Longas pausas de parada do mundo.
- Uso de heap que sobe perto do limite após cada coleta.
- Erros OOM durante grandes pesquisas, indexação em lote ou agregações.
Respeite os Disjuntores
Os disjuntores estimam o uso de memória e rejeitam operações antes que elas possam esgotar o nó.
- Disjuntor de fielddata: Limita o heap usado para fielddata.
- Disjuntor de solicitação: Limita a memória usada para concluir as estruturas de dados da solicitação.
- Disjuntor pai: Rastreia as estimativas combinadas do disjuntor.
Veja as estatísticas do disjuntor com:
curl -X GET "localhost:9200/_nodes/stats/breaker?pretty"
Você pode alterar algumas configurações do disjuntor por meio das configurações do cluster, mas faça isso somente depois de saber por que o disjuntor está disparando. Um disjuntor disparado geralmente está protegendo o nó de um OOM.
Monitore e Alerte
Alerta sobre:
- Uso de heap JVM após a coleta de lixo.
- Tempo de coleta de lixo e pausas longas.
- Disparos do disjuntor.
- Pressão de indexação e tarefas rejeitadas do pool de threads.
- Pressão de memória do SO e uso de swap.
- Número de shards por nó e agregações excepcionalmente grandes.
Conclusão
Comece com o dimensionamento do heap, depois observe a quantidade de shards, mapeamentos de campos, agregações grandes e disparos repetidos do disjuntor. Se o seu nó ainda estiver sob pressão após a limpeza, adicione capacidade ou divida as cargas de trabalho em vez de esconder os sinais de alerta com limites maiores.