web-dev-qa-db-fra.com

Stockage d'un million d'images dans le système de fichiers

J'ai un projet qui va générer un très grand nombre d'images. Environ 1 000 000 pour commencer. Ce ne sont pas des images de grande taille, je vais donc les stocker sur une seule machine au démarrage.

Comment recommandez-vous de stocker ces images efficacement? (Système de fichiers NTFS actuellement)

J'envisage un schéma de nommage ... pour commencer, toutes les images auront un nom incrémentiel à partir de 1, j'espère que cela m'aidera à les trier plus tard si nécessaire et à les jeter dans différents dossiers.

quel serait un meilleur schéma de nommage:

 a/b/c/0 ... z/z/z/999 

ou

 a/b/c/000 ... z/z/z/999 

une idée à ce sujet?

80
s.mihai

Je recommanderais d'utiliser un système de fichiers classique au lieu de bases de données. L'utilisation du système de fichiers est plus facile qu'une base de données, vous pouvez utiliser des outils normaux pour accéder aux fichiers, les systèmes de fichiers sont conçus pour ce type d'utilisation, etc. NTFS devrait fonctionner très bien comme système de stockage.

Ne stockez pas le chemin d'accès réel à la base de données. Mieux vaut stocker le numéro de séquence de l'image dans la base de données et avoir une fonction qui peut générer un chemin à partir du numéro de séquence. par exemple:

 File path = generatePathFromSequenceNumber(sequenceNumber);

Il est plus facile à gérer si vous devez modifier la structure des répertoires. Peut-être que vous devez déplacer les images vers un emplacement différent, peut-être que vous manquez d'espace et que vous commencez à stocker certaines des images sur le disque A et certaines sur le disque B, etc. Il est plus facile de changer une fonction que de changer les chemins dans la base de données .

J'utiliserais ce type d'algorithme pour générer la structure du répertoire:

  1. Tapez d'abord le numéro de séquence avec les zéros en tête jusqu'à ce que vous ayez au moins une chaîne de 12 chiffres. Il s'agit du nom de votre fichier. Vous voudrez peut-être ajouter un suffixe:
    • 12345 -> 000000012345.jpg
  2. Ensuite, divisez la chaîne en blocs de 2 ou 3 caractères où chaque bloc indique un niveau de répertoire. Avoir un nombre fixe de niveaux de répertoire (par exemple 3):
    • 000000012345 -> 000/000/012
  3. Stockez le fichier dans le répertoire généré:
    • Ainsi, le chemin d'accès complet et le nom de fichier pour le fichier avec l'ID de séquence 123 est 000/000/012/00000000012345.jpg
    • Pour le fichier avec l'ID de séquence 12345678901234 le chemin d'accès serait 123/456/789/12345678901234.jpg

Quelques points à considérer sur les structures de répertoires et le stockage de fichiers:

  • L'algorithme ci-dessus vous donne un système où chaque répertoire feuille a un maximum de 1000 fichiers (si vous avez moins de 1 000 000 000 000 de fichiers au total)
  • Le nombre de fichiers et de sous-répertoires qu'un répertoire peut contenir peut être limité, par exemple système de fichiers ext3 sous Linux a une limite de 31998 sous-répertoires pour un répertoire.
  • Les outils normaux (WinZip, Windows Explorer, ligne de commande, bash Shell, etc.) peuvent ne pas fonctionner très bien si vous avez un grand nombre de fichiers par répertoire (> 1000)
  • La structure de répertoire elle-même prendra un peu d'espace disque, vous ne voudrez donc pas trop de répertoires.
  • Avec la structure ci-dessus, vous pouvez toujours trouver le bon chemin pour le fichier image en regardant simplement le nom du fichier, si vous vous trompez dans la structure de votre répertoire.
  • Si vous devez accéder à des fichiers à partir de plusieurs machines, envisagez de partager les fichiers via un système de fichiers réseau.
  • La structure de répertoires ci-dessus ne fonctionnera pas si vous supprimez un grand nombre de fichiers. Il laisse des "trous" dans la structure du répertoire. Mais puisque vous ne supprimez aucun fichier, cela devrait aller.
73
Juha Syrjälä

Je vais mettre mes 2 cents sur un conseil négatif: n'allez pas avec une base de données.

Je travaille avec des bases de données de stockage d'images depuis des années: fichiers volumineux (1 méga-> 1 gig), souvent modifiés, plusieurs versions du fichier, accessibles assez souvent. Les problèmes de base de données que vous rencontrez avec des fichiers volumineux sont stockés sont extrêmement fastidieux, les problèmes d'écriture et de transaction sont difficiles et vous rencontrez des problèmes de verrouillage qui peuvent provoquer des épaves de train majeures. J'ai plus de pratique pour écrire des scripts dbcc et restaurer des tables à partir de sauvegardes que n'importe quelle personne normale. déjà avoir.

La plupart des nouveaux systèmes avec lesquels j'ai travaillé ont poussé le stockage de fichiers vers le système de fichiers et se sont appuyés sur des bases de données pour rien de plus que l'indexation. Les systèmes de fichiers sont conçus pour accepter ce type d'abus, ils sont beaucoup plus faciles à développer et vous perdez rarement tout le système de fichiers si une entrée est corrompue.

31
Satanicpuppy

Je pense que la plupart des sites qui doivent gérer ce problème utilisent un hachage quelconque pour s'assurer que les fichiers sont répartis uniformément dans les dossiers.

Disons que vous avez un hachage d'un fichier qui ressemble à ceci 515d7eab9c29349e0cde90381ee8f810
Vous pouvez stocker ces informations à l'emplacement suivant et utiliser le nombre de niveaux dont vous avez besoin pour maintenir le nombre de fichiers dans chaque dossier à un niveau bas.
\51\5d\7e\ab\9c\29\349e0cde90381ee8f810.jpg

J'ai vu cette approche adoptée plusieurs fois. Vous avez toujours besoin d'une base de données pour mapper ces hachages de fichiers à un nom lisible par l'homme et aux autres métadonnées que vous devez stocker. Mais cette approche évolue assez bien b/c, vous pouvez commencer à distribuer l'espace d'adressage de hachage entre plusieurs ordinateurs et/ou pools de stockage, etc.

12
3dinfluence

Idéalement, vous devez exécuter des tests sur les temps d'accès aléatoires pour diverses structures, car la configuration spécifique de votre disque dur, la mise en cache, la mémoire disponible, etc. peuvent modifier ces résultats.

En supposant que vous ayez le contrôle sur les noms de fichiers, je les partitionnerais au niveau de 1000 par répertoire. Plus vous ajoutez de niveaux de répertoire, plus vous gravez d'inodes, donc il y a un push-pull ici.

Par exemple.,

/ root/[0-99]/[0-99]/nom de fichier

Remarque, http://technet.Microsoft.com/en-us/library/cc781134 (WS.10) .aspx contient plus de détails sur la configuration NTFS. En particulier, "Si vous utilisez un grand nombre de fichiers dans un dossier NTFS (300 000 ou plus), désactivez la génération de noms de fichiers courts pour de meilleures performances, et surtout si les six premiers caractères des noms de fichiers longs sont similaires."

Vous devriez également envisager de désactiver les fonctionnalités du système de fichiers dont vous n'avez pas besoin (par exemple, le dernier accès). http://www.pctools.com/guides/registry/detail/50/

11
Jason Yanowitz

Quoi que vous fassiez, ne les stockez pas tous dans un seul répertoire.

Selon la distribution des noms de ces images, vous pouvez créer une structure de répertoires dans laquelle vous avez des dossiers de premier niveau à une seule lettre où vous auriez un autre ensemble de sous-dossiers pour la 2e lettre d'images, etc.

Donc:

Dossier img\a\b\c\d\e\f\g\ contiendrait les images commençant par 'abcdefg' et ainsi de suite.

Vous pouvez introduire votre propre profondeur appropriée requise.

La grande chose à propos de cette solution est que la structure du répertoire agit efficacement comme une table de hachage/dictionnaire. Étant donné un nom de fichier image, vous connaîtrez son répertoire et un répertoire donné, vous connaîtrez un sous-ensemble d'images qui y vont.

7
Wim Hollebrandse

Nous avons un système de magasin de photos avec 4 millions d'images. Nous utilisons la base de données uniquement pour les métadonnées et toutes les images sont stockées sur le système de fichiers à l'aide d'un système de nommage inversé, où les noms de dossier sont générés à partir du dernier chiffre du fichier, last-1, etc. par exemple: 000001234.jpg est stocké dans une structure de répertoires comme 4\3\2\1\000001234.jpg.

Ce schéma fonctionne très bien avec l'index d'identité dans la base de données, car il remplit uniformément la structure de répertoires entière.

5
user30438

Je les stockerais sur le système de fichiers, mais cela dépend de la vitesse à laquelle le nombre de fichiers augmentera. Ces fichiers sont-ils hébergés sur le Web? Combien d'utilisateurs accèderaient à ce fichier? Ce sont les questions auxquelles il faut répondre avant que je puisse vous donner une meilleure recommandation. Je regarderais également Haystack de Facebook, ils ont une très bonne solution pour stocker et servir des images.

De plus, si vous choisissez le système de fichiers, vous devrez partitionner ces fichiers avec des répertoires. J'ai examiné ce problème et proposé une solution, mais ce n'est pas parfait du tout. Je partitionne par table de hachage et les utilisateurs peuvent en savoir plus sur mon blog .

5
Lukasz

Point rapide, vous n'avez pas besoin de stocker un chemin de fichier dans votre base de données. Vous pouvez simplement stocker une valeur numérique, si vos fichiers sont nommés de la manière que vous décrivez. Ensuite, en utilisant l'un des schémas de stockage bien définis déjà discutés, vous pouvez obtenir l'index sous forme de nombre et trouver très rapidement le fichier en parcourant la structure du répertoire.

4
Mr. Boy

Le nouveau MS SQL 2008 a une nouvelle fonctionnalité pour gérer de tels cas, il s'appelle FILESTREAM. Regarde:

Présentation de Microsoft TechNet FILESTREAM

4
Padu Merloti

Vos images devront-elles être nommées de manière unique? Le processus qui génère ces images peut-il produire le même nom de fichier plus d'une fois? Difficile à dire sans savoir quel appareil crée le nom de fichier, mais dites que l'appareil est "réinitialisé" et au redémarrage, il commence à nommer les images comme il l'a fait la dernière fois qu'il a été "réinitialisé" - si c'est une telle préoccupation ..

Vous dites également que vous atteindrez 1 million d'images en un mois. Et après ça? À quelle vitesse ces images continueront-elles à remplir le système de fichiers? Vont-elles se compléter à un moment donné et se stabiliser à environ 1 million d'images TOTALES ou va-t-elle continuer à croître et grandir, mois après mois?

Je vous le demande car vous pourriez commencer à concevoir votre système de fichiers par mois, puis par image. Je pourrais être enclin à suggérer que vous stockiez les images dans une telle structure de répertoires:

imgs\yyyy\mm\filename.ext

where: yyyy = 4 digit year
         mm = 2 digit month

example:  D:\imgs\2009\12\aaa0001.jpg
          D:\imgs\2009\12\aaa0002.jpg
          D:\imgs\2009\12\aaa0003.jpg
          D:\imgs\2009\12\aaa0004.jpg
                   |
          D:\imgs\2009\12\zzz9982.jpg
          D:\imgs\2010\01\aaa0001.jpg (this is why I ask about uniqueness)
          D:\imgs\2010\01\aab0001.jpg

Mois, année, même jour est bon pour les images de type sécurité. Je ne sais pas si c'est ce que vous faites, mais je l'ai fait avec une caméra de sécurité à domicile qui a pris une photo toutes les 10 secondes ... De cette façon, votre application peut explorer une heure spécifique ou même une plage où vous pourriez penser que l'image a été générée . Ou, au lieu de l'année, du mois - existe-t-il une autre "signification" qui peut être dérivée du fichier image lui-même? D'autres descripteurs, autre que l'exemple de date que j'ai donné?

Je ne stockerais pas les données binaires dans la base de données. Jamais eu de bonnes performances/chance avec ce genre de chose. Je ne peux pas imaginer qu'il fonctionne bien avec 1 million d'images. Je voudrais stocker le nom de fichier et c'est tout. S'ils vont tous être au format JPG, ne stockez même pas l'extension. Je créerais une table de contrôle qui stockait un pointeur sur le serveur, le lecteur, le chemin du fichier, etc. De cette façon, vous pouvez déplacer ces images vers une autre boîte et les localiser. Avez-vous besoin de taguer vos images par mot-clé? Si c'est le cas, vous souhaitez créer les tableaux appropriés qui permettent ce type de marquage.

Vous/d'autres avez peut-être abordé ces idées pendant que je répondais. J'espère que cela vous aidera.

4
Taptronic

Je participe à un projet qui stocke 8,4 millions d'images au cours d'une année pour documenter l'état de divers appareils. Des images plus récentes sont consultées plus fréquemment et des images plus anciennes sont rarement recherchées à moins qu'une condition ne soit découverte qui a incité quelqu'un à fouiller dans les archives.

Ma solution, basée sur cette utilisation, était de compresser progressivement les images dans des fichiers compressés. Les images sont des JPG, chacune d'environ 20 Ko et ne compressent pas beaucoup, donc le schéma de compression Zip est nul. Cela se fait simplement pour les concaténer en une seule entrée du système de fichiers, ce qui aide grandement NTFS en termes de vitesse lorsqu'il s'agit de les déplacer d'un lecteur à l'autre ou de parcourir la liste des fichiers.

Les images de plus d'un jour sont combinées dans un Zip "quotidien"; les zips de plus d'un mois sont combinés dans leur Zip "mensuel" respectif; et enfin tout ce qui dépasse un an n'est plus nécessaire et par conséquent supprimé.

Ce système fonctionne bien car les utilisateurs peuvent parcourir les fichiers (via le système d'exploitation ou un certain nombre d'applications clientes) et tout est nommé en fonction des noms des appareils et des horodatages. Généralement, un utilisateur connaît ces deux informations et peut localiser rapidement n'importe laquelle des millions d'images.

Je comprends que ce n'est probablement pas lié à vos détails particuliers, mais j'ai pensé partager.

3
JYelton

Cela pourrait être en retard dans le match. Mais une solution (si elle convient à votre cas d'utilisation) pourrait être le hachage de nom de fichier. C'est un moyen de créer un chemin de fichier facilement reproductible en utilisant le nom du fichier tout en créant une structure de répertoire bien répartie. Par exemple, vous pouvez utiliser les octets du code de hachage du nom de fichier comme chemin:

String fileName = "cat.gif";
int hash = fileName.hashCode();
int mask = 255;
int firstDir = hash & mask;
int secondDir = (hash >> 8) & mask;

Cela se traduirait par le chemin étant:

/172/029/cat.gif

Vous pouvez alors trouver cat.gif dans la structure du répertoire en reproduisant l'algorithme.

Utiliser HEX comme noms de répertoire serait aussi simple que de convertir les valeurs int:

String path = new StringBuilder(File.separator)
        .append(String.format("%02x", firstDir))
        .append(File.separator)
        .append(String.format("%02x", secondDir)
        .toString();

Résultant en:

/AC/1D/cat.gif

J'ai écrit un article à ce sujet il y a quelques années et je l'ai récemment déplacé vers Medium. Il contient quelques détails supplémentaires et quelques exemples de code: Hashing de nom de fichier: création d'une structure de répertoire hachée . J'espère que cela t'aides!

2
Michael Andrews

Envisagez-vous une reprise après sinistre?

Certaines des solutions proposées ici finissent par altérer le nom du fichier (de sorte que si le fichier physique était déplacé, vous perdriez la trace de ce fichier). Je recommande de conserver un nom de fichier physique unique afin que si votre liste principale d'emplacements de fichiers est corrompue, vous pouvez le régénérer avec un petit Shell, euh, PowerShell, script;)

D'après ce que j'ai lu ici, il semble que tous ces fichiers soient stockés sur un système de fichiers. Pensez à les stocker sur plusieurs systèmes de fichiers sur plusieurs machines. Si vous avez les ressources, déterminez un système de stockage de chaque fichier sur deux machines différentes au cas où vous perdriez une alimentation électrique et que le remplacement est dans 2 jours.

Considérez les types de procédures que vous devez créer pour migrer des fichiers entre des machines ou des systèmes de fichiers. La possibilité de le faire avec votre système est en direct et en ligne peut vous éviter des maux de tête considérables sur la route.

Vous pourriez envisager d'utiliser un GUID comme nom de fichier physique au lieu d'un nombre incrémentiel au cas où votre compteur de nombres incrémentiels (la colonne d'identité de la base de données?) Serait gâché.

Le cas échéant, envisagez d'utiliser un CDN tel qu'Amazon S3.

2
Donald Byrd

Peut-être un schéma de nommage basé sur la date de création - soit en incluant toutes les informations dans le nom du fichier ou (mieux pour parcourir plus tard) en le divisant en répertoires. Je peux penser aux éléments suivants, selon la fréquence à laquelle vous générez des images:

  • Plusieurs images générées chaque jour: Year/Month/Day/Hour_Minute_Second.png
  • Un couple par mois: Year/Month/Day_Hour_Minute_Second.png

etc. Vous obtenez mon point ... =)

2
Tomas Aschan

Bien que je n'aie pas servi de photos à cette échelle, j'ai déjà écrit une petite application de galerie pour servir environ 25k photos sur une machine à 400 MHz. 512 Mo de RAM environ. Quelques expériences;

  • Évitez à tout prix les bases de données relationnelles; Bien que les bases de données, sans aucun doute, soient intelligentes dans la gestion des données, elles ne sont pas conçues pour une telle utilisation (nous avons obtenu des bases de données de valeurs clés hiérarchisées spécialisées pour celles appelées systèmes de fichiers). Bien que je n'ai rien de plus qu'un pressentiment, je parierais que le cache DB sort par la fenêtre, si vous lui jetez de très gros blobs. Alors que mon matériel disponible était petit, le fait de ne pas toucher du tout à la base de données lors de la recherche d'image donnait des ordres de grandeur plus rapides.

  • Rechercher le comportement du système de fichiers; sur ext3 (ou était-ce ext2 à l'époque - je ne me souviens pas), la limite de la possibilité de rechercher efficacement des sous-répertoires et des fichiers était d'environ 256; afin d'avoir seulement autant de fichiers et de dossiers dans un dossier donné. Encore une fois, une accélération notable. Bien que je ne connaisse pas NTFS, des choses comme XFS (qui utilise des arbres B, pour autant que je m'en souvienne) sont extrêmement rapides, simplement parce qu'elles peuvent faire des recherches extrêmement rapidement.

  • Distribuez les données de manière égale; quand j'ai expérimenté avec ce qui précède, j'ai essayé de distribuer les données uniformément sur tous les répertoires (j'ai fait un MD5 de l'URL et l'ai utilisé pour les répertoires; /1a/2b/1a2b...f.jpg). De cette façon, il faut plus de temps pour atteindre la limite de performances (et le cache du système de fichiers est de toute façon vide pour de tels ensembles de données). (au contraire, vous voudrez peut-être voir où sont les limites dès le début; vous voulez alors tout jeter dans le premier répertoire disponible.

2
Morten Siebuhr

Je serais enclin à créer une structure de dossiers basée sur la date, par exemple\year\month\day et utilisez des horodatages pour les noms de fichiers. Si nécessaire, les horodatages peuvent avoir un composant compteur supplémentaire si les images doivent être créées si rapidement qu'il peut y en avoir plusieurs en une milliseconde. En utilisant une séquence la plus significative à la moins significative pour le tri des noms, la recherche et la maintenance sont un jeu d'enfant. par exemple. hhmmssmm [seq] .jpg

2
John Gardeniers

Je vois que d'autres mentionnent une base de données, mais je n'en vois aucune mention dans votre message. En tout cas, mon avis sur ce point particulier est: soit s'en tenir à une base de données ou à un système de fichiers. Si vous devez mélanger les deux, soyez prudent. Les choses se compliquent. Mais vous devrez peut-être. Stocker un million de photos dans une base de données ne semble pas la meilleure idée.

Vous pourriez être intéressé par la spécification suivante, la plupart des appareils photo numériques la suivent pour gérer le stockage de fichiers: https://en.wikipedia.org/wiki/Camera_Image_File_Format

Essentiellement, un dossier est créé, tel que 000Olympus et des photos sont ajoutées à ce dossier (par exemple DSC0000.RAW). Lorsque le compteur de noms de fichiers atteint DSC9999.RAW un nouveau dossier est créé (001Olympus) et l'image sont à nouveau ajoutées, réinitialisant le compteur, éventuellement avec un préfixe différent (ex: P_0000.RAW).

Alternativement, vous pouvez également créer des dossiers basés sur des parties du nom de fichier (déjà mentionné plusieurs fois). Par exemple, si votre photo est nommée IMG_A83743.JPG, stockez-le à IMG_\A8\3\IMG_A83743.JPG. Il est plus compliqué à implémenter mais rendra vos fichiers plus faciles à trouver.

Selon le système de fichiers (cela nécessitera des recherches), vous pourrez peut-être simplement vider toutes les images dans un seul dossier, mais, selon mon expérience, cela entraînerait généralement des problèmes de performances.

1
Rolf

Je viens de lancer un test sur zfs parce que j'adore zfs, et j'avais une partition de 500gig sur laquelle j'avais une compression. J'ai écrit un script qui a généré des fichiers 50-100k et les ai placés dans des répertoires imbriqués 1/2/3/4/5/6/7/8 (5-8 niveaux de profondeur) et je l'ai laissé fonctionner pendant une semaine je pense. (ce n'était pas un excellent script.) Il a rempli le disque et a fini par avoir environ 25 millions de fichiers. L'accès à n'importe quel fichier avec un chemin connu était instantané. La liste de tout répertoire avec un chemin connu était instantanée.

Le décompte de la liste des fichiers (via find) a cependant pris 68 heures.

J'ai également effectué un test en mettant un grand nombre de fichiers dans un seul répertoire. J'ai obtenu jusqu'à environ 3,7 millions de fichiers dans un répertoire avant de m'arrêter. La liste du répertoire pour obtenir un décompte a pris environ 5 minutes. La suppression de tous les fichiers de ce répertoire a pris 20 heures. Mais la recherche et l'accès à n'importe quel fichier étaient instantanés.

1
Stu

Si vous êtes sur Windows, que diriez-vous d'un fichier exFat

http://msdn.Microsoft.com/en-us/library/aa914353.aspx

il a été conçu en pensant au stockage des fichiers multimédias et est disponible dès maintenant.

1
Alex

S'ils ne sont PAS tous requis immédiatement et que vous pouvez les générer à la volée et que ce sont de petites images, pourquoi ne pas implémenter une mémoire LRU ou un cache-disque au-dessus de votre générateur d'images?

Cela pourrait vous sauver du stockage et conserver les images chaudes à servir de mem?

1
Jé Queue

Une façon propre de générer le chemin à partir d'un grand nombre est de le convertir facilement en hex puis de le diviser!

par exemple 1099496034834> 0xFFFF1212> FF/FF/12/12

public string GeneratePath(long val)
{  
    string hex = val.ToString("X");
    hex=hex.PadLeft(10, '0');
    string path="";
    for(int i=0; i<hex.Length; i+=2 )
    {
        path += hex.Substring(i,2);
        if(i+2<hex.Length)
            path+="/";
    }
    return path;
}

Stocker et charger:

public long Store(Stream doc)
{
   var newId = getNewId();
   var fullpath = GeneratePath(newId)
   // store into fullpath 
   return newId;
}

public Stream Load(long id)
{
   var fullpath = GeneratePath(newId)
   var stream = ... 
   return stream;
}

Codes source complets: https://github.com/acrobit/AcroFS

0
Ghominejad

Vous voudrez peut-être regarder ZFS (système de fichiers, gestionnaire de volume de Sun)

0
CDDH