Eu tenho um site que armazena imagens de perfil de usuário. Cada imagem é armazenada em um diretório (Linux) específico para o usuário. Atualmente, tenho uma base de clientes de mais de 30, o que significa que terei mais de 30 pastas. Mas minha caixa atual do Linux (ext2 / ext3) não suporta a criação de mais de 32000 diretórios. Como faço para superar isso? Até os caras do YouTube têm o mesmo problema, com miniaturas de vídeo. Mas eles resolveram o problema migrando para o ReiserFS. Não podemos ter uma solução melhor?
Atualização: Quando perguntadas no IRC, as pessoas estavam perguntando sobre a atualização para o ext4, que tem limite de 64k e, é claro, você também pode superar isso . Ou hackear o kernel para alterar o limite.
Atualização: que tal dividir a base de usuários em pastas com base no intervalo da identificação do usuário. Significado 1-1000 em uma pasta, 1000-2000 na outra assim. Isto parece ser simples. O que você diz, pessoal?
Francamente, não há outra maneira?
fonte
Respostas:
Esse limite é por diretório, não para todo o sistema de arquivos; portanto, você pode contornar isso subdividindo ainda mais as coisas. Por exemplo, em vez de ter todos os subdiretórios de usuário no mesmo diretório, divida-os pelos dois primeiros caracteres do nome, para que você tenha algo como:
Melhor ainda seria criar algum tipo de hash dos nomes e usá-lo para a divisão. Dessa forma, você terá uma melhor distribuição entre os diretórios, em vez de, com o exemplo das letras iniciais, "da" estar muito cheio e "zz" completamente vazio. Por exemplo, se você pegar o nome do CRC ou MD5 e usar os primeiros 8 bits, obterá algo como:
Isso pode ser estendido para outras profundidades, conforme necessário, por exemplo, se o nome de usuário não for um valor de hash:
Este método é usado em muitos lugares, como o cache do squid, para copiar o exemplo de Ludwig e os caches locais dos navegadores da web.
Uma coisa importante a ser observada é que, com o ext2 / 3, você começará a encontrar problemas de desempenho antes de chegar perto do limite de 32.000, pois os diretórios são pesquisados linearmente. Mover para outro sistema de arquivos (ext4 ou reiser, por exemplo) removerá essa ineficiência (o reiser pesquisa diretórios com um algoritmo de divisão binária, para que diretórios longos sejam tratados com muito mais eficiência, o que o ext4 pode fazer também), bem como o limite fixo por diretório.
fonte
Se você está vinculado ao ext2 / ext3, a única possibilidade que vejo é particionar seus dados. Encontre um critério que divida seus dados em blocos gerenciáveis de tamanho semelhante.
Se for apenas sobre as imagens de perfil que eu faria:
Por exemplo, o cache SQUID faz desta maneira:
f / 4b / 353ac7303854033
O diretório de nível superior é o primeiro dígito hexadecimal, o segundo nível são os dois dígitos hexadecimais seguintes e o nome do arquivo é o dígito hexadecimal restante.
fonte
Você tem uma solução melhor - use um sistema de arquivos diferente, há muitos disponíveis, muitos dos quais são otimizados para tarefas diferentes. Como você apontou, o ReiserFS é otimizado para lidar com muitos arquivos em um diretório.
Veja aqui uma comparação dos sistemas de arquivos.
Apenas fique feliz por não estar preso ao NTFS, o que é realmente péssimo para muitos arquivos em um diretório. Eu recomendaria o JFS como um substituto se você não gosta de usar o relativamente novo (mas aparentemente estável) ext4 FS.
fonte
A imagem do perfil é pequena? Que tal colocá-lo no banco de dados com o restante dos dados do perfil? Esta pode não ser a melhor opção para você, mas vale a pena considerar ...
Aqui está um white paper da Microsoft (mais antigo) sobre o tópico: BLOB ou não BLOB .
fonte
Eu cortei uma pequena galeria na web, onde acabei com uma variação desse problema; Eu "apenas" tinha ~ 30.000 imagens no diretório de cache, o que acabou sendo bastante lento (ext2 usa listas vinculadas para índices de diretório, pelo que me lembro).
Acabei fazendo algo nesse sentido:
Isso particionará os dados em 256 diretórios, o que fornece uma rápida pesquisa de diretório para cada um dos três níveis.
fonte
Não é uma resposta imediata para o seu problema, mas algo a se observar para referência futura é o projeto vinculado ao OpenBSD chamado 'Epitome'
Epitome é um mecanismo que fornece serviços de Armazenamento de instância única, Armazenamento endereçável de conteúdo e Desduplicação.
Todos os seus dados são armazenados em um armazenamento de dados como blocos de hash, removendo blocos não exclusivos para reduzir o uso de espaço e permitem que você esqueça basicamente o mecanismo de armazenamento, pois você pode simplesmente solicitar o conteúdo do armazenamento de dados pelo UUID.
O epítome é atualmente experimental, mas algo a ser observado no futuro.
fonte
Geralmente, você deseja evitar diretórios com um grande número de arquivos / diretórios. O principal motivo é que a expansão de curinga na linha de comando resultará em erros "Muitos argumentos", resultando em muita dor ao tentar trabalhar com esses diretórios.
Procure uma solução que crie uma árvore mais profunda, porém mais estreita, por exemplo, criando subpastas como as outras descritas.
fonte
Tivemos um problema semelhante, a solução - como mencionado anteriormente - é criar uma hierarquia de diretórios.
Obviamente, se você tem um aplicativo complexo que depende de uma estrutura de diretórios simples, provavelmente precisará de muitas correções. Portanto, é bom saber que existe uma solução alternativa, use links simbólicos que não tenham o limite de 32k mencionado. Então você tem bastante tempo para consertar o aplicativo ...
fonte
Por que não usar uma abordagem de carimbo de data e hora e ter uma opção de estouro.
Por exemplo
Digamos que seu carimbo de data e hora seja: 1366587600
Omita os dois últimos dígitos (ou isso fica ridículo). Separe o carimbo em conjuntos de 4 (a contagem de diretórios não deve atingir mais de 9999 - se você quiser, pode separá-lo de maneira diferente).
Isso deve deixar você com algo assim:
Em seguida, verifique também a quantidade no diretório antes de fazer o upload, se estiver recebendo um grande número de uploads (por exemplo, 32000 + por 100 segundos), em seguida, itere o diretório pela segunda ou por uma letra, por exemplo:
ou
Em seguida, registre o carimbo de data / hora + letra ou o código do caminho completo em um banco de dados junto com o usuário e você deve estar definido.
pathstamp: 1366587600 ou 13665876a (se você estiver usando letras).
Isso acaba com um grande número de diretórios, mas pode ser realmente útil para lidar com revisões de arquivos. Por exemplo, se um usuário quiser usar uma nova imagem de perfil, você ainda terá a versão com carimbo de data e hora antiga da mais antiga, caso deseje desfazer as alterações (não é apenas sobrescrita).
fonte
Sugiro que você decida quantos subdiretórios máximos você deseja (ou pode) ter na pasta pai.
Então, você precisa converter seu ID de usuário para que eles comecem a partir de 1.
Então você pode fazer:
modulo = currentId % numberOfSubdirectories
modulo
agora conterá o número do subdiretório que nunca será maior do quenumberOfSubdirectories
você escolheu.Faça o que quiser com o módulo, faça o hash, por exemplo.
Além disso, os subdiretórios dessa maneira serão preenchidos linearmente.
fonte