Eu escrevi um programa com bugs que criou acidentalmente cerca de 30 milhões de arquivos em /tmp. (O bug foi introduzido há algumas semanas e estava criando alguns subdiretórios por segundo.) Eu poderia renomear /tmp para /tmp2 e agora preciso excluir os arquivos. O sistema é FreeBSD 10, o sistema de arquivos raiz é zfs.
Enquanto isso, uma das unidades no espelho deu errado e eu a substituí. A unidade possui dois discos SSD de 120 GB.
Aqui está a questão: substituir o disco rígido e restaurar todo o array levou menos de uma hora. Excluir arquivos /tmp2 é outra história. Escrevi outro programa para remover os arquivos e ele pode excluir apenas 30 a 70 subdiretórios por segundo. Levará de 2 a 4 dias para excluir todos os arquivos.
Como é possível que a restauração de toda a matriz leve uma hora, mas a exclusão do disco leve 4 dias? Por que tenho um desempenho tão ruim? 70 deleções/segundo parece um desempenho muito, muito ruim.
Eu poderia excluir o inode para /tmp2 manualmente, mas isso não liberaria espaço, certo?
Isso pode ser um problema com o zfs, ou com os discos rígidos ou o quê?
As exclusões no ZFS são caras. Ainda mais se você tiver a desduplicação habilitada no sistema de arquivos (já que desreferenciar arquivos desduplicados é caro). Os instantâneos também podem complicar as coisas.
Talvez seja melhor excluir o
/tmp
diretório em vez dos dados contidos nele.Se
/tmp
for um sistema de arquivos ZFS, exclua-o e crie novamente.Considere um edifício de escritórios.
A remoção de todos os computadores, móveis e acessórios de todos os escritórios em todos os andares leva muito tempo, mas deixa os escritórios imediatamente utilizáveis por outro cliente.
Demolir todo o prédio com RDX é muito mais rápido, mas é bem provável que o próximo cliente reclame sobre como o local é frio.
Há uma série de coisas acontecendo aqui.
Primeiro, todas as tecnologias de disco modernas são otimizadas para transferências em massa. Se você precisar mover 100 MB de dados, eles farão isso muito mais rápido se estiverem em um bloco contíguo em vez de espalhados por todo o lugar. Os SSDs ajudam muito aqui, mas até eles preferem dados em blocos contíguos.
Em segundo lugar, o resilvering é bastante ideal no que diz respeito às operações de disco. Você lê um grande pedaço contíguo de dados de um disco, faz algumas operações rápidas de CPU nele e depois o reescreve em outro grande pedaço contíguo para outro disco. Se a energia falhar no meio do caminho, não é grande coisa - você simplesmente ignorará todos os dados com somas de verificação incorretas e continuará normalmente.
Em terceiro lugar, excluir um arquivo é muito lento . O ZFS é particularmente ruim, mas praticamente todos os sistemas de arquivos são lentos para excluir. Eles devem modificar um grande número de blocos de dados diferentes no disco e cronometrar corretamente (ou seja, aguardar) para que o sistema de arquivos não seja danificado se houver falha de energia.
O resilvering é algo em que os discos são realmente rápidos e a exclusão é algo em que os discos são lentos. Por megabyte de disco, você só precisa fazer um pouco de resilvering. Você pode ter mil arquivos nesse espaço que precisam ser excluídos.
Depende. Eu não ficaria surpreso com isso. Você não mencionou que tipo de SSD está usando. Os SSDs Intel e Samsung modernos são muito bons nesse tipo de operação (leitura-modificação-gravação) e terão um desempenho melhor. SSDs mais baratos/antigos (por exemplo, Corsair) serão lentos. O número de operações de E/S por segundo (IOPS) é o fator determinante aqui.
O ZFS é particularmente lento para excluir coisas. Normalmente, ele executará exclusões em segundo plano para que você não veja o atraso. Se você estiver fazendo um grande número deles, ele não poderá escondê-lo e deve atrasá-lo.
Apêndice: por que as exclusões são lentas?
Ian Howson dá uma boa resposta sobre por que é lento.
Se você excluir arquivos em paralelo, poderá ver um aumento na velocidade, pois a exclusão pode usar os mesmos blocos e, portanto, pode economizar reescrevendo o mesmo bloco várias vezes.
Então tente:
e veja se isso funciona melhor do que suas 70 exclusões por segundo.
Isso é possível porque as duas operações funcionam em camadas diferentes da pilha do sistema de arquivos. O resilvering pode ser executado em baixo nível e, na verdade, não precisa examinar arquivos individuais, copiando grandes blocos de dados por vez.
Tem que fazer muita contabilidade...
Não sei para o ZFS, mas se ele pudesse se recuperar automaticamente disso, provavelmente, no final, faria as mesmas operações que você já está fazendo, em segundo plano.
diz
zfs scrub
alguma coisa?Excluir muitos arquivos nunca é realmente uma operação rápida.
Para excluir um arquivo em qualquer sistema de arquivos, você precisa ler o índice do arquivo, remover (ou marcar como excluído) a entrada do arquivo no índice, remover quaisquer outros metadados associados ao arquivo e marcar o espaço alocado para o arquivo como não utilizado. Isso deve ser feito individualmente para cada arquivo a ser excluído, o que significa que a exclusão de muitos arquivos requer muitos pequenos I/Os. Fazer isso de maneira a garantir a integridade dos dados em caso de falha de energia aumenta ainda mais a sobrecarga.
Mesmo sem as peculiaridades introduzidas pelo ZFS, a exclusão de 30 milhões de arquivos geralmente significa mais de cem milhões de operações de E/S separadas. Isso levará muito tempo, mesmo com um SSD rápido. Como outros já mencionaram, o design do ZFS agrava ainda mais esse problema.
Muito simples se você inverter seu pensamento.
Obtenha uma segunda unidade (parece que você já tem isso)
Copie tudo da unidade A para a unidade B com rsync, excluindo o diretório /tmp. Rsync será mais lento que uma cópia em bloco.
Reinicie, usando a unidade B como o novo volume de inicialização
Reformate a unidade A.
Isso também desfragmentará sua unidade e fornecerá um novo diretório (tudo bem, desfragmentar não é tão importante com um SSD, mas linearizar seus arquivos nunca prejudica nada)
Você tem 30 milhões de entradas em uma lista não classificada. Você examina a lista em busca da entrada que deseja remover e a remove. Agora você tem apenas 29.999.999 entradas em sua lista não classificada. Se eles estão todos em /tmp, por que não reiniciar?
Editado para refletir as informações nos comentários: Declaração do problema: Remover a maioria, mas não todos , dos mais de 30 milhões de arquivos criados incorretamente em /tmp está demorando muito.
Problema 1) Melhor maneira de remover um grande número de arquivos indesejados de /tmp.
Problema 2) Entendendo por que é tão lento excluir arquivos.
Solução 1) - /tmp é redefinido para vazio na inicialização pela maioria das distribuições * nix. O FreeBSD, no entanto, não é um deles.
Etapa 1 - copie arquivos interessantes em outro lugar.
Passo 2 - Como root
Passo 3 - reinicie.
Etapa 4 - altere clear_tmp_enable de volta para "Não".
Os arquivos indesejados desapareceram, pois o ZFS no FreeBSD tem o recurso de que "Destruir um conjunto de dados é muito mais rápido do que excluir todos os arquivos que residem no conjunto de dados, pois não envolve a verificação de todos os arquivos e a atualização de todos os metadados correspondentes. " portanto, tudo o que ele precisa fazer no momento da inicialização é redefinir os metadados para o conjunto de dados /tmp. Isso é muito rápido.
Solução 2) Por que é tão lento? O ZFS é um sistema de arquivos maravilhoso que inclui recursos como acesso constante ao diretório. Isso funciona bem se você souber o que está fazendo, mas as evidências sugerem que o OP não é um especialista em ZFS. O OP não indicou como eles estavam tentando remover os arquivos, mas suponho que eles usaram uma variação de "find regex -exec rm {} \;". Isso funciona bem com números pequenos, mas não escala porque há três operações seriais acontecendo 1) obtém a lista de arquivos disponíveis (retorna 30 milhões de arquivos em ordem de hash), 2) usa regex para escolher o próximo arquivo a ser excluído, 3 ) diga ao sistema operacional para localizar e remover esse arquivo de uma lista de 30 milhões. Mesmo que o ZFS retorne uma lista da memória e se'encontrar' o armazena em cache, o regex ainda precisa identificar o próximo arquivo a ser processado da lista e, em seguida, instruir o sistema operacional a atualizar seus metadados para refletir essa alteração e, em seguida, atualizar a lista para que não seja processada novamente.