Gostaríamos de armazenar milhões de arquivos de texto em um sistema de arquivos Linux, com o objetivo de poder compactar e servir uma coleção arbitrária como um serviço. Tentamos outras soluções, como um banco de dados de chave / valor, mas nossos requisitos de simultaneidade e paralelismo tornam a melhor escolha usar o sistema de arquivos nativo.
A maneira mais direta é armazenar todos os arquivos em uma pasta:
$ ls text_files/
1.txt
2.txt
3.txt
o que deve ser possível em um sistema de arquivos EXT4 , que não tem limite para o número de arquivos em uma pasta.
Os dois processos de FS serão:
- Escreva um arquivo de texto a partir do scrape da web (não deve ser afetado pelo número de arquivos na pasta).
- Zip arquivos selecionados, fornecidos pela lista de nomes de arquivos.
Minha pergunta é: o armazenamento de até dez milhões de arquivos em uma pasta afetará o desempenho das operações acima, ou o desempenho geral do sistema, de maneira diferente da criação de uma árvore de subpastas para os arquivos residirem?
fonte
dir_index
, que geralmente é ativado por padrão, agiliza as pesquisas, mas pode limitar o número de arquivos por diretório.ls -l
ou qualquer outra coisa que sejastat
cada inode no diretório (por exemplo,bash
globbing / tab tab) será artificialmente mais rápido do que depois de algum desgaste (apague alguns arquivos, escreva alguns novos). O ext4 pode se sair melhor com isso do que o XFS, porque o XFS aloca espaço dinamicamente para inodes x dados, para que você possa acabar com inodes mais dispersos, eu acho. (Mas esse é um palpite puro baseado em muito pouco conhecimento detalhado; eu mal usei o ext4). Vá comabc/def/
subdiretórios.ZipOutputStream
rapidamente, superaria praticamente qualquer sistema de arquivos nativo gratuito do Linux - duvido que você queira pagar pelo GPFS da IBM. O loop para processar um conjunto de resultados JDBC e criar esse fluxo zip é provavelmente apenas de 6 a 8 linhas de código Java.Respostas:
O
ls
comando, ou mesmo a conclusão do TAB ou a expansão do curinga pelo shell, normalmente apresentam seus resultados em ordem alfanumérica. Isso requer a leitura de toda a lista de diretórios e a classificação. Com dez milhões de arquivos em um único diretório, essa operação de classificação levará um tempo não negligenciável.Se você puder resistir ao desejo de concluir a TAB e, por exemplo, escrever os nomes dos arquivos a serem compactados na íntegra, não deverá haver problemas.
Outro problema com os curingas pode ser a expansão de curingas, possivelmente produzindo mais nomes de arquivos do que cabem em uma linha de comando de tamanho máximo. O tamanho máximo típico da linha de comando será mais que adequado para a maioria das situações, mas quando falamos de milhões de arquivos em um único diretório, isso não é mais uma suposição segura. Quando um comprimento máximo da linha de comando é excedido na expansão de curinga, a maioria dos shells simplesmente falha na linha de comando inteira sem executá-la.
Isso pode ser resolvido executando suas operações curinga usando o
find
comando:ou uma sintaxe semelhante sempre que possível. Ele
find ... -exec ... \+
levará em conta automaticamente o comprimento máximo da linha de comando e executará o comando quantas vezes forem necessárias, ajustando a quantidade máxima de nomes de arquivos para cada linha de comando.fonte
ls
comando não souberem que a lista de diretórios já está classificada, eles levarão algum tempo para executar o algoritmo de classificação de qualquer maneira. Além disso, o espaço do usuário pode estar usando uma ordem de classificação localizada (LC_COLLATE) que pode ser diferente do que o sistema de arquivos pode fazer internamente.Isso é perigosamente próximo a uma pergunta / resposta baseada em opinião, mas tentarei fornecer alguns fatos com minhas opiniões.
mv * /somewhere/else
) poderá falhar em expandir o curinga com êxito ou o resultado poderá ser muito grande para ser usado.ls
levará mais tempo para enumerar um número muito grande de arquivos do que um pequeno número de arquivos.Uma recomendação é dividir o nome do arquivo em dois, três ou quatro caracteres e usá-los como subdiretórios. Por exemplo,
somefilename.txt
pode ser armazenado comosom/efi/somefilename.txt
. Se você estiver usando nomes numéricos, divida da direita para a esquerda em vez de da esquerda para a direita, para que haja uma distribuição mais uniforme. Por exemplo,12345.txt
pode ser armazenado como345/12/12345.txt
.Você pode usar o equivalente a
zip -j zipfile.zip path1/file1 path2/file2 ...
para evitar incluir os caminhos do subdiretório intermediário no arquivo ZIP.Se você estiver entregando esses arquivos de um servidor da Web (não tenho certeza se isso é relevante), é trivial ocultar essa estrutura em favor de um diretório virtual com regras de reescrita no Apache2. Eu diria que o mesmo vale para o Nginx.
fonte
*
expansão será bem-sucedida, a menos que você fique sem memória, mas, a menos que você aumente o limite do tamanho da pilha (no Linux) ou use um shellmv
embutido ou embutido (ksh93, zsh), aexecve()
chamada do sistema poderá falhar com um erro E2BIG.zip -j - ...
e canalizar o fluxo de saída diretamente para a conexão de rede do clientezip -j zipfile.zip ...
. Gravar um arquivo zip no disco significa que o caminho dos dados é lido em disco-> compactar-> gravar em disco-> ler em disco-> enviar para o cliente. Isso pode triplicar os requisitos de E / S do disco sobre a leitura de disco-> compactar-> enviar para o cliente.Eu administro um site que lida com um banco de dados para filmes, TV e videogames. Para cada uma delas, há várias imagens na TV contendo dezenas de imagens por programa (por exemplo, instantâneos de episódios etc.).
Acaba havendo muitos arquivos de imagem. Em algum lugar na faixa de mais de 250.000. Tudo isso é armazenado em um dispositivo de armazenamento em bloco montado, onde o tempo de acesso é razoável.
Minha primeira tentativa de armazenar as imagens foi em uma única pasta, como
/mnt/images/UUID.jpg
Encontrei os seguintes desafios.
ls
através de um terminal remoto seria apenas travar. O processo seria zumbi eCTRL+C
não o quebraria.ls
comando preencheria rapidamente o buffer de saída eCTRL+C
não pararia a rolagem sem fim.Acabei tendo que armazenar os arquivos em subpastas usando o tempo de criação para criar o caminho. Tais como
/mnt/images/YYYY/MM/DD/UUID.jpg
. Isso resolveu todos os problemas acima e me permitiu criar arquivos zip direcionados a uma data.Se o único identificador para um arquivo que você possui é um número numérico, e esses números tendem a ser executados em sequência. Por que não agrupá-los por
100000
,10000
e1000
.Por exemplo, se você tiver um arquivo chamado,
384295.txt
o caminho seria:Se você souber, alcançará alguns milhões. Use
0
prefixos para 1.000.000fonte
Para criar um novo arquivo, é necessário varrer o arquivo do diretório procurando espaço vazio suficiente para a nova entrada do diretório. Se não houver um espaço grande o suficiente para armazenar a nova entrada de diretório, ela será colocada no final do arquivo de diretório. À medida que o número de arquivos em um diretório aumenta, o tempo para varrer o diretório também aumenta.
Enquanto os arquivos de diretório permanecerem no cache do sistema, o desempenho atingido não será ruim, mas se os dados forem liberados, a leitura do arquivo de diretório (geralmente altamente fragmentado) do disco poderá consumir um pouco de tempo. Um SSD melhora isso, mas para um diretório com milhões de arquivos, ainda pode haver um impacto perceptível no desempenho.
Também é provável que exija tempo adicional em um diretório com milhões de arquivos. Em um sistema de arquivos com entradas de diretório com hash (como EXT4), essa diferença é mínima.
Uma árvore de subpastas não possui nenhuma das desvantagens de desempenho acima. Além disso, se o sistema de arquivos subjacente for alterado para não ter nomes de arquivos com hash, a metodologia da árvore ainda funcionará bem.
fonte
Primeiramente: impeça 'ls' de classificar com 'ls -U', talvez atualize seu ~ / bashrc para ter 'alias ls = "ls -U"' ou similar.
Para seu conjunto de arquivos grande, você pode tentar isso da seguinte maneira:
crie um conjunto de arquivos de teste
veja se muitos nomes de arquivos causam problemas
use o comportamento xargs parmeter-batching e zip (default) de adicionar arquivos a um zip para evitar problemas.
Isso funcionou bem:
fonte