Como excluir milhões de arquivos sem perturbar o servidor

11

Gostaria de excluir um diretório de cache nginx, que eu rapidamente removi:

mv cache cache.bak
mkdir cache
service nginx restart

Agora eu tenho uma pasta cache.bak que tem 2 milhões de arquivos. Eu gostaria de apagá-lo, sem perturbar o servidor.

Um simples rm -rf cache.bak trash o servidor, mesmo a mais simples resposta HTTP leva 16 segundos enquanto o rm está rodando, então eu não posso fazer isso.

Eu tentei ionice -c3 rm -rf cache.bak , mas isso não ajudou. O servidor tem um HDD, não um SSD, provavelmente em um SSD, isso pode não ser um problema.

Acredito que a melhor solução seria algum tipo de afogamento, como o modo como o gerenciador de cache interno do nginx faz.

Como você resolveria isso? Existe alguma ferramenta que possa fazer exatamente isso?

ext4 no Ubuntu 16.04

    
por hyperknot 24.12.2016 / 02:41

4 respostas

2

Eu tenho muitas respostas / comentários úteis aqui, que eu gostaria de concluir, assim como mostrar minha solução também.

  1. Sim, a melhor maneira de impedir que isso aconteça é manter o diretório em cache em um sistema de arquivos separado. Nuking / formatação rápida de um sistema de arquivos sempre leva alguns segundos (talvez minutos) no máximo, sem relação com quantos arquivos / pastas estavam presentes nele.

  2. As soluções ionice / nice não fizeram nada, porque o processo de exclusão causou quase nenhuma E / S. O que causou o I / O foi que eu acredito que as filas / buffers no nível do kernel / do sistema de arquivos estavam cheios quando os arquivos eram excluídos muito rapidamente pelo processo de exclusão.

  3. A maneira como resolvi isso é semelhante à solução de Tero Kilkanen, mas não exigi a chamada de um script de shell. Eu usei a opção --bwlimit incorporada do rsync para limitar a velocidade de exclusão.

O comando completo foi:

mkdir empty_dir
rsync -v -a --delete --bwlimit=1 empty_dir/ cache.bak/

Agora o bwlimit especifica a largura de banda em kilobyes, que neste caso se aplica ao nome do arquivo ou caminho dos arquivos. Ao defini-lo para 1 KBps, ele estava excluindo cerca de 100.000 arquivos por hora ou 27 arquivos por segundo. Os arquivos tinham caminhos relativos como cache.bak/e/c1/db98339573acc5c76bdac4a601f9ec1e , que tem 47 caracteres, de modo que daria 1000/47 ~ = 21 arquivos por segundo, de forma semelhante ao meu palpite de 100.000 arquivos por hora.

Agora, por que --bwlimit=1 ? Eu tentei vários valores:

  • 10000, 1000, 100 - > sistema abrandar como antes
  • 10 - > sistema funcionando muito bem por um tempo, mas produz lentidão parcial uma vez por minuto ou mais. Tempos de resposta HTTP ainda < 1 seg.
  • 1 - > nenhuma lentidão no sistema. Eu não tenho pressa e 2 milhões de arquivos podem ser deletados em < 1 dia assim, então eu escolho.

Eu gosto da simplicidade do método embutido do rsync, mas esta solução depende do tamanho do caminho relativo. Não é um grande problema, pois a maioria das pessoas encontraria o valor correto por tentativa e erro.

    
por 30.12.2016 / 01:12
9

Faça um script bash como este:

#!/bin/bash
rm -- "$*"
sleep 0.5

Salve-o com o nome deleter.sh por exemplo. Execute chmod u+x deleter.sh para torná-lo executável.

Esse script exclui todos os arquivos passados para ele como argumentos e, em seguida, dorme 0,5 segundo.

Então, você pode correr

find cache.bak -print0 | xargs -0 -n 5 deleter.sh

Este comando recupera uma lista de todos os arquivos em cache.bak e passa os cinco nomes de arquivos de cada vez para o script de exclusão.

Assim, você pode ajustar quantos arquivos são excluídos por vez e quanto tempo demora um atraso entre cada operação de exclusão.

    
por 24.12.2016 / 03:27
4

Você deve considerar salvar seu cache em um sistema de arquivos separado que possa montar / desmontar como alguém declarou nos comentários. Até que você o faça, você pode usar esse forro /usr/bin/find /path/to/files/ -type f -print0 -exec sleep 0.2 \; -exec echo \; -delete supondo que seu binário de localização esteja localizado em / usr / bin e você deseja ver o progresso na tela. Ajuste o sono de acordo, para não sobrecarregar o HDD.

    
por 24.12.2016 / 15:36
3

Você pode querer tentar ionizar um script consumindo a saída de um comando find. Algo como o seguinte:

ionice -c3 $(
for file in find cache.bak -type f; do
    rm $file
done
for dir in find cache.bak -depthe -type d -empty; do
    rmdir $dir
done
)

Dependendo do sistema de arquivos, cada exclusão de arquivo pode resultar na regravação de todo o diretório. Para diretórios grandes, isso pode ser um grande sucesso. Há atualizações adicionais necessárias para a tabela de inodes e possivelmente uma lista de espaço livre.

Se o sistema de arquivos tiver um diário, as alterações serão gravadas no diário; aplicado; e removido do diário. Isso aumenta os requisitos de E / S para atividades intensivas de gravação.

Você pode querer usar um sistema de arquivos sem um diário para o cache.

Em vez de ionice, você pode usar um comando sleep para classificar as ações. Isso funcionará mesmo se o ionice não funcionar, mas levará muito tempo para excluir todos os seus arquivos.

    
por 24.12.2016 / 03:40