두 개의 EC2 가용성 영역에 두 개의 redis 마스터 서버를 사용하여 작업 대기열을 작성하려고합니다. 모든 LPUSH 작업은 두 AZ의 두 마스터 시스템 모두에 대해 응용 프로그램 계층에서 수행됩니다. 이상적으로는 GitHub's resque을 사용하지만 여러 AZ에서 복수 마스터의 does not seem to have any notion을 리졸브하는 것이 이상적입니다.여러 redis 마스터 서버에서 큐 구현
한 작업자 만 특정 작업을하고 있는지 확인해야합니다. 일부 근로자는 1A 1A에서 redis 기계와 1A로 통화하고 일부는 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
SETNX는 잠금을 확보 할 수없는 경우 실패를 반환하므로 이론적으로 동시에 실행하고 작업을 수행하지 않으면 둘 다 실패하게됩니다. 그래서 나는 괜찮을 것이라고 생각합니다 (한 경우에 대기열에서 단지 1 번만 반복적으로 잠글 수없는 상황에서 끝낼 수 있기 때문에 일종의 백 오프 기간을 원할 수 있습니다. 그러나 현실 세계에서 대기열의 길이는 가변적이므로 머물러 있을지는 의문입니다. 매우 긴 경우). 나는 redis가 이것을 지원하지 않는다는 것을 알기 때문에 EC2 머신과 AZ는 실패 할 수 있기 때문에 어플리케이션 레벨에서 그것을 할 필요가 있습니다. ... – esilver
클라이언트가 가장 먼저 마스터가 아닌 가장 먼저 마스터를 처리하는 경우 그것은 연쇄 복제 (마스터 - 슬레이브/마스터 - 슬레이브)와 정말로 다른가요? –
내 실제 코드에서 클라이언트는 가장 가까운 마스터 (자신의 AZ에있는 마스터)에게 연락을 시도하고, 그렇지 않으면 다른 AZ의 마스터에 갈 것입니다. (2011 년 4 월 Amazon Cloudpocalypse에서 FWIW를 사용하면 두 개의 AZ 중 하나에서 마스터 시스템을 완전히 종료해야했기 때문에이 방법을 사용할 수 있습니다 ...) – esilver