Como gerenciar e solucionar problemas de memória do Elasticsearch

Com o Elastic Cloud oferecendo soluções como Observability, Security, e busca, ampliamos o número de usuários que utilizam o Elastic Cloud além das equipes completas de operações, incluindo engenheiros de dados, equipes de segurança e consultores. Como representante de suporte da Elastic, gostei de interagir com uma ampla variedade de usuários e casos de uso.

Com um público maior, estou vendo mais perguntas sobre como gerenciar a alocação de recursos, em particular solucionar problemas de integridade da alocação e evitar disjuntores. Eu entendo! Quando comecei com o Elasticsearch, eu tinha as mesmas perguntas. Foi minha primeira introdução ao gerenciamento de heap Java e shards de banco de dados de séries temporais e ao redimensionamento de minha própria infraestrutura.

Quando entrei na Elastic, adorei que, além da documentação, tínhamos blogs e tutoriais para que eu pudesse me integrar rapidamente. Mas eu sofri no primeiro mês para correlacionar meu conhecimento teórico com os erros que os usuários enviavam pela minha fila de tíquetes. Por fim, descobri, como outros representantes de suporte, que muitos dos erros relatados eram apenas sintomas de problemas de alocação e que os mesmos sete links ajudariam os usuários a gerenciar sua alocação de recursos com sucesso.

Falando como representante de suporte, vou examinar os principais links da teoria de gerenciamento de alocação que enviamos aos usuários, os principais sintomas que vemos e para onde direcionamos os usuários a atualizar suas configurações para resolver seus problemas de alocação de recursos.

Teoria

Como uma aplicação Java, o Elasticsearch requer uma certa alocação de memória lógica (heap) da memória física do sistema. Essa alocação deve ser de até metade da RAM física, com um limite máximo de 32 GB. Um uso maior do heap geralmente é em resposta a consultas complexas e maior capacidade de armazenamento de dados. O limite de alocação de recursos (circuit breaker) padrão é de 95%, mas recomendamos o redimensionamento de recursos quando esse limite atingir consistentemente 85%

Eu recomendo muito estes artigos de visão geral para obter mais informações:

Configuração

Prontas para usar, as configurações padrão do Elasticsearch dimensionam automaticamente seu heap da JVM com base na função do nó e na memória total. No entanto, conforme necessário, você pode configurá-lo diretamente das três maneiras a seguir:

1. Diretamente no config > jvm.options dos seus arquivos locais do Elasticsearch:

## JVM configuration

################################################################
## IMPORTANT: JVM heap size
################################################################

…

# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space

-Xms4g
-Xmx4g

2. Como variável do ambiente Elasticsearch no seu docker-compose:

version: '2.2'
services:
  es01:
	image: docker.elastic.co/elasticsearch/elasticsearch:7.12.0
	environment:
  	- node.name=es01
  	- cluster.name=es
  	- bootstrap.memory_lock=true
  	- "ES_JAVA_OPTS=-Xms4g -Xmx4g"
  	- discovery.type=single-node
	ulimits:
  	memlock:
    	soft: -1
    	hard: -1
	ports:
  	- 9200:9200

3. Via nosso Elastic Cloud Hosted > Implantação > Editar visualização. Nota: o menu suspenso atribui memória física e aproximadamente metade será alocada para o heap.

camada hot de dados e conteúdo elasticsearch

Solução de problemas

Se você está enfrentando problemas de desempenho com seu cluster, provavelmente trata-se dos suspeitos de sempre:

  • Problemas de configuração: nós master subdimensionados, sem políticas ILM
  • Volume induzido: alta velocidade e carga de solicitações, sobreposição de consultas/escritas custosas
Todas as solicitações de cURL/API a seguir podem ser feitas em Elastic Cloud Hosted > Elasticsearch API Console, como um cURL para a Elasticsearch API ou em Kibana > Dev Tools.

Saúde da alocação

Índices de dados armazenados em sub-shards, que usam o heap para manutenção e durante requisições de busca e escrita. O tamanho do shard não deve ser maior que 50GB. Pegando o exemplo acima do Elastic Cloud Hosted com 8GB de memória física em duas zonas (que alocarão dois nós no total), vamos juntar isso a um exemplo:  _cat/allocation.

GET /_cat/allocation?v=true&h=shards,node
shards node
    41 instance-0000000001
    41 instance-0000000000
GET /_cluster/health?filter_path=status,*_shards

{
  "status": "green",
  "unassigned_shards": 0,
  "initializing_shards": 0,
  "active_primary_shards": 41,
  "relocating_shards": 0,
  "active_shards": 82,
  "delayed_unassigned_shards": 0
}

Se algum shard relatar >0 fora de active_shards ou active_primary_shards, você identificou uma causa de problemas de desempenho.

Na maioria das vezes, se isso reportar um problema, será unassigned_shards>0. Se esses shards forem primários, seu cluster reportará como status:red, e se for apenas réplica, reportará como status:yellow. (é por isso configurar réplicas nos índices é importante — se o cluster encontrar um problema, ele pode se recuperar em vez de sofrer perda de dados.) Vamos supor que temos um status:yellow com um único shard não atribuído. Para investigar, daríamos uma olhada em qual shard de índice está tendo problemas via _cat/shards.

GET _cat/shards?v=true&s=state
index                                 	shard prirep state    	docs   store ip       	node
logs                                  	0 	p  	STARTED     	2  10.1kb 10.42.255.40 instance-0000000001
logs                                  	0 	r  	UNASSIGNED
kibana_sample_data_logs               	0 	p  	STARTED 	14074  10.6mb 10.42.255.40 instance-0000000001
.kibana_1                             	0 	p  	STARTED  	2261   3.8mb 10.42.255.40 instance-0000000001

Então, isso será para nossos logs de índice que não são do sistema, que têm um shard de réplica não atribuído. Vamos ver o que está causando problemas executando _cluster/allocation/explain. (Dica profissional: quando você encaminha o suporte, é exatamente isso que fazemos.)

GET _cluster/allocation/explain?pretty&filter_path=index,node_allocation_decisions.node_name,node_allocation_decisions.deciders.*

{ "index": "logs",
  "node_allocation_decisions": [{
      "node_name": "instance-0000000005",
      "deciders": [{
          "decider": "data_tier",
          "decision": "NO",
          "explanation": "node does not match any index setting [index.routing.allocation.include._tier] tier filters [data_hot]"
}]}]}

Essa mensagem de erro aponta para data_hot, que faz parte de uma política de gestão de ciclo de vida do índice (ILM) e indica que nossa política de ILM é incongruente com as configurações atuais do índice. Nesse caso, a causa desse erro é a configuração de uma política ILM hot-warm sem ter nós quentes designados. (Eu precisava garantir que algo falharia, então estou forçando exemplos de erro para vocês. Para mais informações, veja este vídeo de resolução de problemas de exemplo para guia de resolução.)

Se você executar esse comando sem shards não atribuídos, vai receber um erro 400 dizendo que não consegue encontrar shards não atribuídos para explicar porque não há nada errado pararelatório.Se tiver uma causa não lógica (por exemplo, um erro temporário de rede, como node saiu do cluster durante a alocação), você pode usar o _cluster/reroute da Elastic.

POST /_cluster/reroute

Esta solicitação sem personalizações inicia um processo assíncrono em segundo plano que tenta alocar todos os shards com estado: não atribuídos. (Não faça como eu e não espere a conclusão do processo antes de contatar a equipe de desenvolvimento, pois achei que seria instantâneo e, coincidentemente, o problema foi escalado justamente quando eles disseram que não havia nada de errado, porque, na verdade, não havia mais nada.) Para obter mais informações, consulte este vídeo de solução de problemas para monitorar a saúde da alocação.

Circuit breakers

Maximizar a sua alocação de heap pode fazer com que as solicitações para o seu cluster atinjam o tempo limite ou causem erros e, com frequência, fará com que o seu cluster apresente exceções de circuit breaker. Erros de circuit breaker causam eventos no elasticsearch.log como:

Caused by: org.elasticsearch.common.breaker.CircuitBreakingException: [parent] Data too large, data for [<transport_request>] would be [num/numGB], which is larger than the limit of [num/numGB], usages [request=0/0b, fielddata=num/numKB, in_flight_requests=num/numGB, accounting=num/numGB]

Para investigar, dê uma olhada em seu heap.percent, seja examinando _cat/nodes:

GET /_cat/nodes?v=true&h=name,node*,heap*
# heap = JVM (logical memory reserved for heap)
# ram  = physical memory

name                                node.role heap.current heap.percent heap.max
tiebreaker-0000000002 mv             119.8mb           23    508mb
instance-0000000001   himrst           1.8gb           48    3.9gb
instance-0000000000   himrst           2.8gb           73    3.9gb

Ou, se você já ativou antes, navegue até o Kibana > Stack Monitoring.

nodes do elasticsearch

Se você confirmou que está atingindo seus circuit breakers de memória, considere aumentar a heap temporariamente para ter espaço para investigar. Ao investigar a causa raiz, procure em seu logging de auditoria, logging lento, clusterlogs ou elasticsearch.log pelos eventos consecutivos anteriores. Você vai procurar:

  • Consultas caras, especialmente:
    • Altas agregações de bucket
      • Eu me senti muito bobo quando descobri que as buscas alocam temporariamente uma determinada parte da sua heap antes de executarem a consulta com base no tamanho da busca ou nas dimensões do bucket, então definir 10.000.000 estava realmente dando uma dor de cabeça na minha equipe de operações.
    • mapeamentos não otimizados
      • A segunda razão para me sentir boba foi quando pensei que fazer relatórios hierárquicos faria buscas melhores do que dados nivelados (não é o caso).
  • Volume/ritmo de solicitação: geralmente consultas em lote ou assíncronas

É hora de redimensionar

Se esta não for a sua primeira vez atingindo circuit breakers ou se você suspeita que será um problema contínuo (por exemplo, atingindo 85% consistentemente, então é hora de analisar o redimensionamento de recursos), você vai querer examinar mais de perto a JVM Memory Pressure como seu indicador de heap de longo prazo. Você pode verificar isso em Elastic Cloud Hosted > Deployment.

Instâncias do Elasticsearch

Ou você pode calcular a partir de _nodes/stats:

GET /_nodes/stats?filter_path=nodes.*.jvm.mem.pools.old

{"nodes": { "node_id": { "jvm": { "mem": { "pools": { "old": {
  "max_in_bytes": 532676608,
  "peak_max_in_bytes": 532676608,
  "peak_used_in_bytes": 104465408,
  "used_in_bytes": 104465408
}}}}}}}

Onde:

JVM Memory Pressure = used_in_bytes / max_in_bytes

Um possível sintoma disso é a alta frequência e a longa duração dos eventos do coletor de lixo (gc) em seu elasticsearch.log:

[timestamp_short_interval_from_last][INFO ][o.e.m.j.JvmGcMonitorService] [node_id] [gc][number] overhead, spent [21s] collecting in the last [40s]

Se você confirmar esse cenário, precisará pensar em redimensionar seu cluster ou reduzir as demandas que o atingem. Convém investigar/considerar:

  • Aumento dos recursos de heap (heap/nó, número de nós)
  • Redução dos shards (excluir dados desnecessários/antigos; use o ILM para colocar dados em armazenamento warm/cold para que você possa encolhê-los; desative réplicas para dados que você não se importa em perder)

Estamos aqui para ajudar

Uau! Pelo que vejo no Suporte da Elastic, esse é o resumo dos tíquetes mais comuns dos usuários: shards não atribuídos, relação shard-heap desbalanceada, circuit breakers, alta coleta de lixo e erros de alocação. Todos são sintomas da conversa básica sobre gerenciamento de alocação de recursos. Espero que agora você também conheça a teoria e as etapas de resolução.

Neste ponto, porém, se você não conseguir resolver um problema, fique à vontade para entrar em contato. Teremos o maior prazer em ajudar! Fale conosco: 

Viva a nossa capacidade de autogerenciar a alocação de recursos do Elastic Stack sem depender do pessoal de operações (mas sem deixar de amá-los)!

Publicado originalmente em 27 de abril de 2021; atualizado em 5 de novembro de 2024.

O lançamento e o tempo de amadurecimento de todos os recursos ou funcionalidades descritos neste artigo permanecem a exclusivo critério da Elastic. Os recursos ou funcionalidades não disponíveis no momento poderão não ser entregues ou não chegarem no prazo previsto.