Nous aimerions stocker des millions de fichiers texte dans un système de fichiers Linux, dans le but de pouvoir compresser et servir une collection arbitraire en tant que service. Nous avons essayé d'autres solutions, comme une base de données clé / valeur, mais nos exigences de concurrence et de parallélisme font de l'utilisation du système de fichiers natif le meilleur choix.
Le moyen le plus simple consiste à stocker tous les fichiers dans un dossier:
$ ls text_files/
1.txt
2.txt
3.txt
ce qui devrait être possible sur un système de fichiers EXT4 , qui n'a pas de limite au nombre de fichiers dans un dossier.
Les deux processus FS seront:
- Écrire un fichier texte à partir du Web scrape (ne devrait pas être affecté par le nombre de fichiers dans le dossier).
- Compressez les fichiers sélectionnés en fonction de la liste des noms de fichiers.
Ma question est la suivante: le stockage d'un maximum de dix millions de fichiers dans un dossier affectera-t-il les performances des opérations ci-dessus, ou les performances générales du système, différemment de la création d'une arborescence de sous-dossiers dans laquelle les fichiers doivent vivre?
la source
dir_index
, qui est souvent activée par défaut, accélérera les recherches mais peut limiter le nombre de fichiers par répertoire.ls -l
ou toute autre chose qui se trouve àstat
chaque inode dans le répertoire (par exemplebash
globbing / tabulation) sera artificiellement plus rapide qu'après une certaine usure (supprimez certains fichiers, écrivez-en de nouveaux). ext4 pourrait faire mieux avec cela que XFS, car XFS alloue dynamiquement de l'espace pour les inodes par rapport aux données, donc vous pouvez vous retrouver avec des inodes plus dispersés, je pense. (Mais c'est une pure supposition basée sur très peu de connaissances détaillées; j'ai à peine utilisé ext4). Allez avec des sous-abc/def/
dires.ZipOutputStream
battrait à peu près n'importe quel système de fichiers natif Linux gratuit - je doute que vous souhaitiez payer pour le GPFS d'IBM. La boucle pour traiter un jeu de résultats JDBC et créer ce flux zip n'est probablement que de 6 à 8 lignes de code Java.Réponses:
La
ls
commande, ou même l'achèvement TAB ou l'expansion générique par le shell, présentera normalement ses résultats dans l'ordre alphanumérique. Cela nécessite la lecture de la liste complète du répertoire et son tri. Avec dix millions de fichiers dans un seul répertoire, cette opération de tri prendra un temps non négligeable.Si vous pouvez résister à l'envie de terminer TAB et par exemple écrire les noms des fichiers à compresser en entier, il ne devrait pas y avoir de problèmes.
Un autre problème avec les caractères génériques pourrait être l'expansion des caractères génériques, produisant éventuellement plus de noms de fichiers que ne le permet une ligne de commande de longueur maximale. La longueur maximale typique de la ligne de commande sera plus que suffisante dans la plupart des situations, mais lorsque nous parlons de millions de fichiers dans un seul répertoire, ce n'est plus une hypothèse sûre. Lorsqu'une longueur de ligne de commande maximale est dépassée dans l'extension générique, la plupart des shells échouent simplement à la ligne de commande entière sans l'exécuter.
Cela peut être résolu en effectuant vos opérations génériques à l'aide de la
find
commande:ou une syntaxe similaire chaque fois que possible. Le
find ... -exec ... \+
prendra automatiquement en compte la longueur maximale de la ligne de commande et exécutera la commande autant de fois que nécessaire tout en ajustant la quantité maximale de noms de fichiers à chaque ligne de commande.la source
ls
commande ne parviennent pas à savoir que la liste des répertoires est déjà triée, ils prendront quand même le temps d'exécuter l'algorithme de tri. De plus, l'espace utilisateur peut utiliser un ordre de tri localisé (LC_COLLATE) qui peut être différent de ce que le système de fichiers pourrait faire en interne.C'est dangereusement proche d'une question / réponse basée sur une opinion mais je vais essayer de fournir quelques faits avec mes opinions.
mv * /somewhere/else
) peut échouer à développer correctement le caractère générique, ou le résultat peut être trop volumineux pour être utilisé.ls
prendra plus de temps pour énumérer un très grand nombre de fichiers qu'un petit nombre de fichiers.Une recommandation est de diviser le nom de fichier en deux, trois ou quatre blocs de caractères et de les utiliser comme sous-répertoires. Par exemple,
somefilename.txt
peut être stocké soussom/efi/somefilename.txt
. Si vous utilisez des noms numériques, divisez-les de droite à gauche au lieu de gauche à droite pour une distribution plus uniforme. Par exemple,12345.txt
peut être stocké sous345/12/12345.txt
.Vous pouvez utiliser l'équivalent de
zip -j zipfile.zip path1/file1 path2/file2 ...
pour éviter d'inclure les chemins de sous-répertoire intermédiaires dans le fichier ZIP.Si vous servez ces fichiers à partir d'un serveur Web (je ne suis pas tout à fait sûr que ce soit pertinent), il est trivial de cacher cette structure en faveur d'un répertoire virtuel avec des règles de réécriture dans Apache2. Je suppose que la même chose est vraie pour Nginx.
la source
*
expansion réussira sauf si vous manquez de mémoire, mais à moins que vous n'augmentiez la limite de taille de pile (sous Linux) ou que vous n'utilisiez un shell oùmv
est intégré ou peut être intégré (ksh93, zsh), l'execve()
appel système peut échouer avec une erreur E2BIG.zip -j - ...
et de diriger le flux de sortie directement vers la connexion réseau du clientzip -j zipfile.zip ...
. L'écriture d'un fichier zip réel sur le disque signifie que le chemin de données est lu sur le disque-> compresser-> écrire sur le disque-> lire sur le disque-> envoyer au client. Cela peut jusqu'à tripler les besoins d'E / S de votre disque par rapport à la lecture depuis le disque-> compresser-> envoyer au client.Je gère un site Web qui gère une base de données pour les films, la télévision et les jeux vidéo. Pour chacun d'eux, il y a plusieurs images avec TV contenant des dizaines d'images par émission (c.-à-d. Instantanés d'épisode, etc.).
Il finit par y avoir beaucoup de fichiers image. Quelque part dans la gamme 250,000+. Ceux-ci sont tous stockés dans un périphérique de stockage en bloc monté où le temps d'accès est raisonnable.
Ma première tentative de stockage des images a été dans un seul dossier
/mnt/images/UUID.jpg
J'ai rencontré les défis suivants.
ls
via un terminal distant serait juste se bloquer. Le processus deviendrait zombie etCTRL+C
ne le briserait pas.ls
commande remplirait rapidement le tampon de sortie etCTRL+C
n'arrêterait pas le défilement sans fin.J'ai fini par devoir stocker les fichiers dans des sous-dossiers en utilisant le temps de création pour créer le chemin. Tels que
/mnt/images/YYYY/MM/DD/UUID.jpg
. Cela a résolu tous les problèmes ci-dessus et m'a permis de créer des fichiers zip ciblant une date.Si le seul identifiant pour un fichier que vous avez est un numéro numérique, et ces numéros ont tendance à s'exécuter en séquence. Pourquoi ne pas les regrouper par
100000
,10000
et1000
.Par exemple, si vous avez un fichier nommé,
384295.txt
le chemin d'accès serait:Si vous savez que vous atteindrez quelques millions. Utiliser des
0
préfixes pour 1000000la source
Pour créer un nouveau fichier, il faut analyser le fichier de répertoire en recherchant suffisamment d'espace vide pour la nouvelle entrée de répertoire. Si aucun espace n'est suffisamment grand pour stocker la nouvelle entrée de répertoire, il sera placé à la fin du fichier de répertoire. À mesure que le nombre de fichiers dans un répertoire augmente, le temps d'analyse du répertoire augmente également.
Tant que les fichiers de répertoire restent dans le cache du système, les performances obtenues ne seront pas mauvaises, mais si les données sont publiées, la lecture du fichier de répertoire (généralement très fragmenté) à partir du disque pourrait prendre beaucoup de temps. Un SSD améliore cela, mais pour un répertoire contenant des millions de fichiers, il pourrait toujours y avoir un impact notable sur les performances.
Cela peut également nécessiter du temps supplémentaire dans un répertoire contenant des millions de fichiers. Dans un système de fichiers avec des entrées de répertoire hachées (comme EXT4), cette différence est minime.
Un arbre de sous-dossiers ne présente aucun des inconvénients de performances ci-dessus. De plus, si le système de fichiers sous-jacent est modifié pour ne pas avoir de noms de fichier hachés, la méthodologie d'arbre fonctionnera toujours bien.
la source
Premièrement: empêcher 'ls' de trier avec 'ls -U', peut-être mettre à jour votre ~ / bashrc pour avoir 'alias ls = "ls -U"' ou similaire.
Pour votre grand ensemble de fichiers, vous pouvez essayer ceci comme ceci:
créer un ensemble de fichiers de test
voir si de nombreux noms de fichiers causent des problèmes
utilisez xargs parmeter-batching et le comportement (par défaut) de zip d'ajouter des fichiers à un zip pour éviter les problèmes.
Cela a bien fonctionné:
la source