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:
- O cliente não fechou a conexão corretamente e não chamou
mysql_close()
a função. - Se o tempo ocioso do cliente exceder
wait_timeout
osinteractive_timeout
segundos do parâmetro ou, o servidor será desconectado automaticamente. - O tamanho do pacote enviado ou recebido pelo cliente ultrapassa
max_allowed_packet
o valor do parâmetro, causando a interrupção da conexão. - 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_timeout
e interactive_timeout
descobri 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_packet
os 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_timeout
o 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_timeout
os 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_timeout
ou 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 |