2 votes

Mise en œuvre d'une file d'attente sur plusieurs serveurs maîtres redis

J'essaie de construire une file d'attente de tâches en utilisant deux serveurs maîtres redis dans deux zones de disponibilité EC2. Toutes les opérations LPUSH sont effectuées dans la couche applicative vers les deux machines maîtres dans les deux zones de disponibilité. Idéalement, je devrais utiliser La resque de GitHub mais resque ne semble pas avoir de notion de plusieurs maîtres dans plusieurs Z.

Je dois m'assurer qu'un seul travailleur travaille sur une tâche donnée. Certains travailleurs seront dans l'AZ 1A en train de parler à la machine redis en 1A, et d'autres seront dans l'AZ 1B en train de parler à la machine en 1B. Je dois éviter le scénario où un travailleur en 1A et un travailleur en 1B déquettent le même travail à partir de différents maîtres redis et essaient de travailler dessus simultanément.

Ce pseudo-code de travailleur présente-t-il des conditions de course que j'ai pu manquer ?

job_id = master1.BRPOPLPUSH "queue", "working"
m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"
completed = master1.ZSCORE "completed", job_id

if completed
  # must have been completed just now on other server, no-op
  master1.LREM "working", 0, job_id
  master1.del "lock.#{job_id}"
  master2.del "lock.#{job_id}"
elsif not m1lock or not m2lock
  # other server is working on it? We will put back at the end of our queue
  master1.LPUSH "queue", job_id
  master1.LREM "working", 0, job_id
  master1.del "lock.#{job_id}" if m1lock
  master2.del "lock.#{job_id}" if m2lock
else
  # have a lock, it's not complete, so do work
  do_work(job_id)

  now = Time.now.to_i
  master1.ZADD "completed", now, job_id
  master2.ZADD "completed", now, job_id

  master1.del "lock.#{job_id}"
  master2.del "lock.#{job_id}"

  master1.LREM "working", 0, job_id
  master2.LREM "queue", 0, job_id # not strictly necessary b/c of "completed"
end

1voto

Not_a_Golfer Points 8585

Ce que vous essayez de faire en substance est une réplication maître-maître, qu'il s'agisse d'une file d'attente ou de n'importe quoi d'autre, redis ne le supporte pas, et votre pseudo-code présente des conditions de course. Je ne fais que ça :

m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"

signifie qu'un autre travailleur peut prendre le travail pendant que vous faites cela, et deux travailleurs travailleront dessus en même temps. Je ne pense pas que redis soit idéal pour votre modèle, et je ne connais aucun serveur de file d'attente qui puisse fonctionner de cette façon, mais là encore, je ne connais pas beaucoup de serveurs de ce type, donc je suis sûr qu'il en existe.

Si vous équilibrez la charge de travail de manière à ce qu'un seul maître reçoive un travail à la fois, c'est possible, mais vous avez alors deux files d'attente en substance, et non une seule.

0voto

codemonkey Points 1756

Je suis curieux... si vous êtes déjà dans l'environnement AWS, pourquoi ne choisiriez-vous pas plutôt d'utiliser le service SQS d'Amazon ? J'ai déjà travaillé avec ce service dans le passé et je sais que c'est un peu un casse-tête, mais c'est le service le plus mature d'Amazon et il a été conçu pour ce scénario.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X