J'ai besoin de trouver un mécanisme \ pattern de verrouillage d'objet récursif personnalisé pour un système distribué en C #. Essentiellement, j'ai un système multi-nœuds. Chaque nœud dispose d' autorisations d' écriture exclusives sur n éléments d'état. Le même état est également disponible en lecture seule sur au moins un autre nœud. Certaines écritures / mises à jour doivent être atomiques sur tous les nœuds, tandis que d'autres mises à jour finiront par devenir cohérentes via des processus de réplication en arrière-plan, des files d'attente, etc.
Pour les mises à jour atomiques, je recherche un modèle ou des échantillons qui me permettent efficacement de marquer un objet comme verrouillé pour les écritures que je peux ensuite distribuer, valider, restaurer, etc ... Puisque le système a des niveaux de concurrence élevés, Je suppose que je devrai pouvoir empiler des verrous qui expireront ou seront déroulés une fois les verrous libérés.
Les éléments de transaction ou de messagerie ne sont pas au centre de cette question, mais je les ai fournis pour un contexte supplémentaire. Cela dit, n'hésitez pas à exprimer les messages qui, selon vous, seraient nécessaires si vous le souhaitez.
Voici un vague échantillon de ce que j'envisageais bien que je sois ouvert à de nouvelles idées en dehors de la mise en œuvre de nouveaux produits
thing.AquireLock(LockLevel.Write);
//Do work
thing.ReleaseLock();
Je pensais utiliser des méthodes d'extension, qui pourraient ressembler à ceci
public static void AquireLock(this IThing instance, TupleLockLevel lockLevel)
{
//TODO: Add aquisition wait, retry, recursion count, timeout support, etc...
//TODO: Disallow read lock requests if the 'thing' is already write locked
//TODO: Throw exception when aquisition fails
instance.Lock = lockLevel;
}
public static void ReleaseLock(this IThing instance)
{
instance.Lock = TupleLockLevel.None;
}
Pour clarifier quelques détails ...
- Toutes les communications sont TCP / IP utilisant un protocole de requête / réponse binaire
- Il n'y a pas de technologies intermédiaires telles que les files d'attente ou les bases de données
- Il n'y a pas de nœud maître central. Dans ce cas, la disposition de verrouillage est définie par l'initiateur de la serrure et le partenaire qui honorera la demande avec une certaine forme de délai pour régir son comportement
Quelqu'un a des suggestions?
Réponses:
Merci pour les clarifications.
Dans ce cas, je recommanderais d'utiliser un modèle de publication / abonnement. Protocole de verrouillage distribué Chubby de Google (une implémentation de Paxos )
Je n'ai jamais utilisé Paxos (ou Chubby), mais il semble y avoir une implémentation open source ici .
Si cela ne fonctionne pas, vous pouvez implémenter votre propre version de Paxos en utilisant, par exemple, l'un des suspects habituels en termes de bibliothèques de messagerie: la bibliothèque de file d'attente de messages zéro , RabbitMQ ou ActiveMQ .
Réponse précédente:
La plupart des suggestions sur SO ( [A] , [B] ) vont pour l'utilisation d'une file d'attente de messages pour réaliser le verrouillage entre machines.
Votre
AcquireLock
méthode pousserait quelque chose identifiant l'objet verrou dans la file d'attente, vérifiant les instances précédentes de verrous avant de réussir. VotreReleaseLock
méthode supprimerait l'objet verrou de la file d'attente.L'utilisateur atlantis de SO suggère, dans ce post , le post de Jeff Key pour certains détails.
la source
Il me semble que vous avez ici quelques technologies mixtes:
communications (sur lesquelles vous comptez essentiellement comme étant 100% fiables ... ce qui peut être fatal)
verrouillage / exclusion mutuelle
délais d'attente (dans quel but)?
Un mot d'avertissement: les délais d'attente dans les systèmes distribués peuvent être lourds de dangers et de difficultés. S'ils sont utilisés, ils doivent être définis et utilisés très soigneusement car l'utilisation aveugle des délais d'attente ne résout pas un problème, elle reporte simplement la catastrophe. (Si vous voulez voir comment les délais d'attente doivent être utilisés, lisez et comprenez la documentation du protocole de communication HDLC. C'est un bon exemple d'utilisation appropriée et intelligente, en combinaison avec un système de codage de bits intelligent pour permettre la détection de choses comme la ligne IDLE) .
Pendant un certain temps, j'ai travaillé dans des systèmes distribués multiprocesseurs connectés via des liaisons de communication (pas TCP, autre chose). L'une des choses que j'ai apprises, c'est qu'en général, il y a des endroits dangereux pour la multi-programmation:
la dépendance aux files d'attente se termine généralement en larmes (si la file d'attente se remplit, vous avez des problèmes. À MOINS que vous puissiez calculer une taille de file d'attente qui ne se remplira jamais, auquel cas vous pourriez probablement utiliser une solution sans file d'attente)
la dépendance au verrouillage est douloureuse, essayez de penser s'il existe un autre moyen (si vous devez utiliser le verrouillage, regardez la littérature, le verrouillage distribué multiprocesseur a fait l'objet de nombreux articles acédémiques des 2-3 dernières décennies)
Si vous devez continuer à utiliser le verrouillage, alors:
Je suppose que vous n'utiliserez les délais d'attente que comme moyen de récupération de dernier recours, c'est-à-dire pour détecter une défaillance du système de communication sous-jacent. Je suppose en outre que votre système de communication TCP / IP a une bande passante élevée et peut être considéré comme une faible latence (idéalement zéro, mais cela ne se produit jamais).
Ce que je suggère, c'est que chaque nœud possède une liste de connectivité d'autres nœuds auxquels il peut se connecter. (Les nœuds ne se soucient pas d'où vient une connexion.) La population des tables auxquelles les nœuds peuvent se connecter est laissée comme une chose distincte à trier, vous n'avez pas dit si cela serait défini statiquement ou non. Des éléments tels que l'attribution des numéros de port IP où les connexions entreraient dans un nœud sont également ignorés de manière pratique - il peut y avoir de bonnes raisons d'accepter des demandes sur un seul port ou sur plusieurs ports. Cela doit être soigneusement examiné. Les facteurs incluront la mise en file d'attente implicite, la commande, l'utilisation des ressources, le type de système d'exploitation et les capacités.
Une fois que les nœuds savent à qui ils se connectent, ils peuvent envoyer à ce nœud une demande de verrouillage et doivent recevoir une réponse de verrouillage de ce nœud distant. Vous pouvez regrouper ces deux opérations dans un wrapper pour lui donner un aspect atomique. Cela a pour effet que les nœuds souhaitant acquérir un verrou feront un appel quelque chose comme:
les appels get_lock et release_lock devraient être quelque chose comme (en principe):
Avec un système de verrouillage distribué, vous devrez faire très attention que les unités de travail effectuées pendant le verrouillage sont petites et rapides car vous aurez de nombreux nœuds distants potentiellement bloqués en attente pour obtenir un verrou. Il s'agit en fait d'un système multiprocesseur / communication d'arrêt et d'attente qui est robuste mais qui n'a pas les meilleures performances possibles.
Une suggestion est d'adopter une approche complètement différente. Pouvez-vous utiliser un appel de procédure à distance où chaque appel RPC transporte un ensemble d'informations qui peuvent être traitées par le destinataire et qui supprime les besoins de verrous?
En relisant la question, il semble que vous ne vouliez pas vraiment vous soucier du côté communication des choses, vous voulez juste résoudre votre problème de verrouillage.
Ma réponse peut donc sembler un peu hors sujet, cependant, je pense que vous ne pouvez pas résoudre votre problème de verrouillage sans obtenir les bonnes pièces en dessous. Analogie: Construire une maison sur de mauvaises fondations la fait tomber ... Finalement.
la source
Votre question peut être facilement mise en œuvre à l'aide d'un cache distribué comme NCache. Ce dont vous avez besoin est un mécanisme de verrouillage pessimiste où vous pouvez acquérir un verrou à l'aide d'un objet. Ensuite, effectuez vos tâches et opérations et libérez le verrou pour que d'autres applications soient utilisées ultérieurement.
Jetez un œil au code suivant;
Ici, vous acquérez un verrou sur une clé spécifique, puis effectuez des tâches (allant d'une ou plusieurs opérations), puis libérez enfin le verrou lorsque vous avez terminé.
Tiré du lien: http://blogs.alachisoft.com/ncache/distributed-locking/
la source