2011-03-18 4 views
3

J'ai environ 50 sites Web, équilibrés en charge sur 5 serveurs Web. Ils utilisent tous la mise en cache de la bibliothèque d'entreprise et accèdent à la même base de données Caching. Les éléments de la base de données Caching sont actualisés toutes les quelques heures à l'aide d'une implémentation ICacheItemRefreshAction.Section critique distribuée dans la batterie de serveurs Web

Je veux garantir que seul un site Web rafraîchit toujours le cache, en plaçant le code de rafraîchissement dans un critical section.

  • Si les sites Web étaient en cours d'exécution dans une application unique piscine sur un seul serveur, je pourrais utiliser un lock()

  • Si les sites Web étaient en cours d'exécution dans app-piscines séparées sur un seul serveur, je pourrais utiliser un Mutex.

Toutefois, ceux-ci ne garantiront pas la section critique sur plusieurs serveurs Web.

Actuellement, je suis en train de créer une nouvelle clé dans la base de données de mise en cache pour agir comme un mutex. Cela fonctionnera généralement, mais je peux voir une mince chance que 2 processus pourraient entrer dans la section critique.

public class TakeLongTimeToRefresh : ICacheItemRefreshAction 
{ 
    #region ICacheItemRefreshAction Members 

    public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason) 
    { 
     string lockKey = "lockKey"; 
     ICacheManager cm = CacheFactory.GetCacheManager(); 

     if (!cm.Contains(lockKey)) 
     { 
      Debug.WriteLine("Entering critical section"); 
      // Add a lock-key which will never expire for synchronisation. 
      // I can see a small window of opportunity for another process to enter 
      // the critical section here... 
      cm.Add(lockKey, lockKey, 
        CacheItemPriority.NotRemovable, null, 
        new NeverExpired()); 

      object newValue = SomeLengthyWebserviceCall(); 
      cm.Remove(removedKey); 
      Utilities.AddToCache(removedKey, newValue); 

      cm.Remove("lockkey"); 
     } 
    } 
} 

Est-il possible d'avoir une section critique garantie pour assurer que je ne l'appelle pas le service Web deux fois?

EDIT Je dois ajouter que je ne peux pas utiliser un fichier partagé, car les stratégies de déploiement l'empêcheront.

références stackoverflow:

+0

Peut-être une sorte de système de bague Token? – jp2code

Répondre

4

Vous devez impliquer une serrure externe acquisiton commun à tous. Par exemple, une table t dans SQL avec une ligne et un champ de verrouillage où vous un verrou avec:

set transaction isolation serializable; 
update t set lock = 1 where lock = 0; 

lignes de contrôle affectées et si son 1 vous avez le verrou, relâchez-le par la mise à jour de verrouillage à 0. Cela se répercute essentiellement sur le verrou de ligne de SQLServer, si deux démarrent en même temps, un seul verrouillera U après le verrou S, l'autre bloquera et retournera 0 lignes affectées (puisque la première transaction l'a retourné à 1).

+0

Je pense que c'est la bonne approche. Si EL Caching a jeté une exception si vous avez ajouté une clé existante, cela aurait le même effet. Cependant, comme ce n'est pas le cas, j'ai besoin de l'implémenter moi-même en SQL.Merci :) –

+6

Gardez à l'esprit que ce verrouillage n'est pas durable, si votre processus est défectueux après l'acquisition mais avant de libérer le verrou, il restera définitivement verrouillé. Un bon moyen de s'en sortir est de forcer les timeouts, ce qui signifie que si lock n'est pas libéré dans le temps défini, un demandeur peut l'obtenir même si lock = 1, quelque chose comme 'set lock = 1, locktime = getdate() où lock = 0 ou datediff (m, locktime, getdate())> 15' pour 15min – mmix

+0

@mmix Merci pour votre suggestion. Je l'utilise. Le seul problème est que je pense que la date "m" est pour des mois et non des minutes. Les minutes seraient "mi". Référence: https://msdn.microsoft.com/fr-fr/library/ms189794.aspx –

1

Je vous suggère de déplacer la logique pour créer/retourner une poignée de verrouillage à la base de données et combiner eux et cela garantira qu'il est toujours un processus ayant le verrou.

Ainsi, la base de données pourrait avoir une procédure stockée qui vous demandez un verrou, et soit il retournera résultat vide (sans succès) ou créé un nouvel enregistrement et le retourner.

Questions connexes