Um estudo de caso de interrupção de conexão MySQL causada por sobrecarga de cache TCP

Como analisar a possibilidade de direcionar outros fatores além do próprio MySQL?

Autor: Gong Tangjie, membro da equipe ACOS DBA, é o principal responsável pelo suporte técnico do MySQL e é bom em MySQL, PG e bancos de dados domésticos.

Produzido pela comunidade de código aberto Aikeson, o conteúdo original não pode ser utilizado sem autorização. Entre em contato com o editor e indique a fonte para reimpressão.

Este artigo tem cerca de 1.200 palavras e deve levar 3 minutos para ser lido.

fundo

Durante a execução de tarefas em lote, o aplicativo encontrou um problema: a conexão com o banco de dados para algumas tarefas era perdida repentinamente, resultando na impossibilidade de conclusão da tarefa. No log de erros do banco de dados foram encontradas informações de conexão abortada , o que indica que a comunicação entre o cliente e o servidor foi interrompida de forma anormal.

analisar

Para descobrir a causa do problema, primeiro analisamos várias situações comuns que podem fazer com que a conexão seja abortada com base na experiência:

  1. O cliente não fechou a conexão corretamente e não chamou mysql_close()a função.
  2. Se o tempo ocioso do cliente exceder wait_timeoutos interactive_timeoutsegundos do parâmetro ou, o servidor será desconectado automaticamente.
  3. O tamanho do pacote enviado ou recebido pelo cliente ultrapassa max_allowed_packeto valor do parâmetro, causando a interrupção da conexão.
  4. O cliente tentou acessar o banco de dados, mas não tinha permissão, ou foi utilizada uma senha errada, ou o pacote de conexão não continha as informações corretas.

Contudo, após investigação, constatou-se que nenhuma das situações acima se aplica ao problema atual. Como as tarefas estavam rodando normalmente antes e o programa não mudou, a primeira situação pode ser descartada. Verifiquei os parâmetros de tempo limite do MySQL wait_timeoute interactive_timeoutdescobri que ambos são 28800, ou seja, 8 horas, excedendo em muito o tempo de execução da tarefa, então a segunda situação pode ser descartada. Também verifiquei max_allowed_packetos parâmetros do cliente e do servidor e descobri que ambos são 64M e dificilmente ultrapassarão esse limite, portanto a terceira situação pode ser descartada. Confirmamos também que os direitos de acesso ao banco de dados do cliente, senha, pacote de conexão e demais informações estão corretos, portanto a quarta situação pode ser descartada.

Neste ponto, inicialmente sentimos que não deveria haver nenhum problema no nível do MySQL, e o problema pode estar em outro lugar.

Para localizar melhor o problema, tentamos modificar alguns parâmetros relevantes do kernel do servidor, como segue:

net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_time = 120
net.core.rmem_default = 2097152
net.core.wmem_default = 2097152
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_syn_backlog = 16384

Esses parâmetros servem principalmente para otimizar o desempenho e a estabilidade da conexão de rede e evitar que a conexão seja fechada inesperadamente ou expire. No entanto, os resultados modificados não melhoraram e a conexão ainda será interrompida de forma anormal.

Por fim, tentamos a análise de captura de pacotes. Utilizando a ferramenta Wireshark , descobrimos um fenômeno anormal: o servidor enviava um grande número de pacotes ACK ao cliente. Como mostrado abaixo:

Esses pacotes ACK são pacotes de confirmação no protocolo TCP, indicando que o servidor recebeu o pacote de dados do cliente e solicita que o cliente continue enviando dados. Mas por que o servidor envia tantos pacotes ACK? Especulamos que pode haver uma anormalidade na rede, fazendo com que o cliente não receba o pacote ACK retornado pelo servidor, de modo que o servidor enviará pacotes ACK repetidamente até atingir o tempo limite ou receber uma resposta do cliente. No entanto, após investigação do pessoal da rede, nenhum problema óbvio foi encontrado.

Continuando a analisar a captura de pacotes, descobrimos outro fenômeno anormal: o cliente dará alguns avisos de janela ao servidor remetente. Como mostrado abaixo:

Esses avisos de janela são um mecanismo de controle de fluxo no protocolo TCP, indicando que a janela de recebimento do servidor ou cliente está cheia e não pode receber mais dados.

[TCP Window Full] é um aviso de janela enviado pelo remetente ao destinatário, indicando que o limite do receptor de dados foi atingido.

[TCP ZeroWindow] é um aviso de janela enviado pelo terminal receptor ao terminal emissor, informando ao remetente que a janela de recebimento do terminal receptor está cheia e interrompe temporariamente o envio.

Com base nas informações acima, especulamos que a causa do problema é: como os dados que o MySQL precisa enviar são muito grandes, o cache TCP do cliente está cheio, então ele precisa esperar que o cliente digira os dados no TCP cache antes que ele possa continuar a receber dados. Porém, durante este período, o MySQL continuará solicitando ao cliente que continue enviando dados. Se o cliente não responder dentro de um determinado período de tempo (o padrão é 60 segundos), o MySQL considerará que o envio de dados expirou e interromperá a conexão.

Para verificar a especulação, verifiquei o log lento do MySQL e encontrei muitos registros Last_errno: 1161 .

Esses registros indicam que o MySQL encontrou um erro de tempo limite ao enviar dados, e o número de ocorrências é muito próximo do número de tarefas com falha do aplicativo. De acordo com o site oficial do MySQL, o significado deste erro é:

Número do erro: 1161; Símbolo: ER_NET_WRITE_INTERRUPTED; ESTADOSQL: 08S01

Mensagem: Tempo limite para gravação de pacotes de comunicação

Pode-se observar que isso significa que a gravação na rede é interrompida e existe um parâmetro no nível do MySQL para controlar isso, então tente alterar o parâmetro net_write_timeout para 600 e a tarefa em lote será executada normalmente.

Portanto, a razão pela qual a conexão MySQL é interrompida de forma anormal é que o banco de dados obtido pelo cliente é muito grande e excede o cache TCP do cliente. O cliente precisa processar os dados no cache primeiro. Durante esse período, o MySQL continuará a solicitar. o cliente continuasse enviando dados, mas o cliente não respondeu em 60 segundos, fazendo com que o MySQL expirasse o envio de dados e interrompesse a conexão.

para concluir

Através das análises e tentativas acima, chegamos às seguintes conclusões:

  • Nas informações de captura de pacotes, há muitas informações ACK porque o cache do cliente está cheio e não pode retornar ao servidor a tempo, então o servidor enviará repetidamente informações ACK por mais de 60 segundos ( net_write_timeouto valor padrão é 60), causando MySQL para interromper a conexão.
  • No log lento, existem muitos registros Last_errno: 1161 porque o SQL foi realmente executado no MySQL, mas ao enviar dados para o cliente, a quantidade de dados excede o cache TCP do cliente, e então o cliente O aplicativo não processou o dados no cache em 60 segundos, fazendo com que o MySQL atinja o tempo limite ao enviar dados ao cliente.
  • Ajustar net_write_timeoutos parâmetros no nível do MySQL só pode aliviar esse fenômeno. A causa raiz é que a quantidade de dados obtidos por um único SQL é muito grande e excede o tamanho do cache do cliente. o que faz com que o envio de dados subsequente expire.

Sugestões de otimização

  • Os dados são processados ​​em lotes no nível de negócios para evitar que uma única consulta SQL obtenha uma grande quantidade de dados do servidor, resultando em cache TCP insuficiente no lado do cliente.
  • Aumentar os parâmetros no MySQL net_write_timeoutou aumentar o cache TCP do cliente pode aliviar esta situação, mas não pode resolver completamente o problema porque muitos dados ainda afetarão o desempenho e a estabilidade.
  • Otimize instruções SQL para reduzir retornos de dados desnecessários, como usar LIMIT, WHERE e outras condições, ou usar funções agregadas, funções de agrupamento, etc., para reduzir a quantidade de dados e melhorar a eficiência da consulta.

Para mais artigos técnicos, visite: https://opensource.actionsky.com/

Sobre SQLE

SQLE é uma plataforma abrangente de gerenciamento de qualidade de SQL que cobre auditoria e gerenciamento de SQL desde o desenvolvimento até ambientes de produção. Ele oferece suporte aos principais bancos de dados de código aberto, comerciais e domésticos, fornece recursos de automação de processos para desenvolvimento, operação e manutenção, melhora a eficiência on-line e melhora a qualidade dos dados.

Obter SQLE

tipo endereço
Repositório https://github.com/actiontech/sqle
documento https://actiontech.github.io/sqle-docs/
lançar notícias https://github.com/actiontech/sqle/releases
Documentação de desenvolvimento de plug-in de auditoria de dados https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
Linus resolveu resolver o problema por conta própria para evitar que os desenvolvedores do kernel substituíssem tabulações por espaços. Seu pai é um dos poucos líderes que sabe escrever código, seu segundo filho é o diretor do departamento de tecnologia de código aberto e seu filho mais novo é um núcleo. contribuidor de código aberto Huawei: Demorou 1 ano para converter 5.000 aplicativos móveis comumente usados ​​A migração abrangente para Hongmeng Java é a linguagem mais propensa a vulnerabilidades de terceiros Wang Chenglu, o pai de Hongmeng: Hongmeng de código aberto é a única inovação arquitetônica. no campo de software básico na China. Ma Huateng e Zhou Hongyi apertam as mãos para "remover rancores". Ex-desenvolvedor da Microsoft: o desempenho do Windows 11 é "ridiculamente ruim" " Embora o que Laoxiangji seja de código aberto não seja o código, as razões por trás disso são muito emocionantes. Meta Llama 3 é lançado oficialmente. Google anuncia uma reestruturação em grande escala.
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/actiontechoss/blog/11054532
Recomendado
Clasificación