Os nove ancinhos do Elasticsearch em que pisei

Ilustração de Anton Gudim


“Uma pessoa treinada também está pisando em um ancinho.
Mas, por outro lado, onde está a caneta.

O Elasticsearch é uma ótima ferramenta, mas cada ferramenta requer não apenas ajuste e manutenção , mas também atenção aos detalhes. Alguns são insignificantes e jazem na superfície, enquanto outros estão escondidos tão fundo que levará mais de um dia para procurar, nem uma dúzia de xícaras de café e nem um quilômetro de nervos. Neste artigo, vou falar sobre nove ancinhos maravilhosos nas configurações elásticas em que pisei.

Vou organizar o rake em ordem decrescente de evidência. Das que podem ser previstas e contornadas na fase de criação e entrada de um cluster no estado de produção, às muito estranhas que trazem mais experiência (e estrelas nos olhos).

Nós de dados devem ser os mesmos


“O cluster está executando na velocidade do nó de dados mais lento” - um axioma agonizado. Mas há outro ponto óbvio que não está relacionado ao desempenho: o elástico pensa não no espaço em disco, mas nos fragmentos, e tenta distribuí-los uniformemente entre os nós de dados. Se alguns dos nós de dados tiverem mais espaço que outros, será inútil permanecer ocioso.

Deprecation.log


Pode acontecer que alguém não use os meios mais modernos de enviar dados para o elástico, que não pode definir o Tipo de Conteúdo ao executar consultas. Nesta lista, por exemplo, heka, ou quando os logs deixarem os dispositivos por seus meios internos). Nesse caso, descontinuação. o log começa a crescer a uma taxa alarmante e, para cada solicitação, as seguintes linhas aparecem nele:

[2018-07-07T14:10:26,659][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,670][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,671][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,673][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,677][WARN ][oedrRestController ] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. 

As solicitações ocorrem, em média, a cada 5 a 10 ms - e sempre que uma nova linha é adicionada ao log. Isso afeta negativamente o desempenho do subsistema de disco e aumenta o iowait. O Deprecation.log pode ser desativado, mas não é muito razoável. Para coletar logs elásticos nele, mas não para o lixo, desabilito apenas os logs da classe oedrRestController.

Para fazer isso, inclua a seguinte construção em logs4j2.properties:

 logger.restcontroller.name = org.elasticsearch.deprecation.rest.RestController logger.restcontroller.level = error 

Ele elevará os logs dessa classe para o nível de erro e eles não cairão mais no deprecation.log.

.kibana


Como é um processo típico de instalação de cluster? Colocamos os nós, combinamos em um cluster, colocamos o x-pack (quem precisa dele) e, claro, o Kibana. Começamos, verificamos que tudo está funcionando e o Kibana vê o cluster e continuamos a configurar. O problema é que, em um cluster recém-instalado, o modelo padrão é mais ou menos assim:

 { "default": { "order": 0, "template": "*", "settings": { "number_of_shards": "1", "number_of_replicas": "0" } }, "mappings": {}, "aliases": {} } 

E o índice .kibana, onde todas as configurações são armazenadas, é criado em uma única cópia.

Houve um caso em que, devido a uma falha de hardware, um dos nós de dados no cluster foi morto. Ele chegou rapidamente a um estado consistente, gerando réplicas de fragmentos de nós de dados vizinhos, mas, felizmente, foi nesse nó de dados que o único fragmento com o índice .kibana foi localizado. A situação é impassível - o cluster está ativo, em condições de trabalho, e Kibana está no status vermelho, e meu telefone é interrompido por telefonemas de funcionários que precisam urgentemente de seus registros.

Tudo isso é resolvido simplesmente. Até agora, nada caiu:

 XPUT .kibana/_settings { "index": { "number_of_replicas": "<__>" } } 

XMX / XMS


A documentação diz "Não mais que 32 GB", e com razão. Mas também é correto que você não precise instalar nas configurações de serviço
 -Xms32g -Xmx32g 

Como ele já tem mais de 32 gigabytes, e aqui encontramos uma nuance interessante de Java trabalhando com memória. Acima de um certo limite, o Java deixa de usar ponteiros compactados e começa a consumir uma quantidade excessiva de memória. Verificar se os ponteiros compactados usam uma máquina Java executando o Elasticsearch é muito simples. Examinamos o log de serviço:

 [2018-07-29T15:04:22,041][INFO][oeeNodeEnvironment][log-elastic-hot3] heap size [31.6gb], compressed ordinary object pointers [true] 

A quantidade de memória que não deve ser excedida depende, inter alia, da versão do Java usada. Para calcular o volume exato no seu caso, consulte a documentação .

Agora eu instalei em todos os nós de dados do elastic:

 -Xms32766m -Xmx32766m 

Parece ser um fato banal, e a documentação está bem descrita, mas encontro regularmente instalações do Elasticsearch onde perdi esse ponto e Xms / Xmx está definido como 32g.

/ var / lib / elasticsearch


Esse é o caminho padrão para armazenar dados na elasticsearch. yml:

 path.data: /var/lib/elasticsearch 

Normalmente, eu monto uma grande matriz RAID e aqui está o porquê: especificamos o ES de várias maneiras para armazenar dados, por exemplo, assim:

 path.data: /var/lib/elasticsearch/data1, /var/lib/elasticsearch/data2 

Diferentes discos ou matrizes de ataque são montados nos dados1 e dados2. Mas o elástico não se equilibra e não distribui a carga entre esses caminhos. Primeiro, ele preenche uma seção e começa a escrever em outra, para que a carga no armazenamento seja desigual. Sabendo disso, tomei uma decisão inequívoca - combinei todos os discos no RAID0 / 1 e montei-o no caminho especificado em path.data.

processadores disponíveis


E não, não me refiro a processadores em nós de entrada agora. Se você observar as propriedades de um nó em execução (por meio da API _nodes), poderá ver algo assim:

 "os". { "refresh_interval_in_millis": 1000, "name": "Linux", "arch": "amd64", "version": "4.4.0-87-generic", "available_processors": 28, "allocated_processors": 28 } 

Pode-se observar que o nó está sendo executado em um host com 28 núcleos, e o elástico determinou corretamente seu número e iniciou tudo. Mas se houver mais de 32 núcleos, às vezes acontece assim:

 "os": { "refresh_interval_in_millis": 1000, "name": "Linux", "arch": "amd64", "version": "4.4.0-116-generic", "available_processors": 72, "allocated_processors": 32 } 

Você precisa forçar o número de processadores disponíveis para o serviço - isso tem um bom efeito no desempenho do nó.

 processors: 72 

thread_pool.bulk.queue_size


Na seção thread_pool.bulk.rejected do último artigo, havia essa métrica - a contagem do número de falhas nas solicitações para adicionar dados.

Escrevi que o crescimento desse indicador é um sinal muito ruim, e os desenvolvedores recomendam não configurar pools de encadeamentos, mas adicionar novos nós ao cluster - supostamente, isso resolve problemas de desempenho. Mas as regras são necessárias para quebrá-las às vezes. E nem sempre é possível "resolver o problema com o ferro", portanto, uma das medidas para combater falhas em solicitações em massa é aumentar o tamanho dessa fila.

Por padrão, as configurações da fila são assim:

 "thread_pool": { "bulk": { "type": "fixed", "min": 28, "max": 28, "queue_size": 200 } } 

O algoritmo é o seguinte:

  1. Coletamos estatísticas sobre o tamanho médio da fila durante o dia (o valor instantâneo é armazenado em thread_pool.bulk.queue);
  2. Aumente cuidadosamente o tamanho da fila para tamanhos ligeiramente maiores que o tamanho médio da fila ativa - porque ocorre uma falha quando é excedida;
  3. Aumentamos o tamanho da piscina - isso não é necessário, mas aceitável.

Para fazer isso, adicione algo assim às configurações do host (é claro que você terá seus próprios valores):

 thread_pool.bulk.size: 32 thread_pool.bulk.queue_size: 500 

E depois de reiniciar o nó, monitoraremos definitivamente o consumo de carga, E / S, memória. e tudo o que é possível reverter as configurações, se necessário.

Importante: essas configurações fazem sentido apenas nos nós que trabalham no recebimento de novos dados.

Criação de Índice Preliminar


Como eu disse no primeiro artigo da série, usamos o Elasticsearch para armazenar os logs de todos os microsserviços. A linha inferior é simples - um índice armazena os logs de um componente em um dia.

A partir disso, segue-se que todos os dias novos índices são criados pelo número de microsserviços - portanto, mais cedo todas as noites, o elástico cai no clinch por cerca de 8 minutos, enquanto uma centena de novos índices é criada, várias centenas de novos fragmentos, o cronograma de carregamento do disco sai da prateleira, as filas crescem para enviar logs para o elástico nos hosts, e o Zabbix floresceu com alertas como uma árvore de Natal.

Para evitar isso, era senso comum escrever um script Python para pré-criar índices. O script funciona assim: ele encontra os índices para hoje, extrai seus mapeamentos e cria novos índices com os mesmos mapeamentos, mas para o dia seguinte. É executado no cron, executado durante aquelas horas em que o Elastic é o menos carregado. O script usa a biblioteca elasticsearch e está disponível no GitHub .

Páginas enormes transparentes dos pais


Uma vez que descobrimos que os nós elásticos que operam a recepção de dados começaram a ficar sob carga durante o horário de pico. E com sintomas muito estranhos: o uso de todos os núcleos do processador cai para zero, mas, no entanto, o serviço fica travado na memória, escuta adequadamente a porta, não faz nada, não responde às solicitações e depois de algum tempo sai do cluster. O serviço não responde à reinicialização do systemctl. Somente a boa e velha matança -9 ajuda.

Isso não é percebido pelas ferramentas de monitoramento padrão; nos gráficos, até o momento do outono, a imagem regular, nos registros de serviço - fica vazia. O despejo de memória da máquina java neste momento também não foi possível.

Mas, como eles dizem, "somos profissionais, então, depois de algum tempo, pesquisamos a solução no Google". Um problema semelhante foi abordado no tópico discuss.elastic.co e acabou sendo um bug do kernel relacionado a páginas enormes e transparentes. Tudo foi resolvido desativando o thp no kernel usando o pacote sysfsutils.

Verificar se você tem páginas enormes transparentes ativadas é simples:

 cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never] 

Se [sempre] estiver lá, você estará potencialmente em risco.

Conclusão


Este é o rake principal (de fato, havia, é claro, mais), que por algum tempo eu andei por um ano e meio como administrador do cluster do Elasticsearch. Espero que essas informações sejam úteis na jornada difícil e misteriosa para o cluster ideal do Elasticsearch.

Obrigado pela ilustração, Anton Gudim - ainda há muito de bom em seu instagram .

Source: https://habr.com/ru/post/pt419041/


All Articles