Ajuste avançado: localização e correção de consultas lentas do Elasticsearch

O Elasticsearch é uma aplicação muito flexível e com recursos sofisticados que oferece muitas maneiras diferentes de consultar seus dados. Mas você já teve a experiência de velocidades de consulta menores do que esperava? Com um sistema distribuído como o Elasticsearch, pode haver diversos fatores possíveis que contribuem para a performance das consultas, incluindo fatores externos como configurações de balanceador de carga, latência de rede (largura de banda, placas NIC/drivers) etc.

Neste blog, vou tratar das causas das consultas lentas e de como identificá-las no contexto do Elasticsearch. Este artigo se baseou em alguns dos nossos métodos comuns de solução de problemas que podem exigir que o usuário tenha certa familiaridade com a maneira como o Elasticsearch funciona.

Causas comuns das consultas lentas do Elasticsearch

Antes de analisarmos alguns dos casos mais capciosos, vamos começar com algumas das causas mais comuns das consultas lentas e suas soluções.

Sintoma: Alta utilização de recursos quando inativo

Cada shard consome recursos (CPU/memória). Mesmo com zero solicitações de indexação/busca, a existência de shards consome overheads de cluster.

Problema

O cluster tem excesso de shards em um ponto em que qualquer consulta pode parecer lenta para ser executada. Uma ótima regra prática é garantir que você mantenha o número de shards não congelados por nó abaixo de 20 GB por heap configurado.

Solução

Reduza a contagem de shards, congele os índices e/ou adicione outros nós para lidar com a carga. Considere a arquitetura hot/warm (funciona muito bem para índices baseados em tempo) juntamente com o recurso de rollover/shrink no Elasticsearch para gerenciar com eficiência a contagem de shards. Um bom começo para qualquer implantação seria executar o planejamento de capacidade adequado para ajudar a determinar a quantidade ideal de shards para cada caso de uso de busca.

Sintoma: alta contagem de rejeições de thread pool

O thread pool de busca está mostrando um aumento constante na contagem "rejected" (rejeitado) que é cumulativa com base na última reinicialização de cluster.

GET /_cat/thread_pool/search?v&h=node_name,name,active,rejected,completed

A resposta tem aparência semelhante a esta:

node_name             name   active rejected completed
instance-0000000001   search      0       10         0
instance-0000000002   search      0       20         0
instance-0000000003   search      0       30         0

Problema

As consultas têm como alvo uma quantidade excessiva de shards, superando a quantidade de cores no cluster. Isso cria filas de tarefas no thread pool de busca, resultando em rejeições de busca. Outra causa comum é o E/S de disco lento que faz com que as buscas se acumulem em fila ou em alguns casos uma CPU completamente saturada. 

Solução

Adote um modelo de 1 Principal : 1 Réplica ao criar índices. O modelo de índice é um ótimo método para fazer rollout dessa configuração no tempo do índice. (1P:1R será padrão no Elasticsearch 7.0 ou posterior). O Elasticsearch 5.1 ou posterior dá suporte ao cancelamento de tarefa de busca, que pode ser útil quando a consulta lenta aparece na API de gerenciamento de tarefas. Para melhorar o E/S de disco, confira nossas recomendações de armazenamento e verifique se usou o hardware recomendado para obter máxima performance.

Sintoma: alta latência de CPU e indexação

A correlação de metrics mostra alta utilização de CPU e latência de indexação quando o cluster é pressionado.

Problema

O cluster passa por intensa indexação, o que afeta a performance de busca.

Solução

O aumento de index.refresh_ interval (quantidade de tempo entre quando um documento é indexado e quando ele fica visível) para um valor como 30 s geralmente ajuda a melhorar a performance de indexação. A velocidade real pode variar, por isso é crucial fazer testes. Isso garante que os shards não precisem trabalhar tão intensamente criando um novo segmento a cada 1 segundo (padrão).

Para um caso de uso de indexação intensa, confira nossas recomendações de ajuste de índice para otimizar a performance do índice e da busca.

Sintoma: maior latência com mais shards de réplica

A latência da consulta pode ser observada após aumentar a contagem de shards de réplica (por exemplo, de 1 para 2). Se mais dados estiverem presentes, os dados armazenados em cache serão eliminados mais cedo, resultando em aumento nas falhas de página do sistema operacional.

Problema

O cache do sistema de arquivos não tem memória suficiente para armazenar em cache partes do índice consultadas com frequência. O cache de consulta do Elasticsearch implementa uma política de eliminação de LRU: quando o cache fica cheio, os dados menos usados recentemente são eliminados para liberar espaço para novos dados.

Solução

Reserve pelo menos 50% da RAM física para o cache do sistema de arquivos. A quantidade maior de memória garantirá o armazenamento em cache de mais memória principalmente se o cluster estiver passando por problemas de E/S. Pressupondo que o tamanho de heap tenha sido configurado adequadamente, qualquer RAM física remanescente que possa ser usada para o cache do sistema de arquivos percorrerá um longo caminho para acelerar a performance de busca.

Por exemplo, um servidor com 128 GB de RAM tem 30 GB reservados para heap e memória remanescente para o cache do sistema de arquivos (às vezes chamado de cache de sistema operacional), que é um método para que o sistema operacional armazene em cache blocos de 4 KB de dados acessados recentemente, de maneira que, se você ler os mesmos arquivos várias vezes e não precisar acessar o disco na maior parte do tempo, a solicitação de leitura será atendida diretamente da memória.

Além do cache do sistema de arquivos, o Elasticsearch usa o cache de consulta e o cache de solicitação para acelerar as buscas. Todos esses caches podem ser otimizados usando search-request-preference para rotear determinadas solicitações de busca para o mesmo conjunto de shards todas as vezes, em vez de alternar entre as diferentes cópias disponíveis. Isso permitirá o melhor uso do cache de solicitação, do cache de consulta de nó e do cache do sistema de arquivos.

Sintoma: alta utilização ao compartilhar recursos

O sistema operacional mostra utilização consistentemente alta de CPU e E/S de disco. O ganho de performance pode ser visto depois de parar aplicações de terceiros.

Problema

Há uma contenção de recursos (CPU e/ou E/S de disco) entre outros processos (por exemplo: Logstash) e o Elasticsearch em si.

Solução

Evite executar o Elasticsearch juntamente com outras aplicações de uso intenso de recursos no hardware compartilhado.

Sintoma: alta utilização de heap agregando campos altamente exclusivos

A baixa performance ao consultar campos agregados que contêm valores altamente exclusivos (por exemplo: IDs, nomes de usuário, endereços de e-mail etc). Durante a análise de heap dump, você deve ver objetos Java com termos como "busca", "períodos", "agregação" etc., consumindo grande parte do heap.

Problema

As agregações estão sendo executadas em campos de alta cardinalidade que exigem muitos recursos para procurar muitos períodos. Também pode haver agregações relacionadas envolvendo campos aninhados e/ou campos de associação.

Solução

Para melhorar a performance de agregações de termos de alta cardinalidade, leia esta postagem de blog do meu colega da equipe de consultoria: https://www.elastic.co/pt/blog/improving-the-performance-of-high-cardinality-terms-aggregations-in-elasticsearch

Para fazer mais ajustes, confira nossas recomendações sobre campos aninhados e campos de associação para melhorar a performance das agregações.

Consultas lentas ocasionais

Falando no geral, consultas lentas ocasionais ou intermitentes podem se beneficiar de parte das recomendações de ajuste para índice/ajuste para busca. As consultas lentas ocasionais devem ser correlacionadas atentamente a uma ou mais dessas metrics de monitoramento:

O Elasticsearch tem outro recurso útil chamado ARS (seleção adaptável de réplicas) que permite que o nó coordenador esteja ciente da carga nos nós de dados e também que ele escolha as melhores cópias de shard para executar uma busca, melhorando assim o throughput de busca e a latência. O ARS pode ser de grande ajuda para lentidões ocasionais espalhando com mais uniformidade a carga durante o tempo da consulta. No Elasticsearch 7.0 e posterior, o ARS será ativado por padrão.

Consultas lentas consistentes

No caso de consultas lentas consistentes, podemos tentar remover recursos da consulta um por um e verificar se ela ainda está lenta. A localização da consulta mais simples que reproduz o problema de performance ajuda a isolar e identificar o problema:

  • Ela ainda é lenta sem os destaques?
  • Ela ainda é lenta sem as agregações?
  • Ela ainda é lenta se size é definido como 0? (quando size é definido como 0, o Elasticsearch armazena em cache os resultados das solicitações de busca para acelerar a busca)

Ela pode se beneficiar de algumas das recomendações de "ajuste para busca"?

Durante a resolução de problemas, com frequência é útil:

  • Obter uma resposta a consulta com o perfil ativado.
  • Reunir a saída nodes hot threads com a consulta sendo executada em um loop while(true). Isso ajudará a entender em que o tempo de CPU é gasto.
  • Perfilar a consulta usando esta versão amigável da API de perfil.

Se uma consulta vier de uma visualização do Kibana, use o painel espião de visualização (Kibana versão 6.3 e anterior) ou o painel de inspeção de dashboard (Kibana versão 6.4 e posterior) para exibir e exportar a solicitação de consulta real e importá-la para a API de perfil para maior análise.

Interceptação de consultas lentas ou caras

Às vezes é difícil interceptar consultas lentas ou caras com diferentes solicitações/threads sendo processados simultaneamente em uma aplicação distribuída como o Elasticsearch. Tudo fica mais complicado quando não há controle sobre os usuários que executam consultas caras que causam lentidão na performance do cluster (por exemplo, longos ciclos de coleta de lixo), ou pior, uma situação de memória insuficiente.

No Elasticsearch versão 7.0, lançamos uma nova estratégia de curto-circuito que mede a utilização real da memória de heap no momento em que a memória está sendo reservada. Essa nova estratégia melhora a resiliência do nó com base nas consultas caras fazendo com que o cluster seja sobrecarregado e é ativada por padrão e pode ser controlada com a nova configuração de cluster indices.breaker.total.use_real_memory.

Entretanto, devemos observar que esses são os melhores esforços; para cenários fora desse escopo, seria útil coletar o heap dump depois da falha de memória insuficiente ou o heap dump a partir de um JVM em execução para entender melhor a causa principal.

O Elasticsearch tem outra configuração de proteção (max bucket soft limit) para resguardar o cluster contra memória insuficiente. Essa configuração de agregação de período máximo para a execução e causa falha na solicitação de busca quando a quantidade de períodos (com padrão de 10.000 na versão 7.0) é superada (por exemplo, ao executar várias camadas de agregações).

Para identificar melhor as consultas caras potenciais, podemos definir a configuração de disjuntor (indices.breaker.request.limit) começando com um limite inferior para isolar as consultas e gradualmente elevar o limite para restringir para as específicas.

Slowlogs

As consultas de execução lenta também podem ser identificadas ativando os slowlogs no Elasticsearch. Os slowlogs funcionam especificamente no nível do shard, o que significa que somente o nó de dados se aplica. Os nós somente coordenadores/clientes são excluídos à medida que não retêm dados (índices/shards).

Os slowlogs ajudam a responder a perguntas como:

  • Quanto tempo a consulta durou?
  • Qual era o conteúdo do corpo da solicitação de consulta?

Amostra de saída de slowlog:

[2019-02-11T16:47:39,882][TRACE][index.search.slowlog.query] [2g1yKIZ] [logstash-20190211][4] took[10.4s], took_millis[10459], total_hits[16160], types[], stats[], 
search_type[QUERY_THEN_FETCH], total_shards[10], source[{"size":0,"query":{"bool":{"must":[{"range":{"timestamp":{"from":1549266459837,"to":1549871259837,"include_lower":true,
"include_upper":true,"format":"epoch_millis","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"_source":{"includes":[],"excludes":[]},"stored_fields":"*","docvalue_fields":
[{"field":"timestamp","format":"date_time"},{"field":"utc_time","format":"date_time"}],"script_fields":{"hour_of_day":{"script":{"source":"doc['timestamp'].value.getHourOfDay()",
"lang":"painless"},"ignore_failure":false}},"aggregations":{"maxAgg":{"max":{"field":"bytes"}},"minAgg":{"min":{"field":"bytes"}}}}], id[]],

Divisão das partes da mensagem de slowlog:

ItemDescrição
[2019-02-11T16:47:39,882]Data da consulta
[TRACE]Nível de log
[index.search.slowlog.query]Fase de consulta do slowlog de busca
[2g1yKIZ]Nome do nó
[logstash-20190211]Nome do índice
[4]Número do shard na consulta executada
took[10.4s]Duração do tempo de processamento no shard [4]. Observação: ao analisar os slowlogs, queremos evitar o acúmulo de todos os tempos de diferentes shards, uma vez que cada shard pode estar sendo executado em paralelo.
took_millis[10459]Duração de tempo em milissegundos
total_hits[16160]Total de hits
search_type[QUERY_THEN_FETCH]Tipo de busca
total_shards[10]Total de shards do índice
source[]O corpo da consulta que foi executada

Logs de auditoria

Os clientes com assinatura Gold ou Platinum, que inclui os recursos de segurança do Elastic, podem ativar os logs de auditoria para capturar mais detalhes sobre a consulta. (Os usuários podem começar uma avaliação por 30 dias para fazer um test drive dos recursos de segurança do Elastic.) O logging de auditoria ajuda a responder a perguntas como:

  • Quando a consulta aconteceu?
  • Quem executou a consulta?
  • Qual é o conteúdo da consulta?

Precisamos ajustar as configurações de auditoria, porque as configurações padrão são muito informais:

  1. Habilitar o log de auditoria de segurança: Defina xpack.security.audit.enabled: true em elasticsearch.yml.
  2. Habilitar o log ou índice nas saídas de auditoria de segurança: Defina xpack.security.audit.outputs:[logfile, index] em elasticsearch.yml.

    Observações:
    • A configuração xpack.security.audit.outputs só se aplica às versões 6.0-6.2 e 5.x. A versão 7.0 não aceita mais essa configuração e entra no padrão da saída de json (<nome_do_cluster>_audit.json) quando xpack.security.audit.enabled está definido como true.
    • Para fins de resolução de problemas, recomendamos escolher logfile em vez de index porque o texto excessivo do logging de auditoria pode ocasionar sobrecarga indesejada na performance do cluster no ponto em que o índice de segurança cresce além do tamanho pretendido.
    • O modo de auditoria pode ter texto excessivo, por isso avalie a sua desativação depois que concluir a resolução de problemas.
  3. Inclua o acesso de authentication_success em sua lista de eventos: Defina xpack.security.audit.logfile.events.include: authentication_success em elasticsearch.yml.

    Observações:
    • Essa configuração não está incluída nos eventos padrão. Essa configuração substituirá aquelas que são padrão.
    • Se você precisar adicionar mais um evento (não substituir), grave a lista de eventos padrão existente primeiro e adicione a configuração anterior após a última entrada.
    • Gere saída do corpo da solicitação nos eventos de auditoria: Defina xpack.security.audit.logfile.events.emit_request_body: true em elasticsearch.yml.

Com essas configurações, você pode monitorar a consulta de usuário assim.

  • Usuário: louisong
  • Tempo de consulta: 2019-05-01T19:26:53,554 (UTC)
  • Endpoint de consulta: _msearch (normalmente significa que é uma consulta emitida do Kibana Visualization/Dashboard)
  • Corpo da consulta: comece de "request.body": no log a seguir:

    {"@timestamp":"2019-05-01T19:26:53,554", "node.id":"Z1z_64sIRcy4dW2eqyqzMw", "event.type":"rest", "event.action":"authentication_success", "user.name":"louisong", "origin.type":"rest", "origin.address":"127.0.0.1:51426", "realm":"default_native", "url.path":"/_msearch", "url.query":"rest_total_hits_as_int=true&ignore_throttled=true", "request.method":"POST", "request.body":"{\"index\":\"*\",\"ignore_unavailable\":true,\"preference\":1556709820160}\n{\"aggs\":{\"2\":{\"terms\":{\"field\":\"actions\",\"size\":5,\"order\":{\"_count\":\"desc\"},\"missing\":\"__missing__\"}}},\"size\":0,\"_source\":{\"excludes\":[]},\"stored_fields\":[\"*\"],\"script_fields\":{},\"docvalue_fields\":[{\"field\":\"access_token.user_token.expiration_time\",\"format\":\"date_time\"},{\"field\":\"canvas-workpad.@created\",\"format\":\"date_time\"},{\"field\":\"canvas-workpad.@timestamp\",\"format\":\"date_time\"},{\"field\":\"creation_time\",\"format\":\"date_time\"},{\"field\":\"expiration_time\",\"format\":\"date_time\"},{\"field\":\"maps-telemetry.timeCaptured\",\"format\":\"date_time\"},{\"field\":\"task.runAt\",\"format\":\"date_time\"},{\"field\":\"task.scheduledAt\",\"format\":\"date_time\"},{\"field\":\"updated_at\",\"format\":\"date_time\"},{\"field\":\"url.accessDate\",\"format\":\"date_time\"},{\"field\":\"url.createDate\",\"format\":\"date_time\"}],\"query\":{\"bool\":{\"must\":[{\"range\":{\"canvas-workpad.@timestamp\":{\"format\":\"strict_date_optional_time\",\"gte\":\"2019-05-01T11:11:53.498Z\",\"lte\":\"2019-05-01T11:26:53.498Z\"}}}],\"filter\":[{\"match_all\":{}},{\"match_all\":{}}],\"should\":[],\"must_not\":[]}},\"timeout\":\"30000ms\"}\n", "request.id":"qrktsPxyST2nVh29GG7tog"}
        

    Conclusão

    Neste artigo, falamos sobre as causas comuns das consultas lentas e as soluções para abordá-las. Também discutimos os diferentes métodos para identificar consultas lentas consistentes e ocasionais. É comum ver consultas lentas como sintomas de um problema mais amplo da performance do cluster que precisa ser enfrentado.

    No Elasticsearch, estamos constantemente procurando melhorar os tempos de consulta e trabalhando para oferecer mais rapidez na performance de consultas com nossas futuras versões. Espero que você ache este artigo útil ao lidar com consultas lentas. Fique à vontade para postar perguntas em nosso fórum de discussão do Elasticsearch para aprofundar a discussão. Boas buscas!