2

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
4

2 に答える 2

1

本質的にやろうとしているのは、キューであろうとなかろうと、マスターマスターレプリケーションであり、redis はそれをサポートしておらず、疑似コードには競合状態があります。ただやっている:

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

は、あなたがこれを行っている間に別のワーカーがジョブを引き受けることができ、2 人のワーカーが一度に作業することを意味します。redis はあなたのパターンには理想的ではないと思いますし、そのように機能するキュー サーバーも知りませんが、そのようなサーバーをあまり知らないので、きっとあると思います。

一度に 1 つのマスターだけがジョブを取得するように作業の負荷を分散する場合、それは可能ですが、本質的に 1 つではなく 2 つのキューができます。

于 2012-05-31T07:55:23.453 に答える
0

興味があります...すでにAWS環境にいる場合は、代わりにAmazonのSQSサービスを使用しないのはなぜですか?私は過去にそれを使って作業しましたが、それはお尻に少し苦痛だと気づきましたが、これはAmazonの最も成熟したサービスであり、このシナリオのために構築された目的です。

于 2012-06-01T16:20:46.623 に答える