A história da exclusão física de 300 milhões de registros no MySQL

Introdução

Olá. Sou ningenMe, desenvolvedor web.

Como o título diz, minha história é a história da exclusão física de 300 milhões de registros no MySQL.

Fiquei interessado nisso, então resolvi fazer um lembrete (instruções).

Início - Alerta

O servidor em lote que uso e mantenho possui um processo regular que coleta os dados do último mês do MySQL uma vez por dia.

Normalmente esse processo é concluído em cerca de 1 hora, mas desta vez só foi concluído em 7 ou 8 horas e o alerta não parou de aparecer...

Procurando por um motivo

Tentei reiniciar o processo e olhar os logs, mas não vi nada de errado.
A consulta foi indexada corretamente. Mas quando pensei no que estava errado, percebi que o tamanho do banco de dados é muito grande.

hoge_table | 350'000'000 |

350 milhões de registros. A indexação parecia estar funcionando corretamente, apenas muito lenta.

A coleta de dados necessária por mês foi de aproximadamente 12 milhões de registros. Parece que o comando select demorou muito e a transação não foi executada por muito tempo.

DB

É essencialmente uma tabela que cresce cerca de 400 entradas todos os dias. O banco de dados deveria coletar dados apenas do último mês, portanto, esperava-se que suportasse exatamente essa quantidade de dados, mas, infelizmente, a operação de rotação não foi incluída.

Este banco de dados não foi desenvolvido por mim. Eu assumi de outro desenvolvedor, então ainda parecia uma dívida técnica.

Chegou um ponto em que o volume de dados inseridos diariamente tornou-se grande e finalmente atingiu o seu limite. Supõe-se que ao trabalhar com uma quantidade tão grande de dados seria necessário separá-los, mas isso, infelizmente, não foi feito.

E então entrei em ação.

Correção

Era mais racional reduzir o tamanho do próprio banco de dados e reduzir o tempo de processamento do que alterar a própria lógica.

A situação deveria mudar significativamente se você apagar 300 milhões de registros, então decidi fazer isso... Eh, pensei que isso definitivamente funcionaria.

Ação 1

Depois de preparar um backup confiável, finalmente comecei a enviar solicitações.

「Enviando uma solicitação」

DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';

"..."

"..."

“Hmm... Sem resposta. Talvez o processo demore muito? — Pensei, mas por precaução, olhei para o grafana e vi que a carga do disco estava crescendo muito rapidamente.
“Perigoso”, pensei novamente e imediatamente interrompi o pedido.

Ação 2

Depois de analisar tudo, percebi que o volume de dados era muito grande para apagar tudo de uma vez.

Decidi escrever um script que pudesse excluir cerca de 1 de registros e executei-o.

「Eu implemento o script」

“Agora isso definitivamente vai funcionar”, pensei.

Ação 3

O segundo método funcionou, mas acabou sendo muito trabalhoso.
Fazer tudo com cuidado, sem nervosismos desnecessários, levaria cerca de duas semanas. Mas ainda assim, este cenário não atendia aos requisitos de serviço, então tivemos que nos afastar dele.

Então aqui está o que decidi fazer:

Copie a tabela e renomeie-a

Na etapa anterior, percebi que excluir uma quantidade tão grande de dados cria uma carga igualmente grande. Então decidi criar uma nova tabela do zero usando insert e mover para ela os dados que iria deletar.

| hoge_table     | 350'000'000|
| tmp_hoge_table |  50'000'000|

Se você fizer a nova tabela do mesmo tamanho acima, a velocidade de processamento de dados também deverá se tornar 1/7 mais rápida.

Depois de criar a tabela e renomeá-la, comecei a usá-la como tabela mestre. Agora, se eu eliminar a tabela com 300 milhões de registros, tudo ficará bem.
Descobri que truncar ou eliminar cria menos sobrecarga do que excluir e decidi usar esse método.

Atuação

「Enviando uma solicitação」

INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';

"..."
"..."
"Em...?"

Ação 4

Achei que a ideia anterior funcionaria, mas após enviar a solicitação de inserção apareceram vários erros. MySQL não perdoa.

Eu já estava tão cansado que comecei a pensar que não queria mais fazer isso.

Sentei-me e pensei e percebi que talvez houvesse muitas consultas de inserção de uma só vez...
Tentei enviar uma solicitação de inserção da quantidade de dados que o banco de dados deve processar em 1 dia. Ocorrido!

Bem, depois disso continuamos enviando solicitações para a mesma quantidade de dados. Como precisamos remover dados de um mês, repetimos essa operação aproximadamente 35 vezes.

Renomeando uma tabela

Aqui a sorte esteve do meu lado: tudo correu bem.

Alerta desaparecido

A velocidade de processamento em lote aumentou.

Anteriormente esse processo demorava cerca de uma hora, agora leva cerca de 2 minutos.

Depois de ter certeza de que todos os problemas foram resolvidos, descartei 300 milhões de registros. Apaguei a mesa e me senti renascer.

Resumo

Percebi que faltava processamento de rotação no processamento em lote e esse era o principal problema. Esse tipo de erro arquitetônico resulta em perda de tempo.

Você pensa na carga durante a replicação de dados ao excluir registros do banco de dados? Não vamos sobrecarregar o MySQL.

Aqueles que são bem versados ​​em bancos de dados definitivamente não encontrarão tal problema. Para o resto de vocês, espero que este artigo tenha sido útil.

Obrigado por ler!

Ficaremos muito felizes se você nos contar se gostou deste artigo, se a tradução está clara, se foi útil para você?

Fonte: habr.com

Adicionar um comentário