8
votes

Quelle est la meilleure façon de créer une serrure d'une application Web?

J'ai une application Web qui redimensionnement des images. Les images de la reformalisation sont écrites sur le disque afin de les mettre en cache. Quelle est la meilleure façon d'empêcher plusieurs demandes simultanées de générer la même image?

Quelques choses à noter, nous avons des millions d'images (mesurées en téraoctets). Des images en cache qui n'ont pas été consultées depuis un moment sont supprimées. Nous avons une ferme Web, mais chaque serveur Web a son propre cache local (les originaux sont stockés sur un autre serveur). Nous placons également les images de reformalisation dans un cache de second niveau une fois générées, de sorte que d'autres serveurs Web peuvent vérifier là pour voir si l'image est mise en cache, si elle est copiée locale.

J'ai envisagé d'utiliser des serrures (j'ai posté une classe que j'envisage à utiliser Ici ). Mais cela ne fonctionnera évidemment pas avec le cache du 2e rang et je ne suis pas sûr que si c'est une bonne idée en général sur un serveur Web d'utiliser des serrures (même si je ne sais pas pourquoi, juste un tas de références vagues à c'est une mauvaise idée).

J'ai aussi envisagé d'écrire un fichier temporaire que je pouvais vérifier avant de commencer à créer l'image, mais je crains que Windows ne nettoie pas le fichier correctement 100% du temps (problèmes de verrouillage, etc.).

Toutes les idées sont appréciées.


7 commentaires

Comment savez-vous si les demandes généreront la même image - faites-les avoir un identifiant unique, ou devez-vous comparer l'octet entier [] pour déterminer si elles sont identiques?


Nous utilisons Mutex pour une machine unique avec de nombreux pools et une base de données commune si nous avons plusieurs ordinateurs avec le même cache, pour la synchronisation (pas les données de cache).


Une solution possible que je puisse penser dans un environnement important que vous travaillez consiste à utiliser une table DB pour la file d'attente des hachages MD5 du fichier image. Avant d'écrire sur le disque, interrogez la table à l'aide du hachage MD5 de ladite image contre la table, s'il existe dans la table d'écriture de table. Si cela n'existe pas, insérez-les, puis commencez le cache. Cela limitera les multiples demandes, en outre vous donnera la possibilité de décider quand effacer la table pour éviter plus de demandes.


@Kirk, les images sont identifiées par un ID entier.


D'où vient la demande? Avez-vous une demande de redimensionner la même image plusieurs fois?


d'où obtenez-vous les images? sont-ils téléchargés? Ou ils sont déjà stockés quelque part?


@ user177883, les demandes proviennent de balises sur des pages Web et les originaux sont stockés sur un serveur de fichiers.


8 Réponses :


1
votes

Avez-vous envisagé d'utiliser le middleware pour cela, tel que MSMQ ou ActiveMQ? Une fois que la demande de redimensionnement de l'image au serveur Web est soumise, elle va à la file d'attente. Une application distincte vérifierait la file d'attente, redimensionnez l'image et enregistrez-la sur le cache.


0 commentaires

0
votes

Utiliser une base de données pour répertorier les hachages de fichiers serait le moyen le plus rapide de le faire. Ensuite, cela peut être partagé entre tous les niveaux, il vous permet également de décharger n'importe quel verrouillage du SQL transactionnel (T-SQL).

Autres applications à grande échelle qui doivent stocker TB comme Symantec Enterprise Vault font la même chose.


0 commentaires

1
votes

J'éviterais les serrures si vous le pouvez - surtout que vous n'avez pas besoin de verrouiller ici. Vous souhaitez également éviter une verrouillage de la machine sur la base d'un autre traitement des machines. Si deux machines créent la même image redimensionnée, je suppose qu'ils seraient les mêmes. Ainsi, si deux machines se présentent pour redimensionner le même problème, car ils ont tous deux manqué le cache, son seul légèrement moins efficace (temps perdu) mais très probablement mieux que de verrouiller (et éventuellement de la manquement) et d'essayer d'optimiser le boîtier de bord.

Une option serait de créer l'image redimensionnée localement et d'en faire l'élément mis en cache dans une file d'attente centrale (base de données? en mémoire sur le service central?) Soit avec les données ou avec une référence comment la tirer de la machine avant. La file d'attente de cache centralisée est traitée en série. Si deux doublons sont placés dans la file d'attente entre le moment où il est redimensionné par plus d'une machine et que l'élément de la file d'attente peut être traité, cela n'a pas d'importance car le traitement duplicaté serait simplement une condition simplement la tirer puisqu'il est déjà sur le disque.


2 commentaires

Sachez-vous si Windows gère plusieurs machines qui écrivent le même fichier en même temps? Ou une machine écrit un fichier et un autre le lisant? Cela ne me dérange pas si plusieurs machines écrivent le même fichier, mais je m'inquiète d'écrire le même fichier en même temps.


Dans mon approche, la file d'attente gère cela. Il y a une file d'attente qui tire des fichiers aussi vite que possible. Si cela ne suffit pas, vous devez avoir plusieurs files d'attente et synchroniser plusieurs files d'attente. Je voudrais toujours éviter la serrure et avoir un ensemble (hashset?) D'éléments traités qui sont partagés.



0
votes

Il ne devrait pas être différent des applications Web qui doivent contrôler l'édition / la mise à jour des données dans une base de données.

Autant que j'ai essayé, avec succès, stockiez l'image comme champ de blob dans la base de données. J'ai eu le montage BLOB contrôlé comme tout autre domaine de données.

Ce qui signifie que vous devez vous familiariser avec la manière dont les services Web fonctionnent avec la base de données pour faire face aux collisions et au contrôle de la concurrence.

comme alternative Si vous ne pouvez pas vous permettre un RDBM hautement évolutif ... Au lieu de stocker comme blob dans la base de données, vous pouvez stocker le nom / chemin de fichier, où l'image réelle est stockée dans le système de fichiers. La base de données fournit la clé unique à une image. Tous les accès à n'importe quelle image doivent être effectués à travers son enregistrement de base de données. Chaque fois qu'une nouvelle image est générée, ce qui suit a lieu sous une transaction atomique de l'ordre prescrit

  1. Il est stocké sous un nouveau nom / chemin
  2. Si le succès, l'enregistrement de base de données est mis à jour
  3. Si le succès, l'ancienne image est supprimée

    Il s'agit des éventualités que vous devez traiter: si la dernière étape n'a pas de succès (la défaillance du système / de la puissance peut être), l'enregistrement DB serait renvoyé et vous auriez une image orpheline. Ou si la mise à jour de la DB échoue, l'image nouvellement stockée se retrouverait comme un orphelin.

    Par conséquent, pour protéger votre système de fichiers sain d'esprit et effacer les orphelins, vous supprimerez probablement des images plus âgées de 24 heures.

    Pour une solution plus robuste, reportez-vous à la description de ma technique de mise en cache d'applications Web:

    http://h2g2java.blessedgeek.com/ 2010/04 / Page-Caching-en utilisant-demande-paramètretric.html


0 commentaires

0
votes

Je suggérerais 2 solutions similaires dans la nature. L'un d'entre eux est d'utiliser une couche de service WCF. Dans ce service, vous pouvez utiliser un dictionnaire simultané. Vous devriez développer un code de hachage de manière à ce que la même image créerait le même hachage. Par conséquent, vous aurez une seule instance de l'image dans votre dictionnaire simultané. Vous pouvez également ajouter un horodatage à votre classe qui représentera l'image. Cela pourrait avoir une utilisation. Une fois que vous avez généré l'image, vous pouvez mettre à jour cette classe dans votre classe avec l'emplacement de l'image générée. Et vous pouvez avoir un gros drapeau qui indiquera que cette image est en cours de traitement si vous avez une autre demande vient en demandant un redimensionnement. Ensuite, vous ignorez cette demande. Non seulement que vous utilisez un dictionnaire simultané, vous pouvez également verrouiller une seule clé unique dans le dictionnaire. Mais si vous utilisez un drapeau bit comme actuellement le traitement, vous n'aurez pas besoin d'un verrou. Ce serait une solution très rapide et efficace, imo.

Une autre solution serait une table de hachage dissiputée telle que le cache AppFabric. Même logique que ci-dessus.

Que pensez-vous?


0 commentaires

0
votes

Je ne sais pas si vous avez vraiment besoin de résoudre ce point - considérez les points suivants:

  • Et si un serveur commence à redimensionner un processus spécifique et le processus de résistance devient en quelque sorte "bloqué"? Si vous implémentez ce que vous décrivez, tous les autres serveurs attendraient que ce serveur ait fini ... Je ne sais pas que cela crée une bonne expérience utilisateur
  • OTOH Si vous n'êtes pas implémenter que vous ne perdez qu'un peu de temps mais ne sont pas confrontés à résoudre le problème ci-dessus ...

    Je voudrais définitivement mettre en œuvre une sorte de cache-mémoire DB- ou (central) dans la mémoire du contenu (ID d'image) du 2nd-cache-cache des machines à Avoud d'entrer dans les conflits lors de la copie de l'image redimensionnée dans le Cache ...


0 commentaires

0
votes

Si vous souhaitez créer un client de traiter une image aléatoire à un moment d'abord, vous stockez un drapeau dans la vieilletate lorsque vous êtes la demande. Le drapeau est soulevé lorsque les données sont soumises et que le drapeau est réintégré lorsque vous avez terminé le traitement de l'image. Lorsque vous recevez une demande, vérifiez si le drapeau est soulevé ou non. Si surélevé rejeté pour traiter l'image.

Dans le deuxième cas, à savoir si vous souhaitez prétendre que l'utilisateur de soumettre la jolie image la même image, vous pouvez stocker le nom et la taille (ByTewise) de l'image dans ViewState et lorsque l'utilisateur sélectionne une image, vous comparez le nom et la taille de la taille du nom. image avant de traiter l'image. Si la taille et le nom de l'image sont les mêmes que vous avez stockés dans la visualisation, vous rejetez pour traiter l'image. Sinon, vous le traitez.

J'espère que cela peut vous aider.


0 commentaires

1
votes

Premièrement, génèverez le nom de fichier avec un GUID afin que vous sachiez que vous n'allez pas avoir des noms de fichiers en double.

guid.newguid ()

empêche ensuite de verrouiller les images à l'aide du code Ci-dessous: - xxx

J'ai ce code fonctionne très efficacement et que c'était le seul moyen de trouver pour être sûr que le fichier n'est jamais verrouillé.


0 commentaires