Saudações amigos!
Nos dois artigos anteriores (
um ,
dois ), mergulhamos na complexidade da escolha entre as tecnologias e procuramos as configurações ideais para nossa solução no
Ostrovok.ru . Que tópico abordaremos hoje?
Cada serviço deve funcionar em algum servidor, comunicando-se com o hardware através das ferramentas do sistema operacional. Existem muitas dessas ferramentas, bem como configurações para elas. Na maioria dos casos, as configurações padrão serão mais que suficientes. Neste artigo, eu gostaria de falar sobre os casos em que as configurações padrão ainda não eram suficientes e eu precisava conhecer o sistema operacional um pouco mais - no nosso caso com o
Linux .

Usamos kernels sabiamente
Em um
artigo anterior, falei sobre a
opção cpu-map no
Haproxy . Com ele, vinculamos os processos do Haproxy a threads de um núcleo em um servidor com processador duplo. Demos o segundo núcleo ao tratamento de interrupção da placa de rede.
Abaixo está uma tela onde você pode ver uma separação semelhante. À esquerda, os kernels são ocupados pelo Haproxy no
user space
e à direita, processando interrupções no
kernel space
.

A interrupção da ligação a uma placa de rede é feita automaticamente usando este
Existem muitos scripts simples e mais complexos adequados na Internet que fazem o mesmo trabalho, mas esse script é suficiente para nossas necessidades.
No Haproxy, vinculamos processos aos kernels, começando com o primeiro kernel. O mesmo script vincula interrupções, começando com o último. Assim, podemos dividir os processadores do servidor em dois campos.
Para uma visão mais profunda das interrupções e da rede, recomendo a leitura deste
artigo .
Revelamos os recursos dos dispositivos de rede
Acontece que muitos quadros podem voar pela rede em um momento e a fila de cartões pode não estar pronta para esse fluxo de convidados, mesmo que tenha a oportunidade de fazê-lo.
Vamos falar sobre o buffer da placa de rede. Na maioria das vezes, os valores padrão não usam todo o buffer disponível. Você pode visualizar as configurações atuais usando o poderoso utilitário ethtool.
Exemplo de uso de comando:
> ethtool -g eno1 Ring parameters for eno1: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 256 RX Mini: 0 RX Jumbo: 0 TX: 256
Agora vamos tirar tudo da vida:
> ethtool -G eno1 rx 4096 tx 4096 > ethtool -g eno1 Ring parameters for eno1: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096
Agora você pode ter certeza de que o cartão não está restrito e funciona no máximo de seus recursos.
Configurações mínimas de sysctl para benefício máximo
O Sysctl tem uma grande variedade de opções em todas as cores e tamanhos que você pode imaginar. E, como regra, os artigos na Internet, abordando a questão da otimização, cobrem uma parte bastante impressionante desses parâmetros. Vou considerar apenas aqueles que foram realmente úteis para mudar no nosso caso.
net.core.netdev_max_backlog - a fila onde os quadros da placa de rede ficam, que são processados pelo kernel. Com interfaces rápidas e grandes quantidades de tráfego, ele pode ser preenchido rapidamente.
Padrão : 1000.
Podemos observar o excesso dessa fila observando a segunda coluna no arquivo / proc / net / softnet_stat.
awk '{print $2}' /proc/net/softnet_stat
O próprio arquivo descreve a estrutura de
netif_rx_stats por linha para cada CPU no sistema.
Especificamente, a segunda coluna descreve o número de pacotes no estado descartado. Se o valor na segunda coluna aumentar com o tempo, provavelmente vale a pena aumentar o valor de
net.core.netdev_max_backlog
ou acelerar a CPU.
net.core.rmem_default /
net.core.rmem_max &&
net.core.wmem_default /
net.core.wmem_max - esses parâmetros indicam o valor padrão / valor máximo para buffers de leitura e gravação de soquete.
O valor
padrão pode ser alterado no nível do aplicativo no momento em que o soquete é criado (a propósito, o Haproxy possui um
parâmetro que faz isso). Tivemos casos em que o kernel lançou mais pacotes do que o Haproxy conseguiu varrer e os problemas começaram. Portanto, a coisa é importante.
net.ipv4.tcp_max_syn_backlog - é responsável pelo limite de novas conexões ainda não estabelecidas para as quais um pacote
SYN
foi recebido. Se houver um grande fluxo de novas conexões (por exemplo, muitas solicitações HTTP do
Connection: close
), faz sentido aumentar esse valor para não perder tempo enviando pacotes encaminhados.
net.core.somaxconn - aqui estamos falando de conexões estabelecidas, mas ainda não processadas pelo aplicativo. Se o servidor for de thread único e houver duas solicitações, a primeira solicitação será processada pela função
accept()
e a segunda ficará pendurada na lista de
backlog
, cujo tamanho é responsável por esse parâmetro.
nf_conntrack_max é provavelmente o mais famoso de todos os parâmetros. Acho que quase todo mundo que lidou com o iptables sabe disso. Idealmente, é claro, se você não precisar usar o iptables mascarado, poderá descarregar o módulo conntrack e não pensar nisso. No meu caso, o
Docker é usado, então você não carrega nada de especial.
Monitoramento Óbvio e não muito
Para não procurar cegamente por que “seu proxy está diminuindo”, será útil configurar alguns gráficos e colocá-los em gatilhos.
nf_conntrack_count é a métrica mais óbvia. Nele, você pode monitorar quantas conexões estão agora na
tabela conntrack . Quando a tabela estourar, o caminho para novas conexões será fechado.
O valor atual pode ser encontrado aqui:
cat /proc/sys/net/netfilter/nf_conntrack_count
Segmentos Tcp retransmitidos - o número de transferências de segmentos. A métrica é muito volumosa, pois pode falar sobre problemas em diferentes níveis. O aumento nas transferências pode indicar problemas de rede, a necessidade de otimizar as configurações do sistema ou até mesmo que o software final (por exemplo, Haproxy) não esteja funcionando. Seja como for, o crescimento anormal desse valor pode servir como motivo para o processo.

Em nosso país, um aumento de valores geralmente indica problemas com um dos fornecedores, embora tenha havido problemas com o desempenho dos servidores e da rede.
Exemplo para verificação:
netstat -s|grep 'segments retransmited'
Soquete Recv-Q - lembre-se, falamos sobre momentos em que um aplicativo pode não ter tempo suficiente para processar solicitações e, em seguida, o
socket backlog
do
socket backlog
? O crescimento desse indicador deixa claro que algo está errado com o aplicativo e ele não pode lidar.
Vi montanhas em gráficos com essa métrica, quando o parâmetro maxconn no Haproxy tinha um valor padrão (2000) e simplesmente não aceitava novas conexões.
E novamente um exemplo:
ss -lntp|awk '/LISTEN/ {print $2}'

Não será supérfluo ter um gráfico com uma discriminação por estado das conexões TCP:

E, separadamente, processa o
time-wait/established
, porque seus valores, em regra, são muito diferentes dos demais:

Além dessas métricas, existem muitas outras, mas mais óbvias - por exemplo, a carga na interface de rede ou na CPU. A escolha deles já dependerá mais das especificidades da sua carga de trabalho.
Em vez de uma conclusão
Em geral, é tudo - tentei descrever os principais pontos que tive que enfrentar ao configurar o proxy reverso http. Parece que a tarefa não é difícil, mas com um aumento na carga, o número de armadilhas que sempre aparecem na hora errada também aumenta. Espero que este artigo ajude você a evitar as dificuldades que tive que enfrentar.
Toda a paz