2 つの EC2 アベイラビリティ ゾーンで 2 つの Redis マスター サーバーを使用してジョブ キューを構築しようとしています。すべての LPUSH 操作は、アプリケーション層で両方の AZ の両方のマスター マシンに対して行われます。理想的には、GitHub の resqueを使用することになりますが、resque には、複数の AZ に複数のマスターがあるという概念がないようです。
特定のジョブで作業するワーカーが 1 人だけであることを確認する必要があります。一部のワーカーは AZ 1A で 1A の redis マシンと通信し、一部のワーカーは AZ 1B で 1B のマシンと通信します。1A のワーカーと 1B のワーカーの両方が異なる redis マスターから同じジョブをデキューし、同時に作業しようとするシナリオを回避する必要があります。
このワーカー疑似コードには、見逃した可能性のある競合状態がありますか?
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