2011-10-02 48 views
4

我有一個隊列接口,我想在redis中實現。訣竅是,每個工人可以在N秒後索取一件物品,然後假定工人已經墜毀,並且該物品需要再次獲得索賠。完成後,工作人員有責任取出物品。你如何在redis中做到這一點?我正在使用phpredis,但這是無關緊要的。Redis隊列與索賠到期

回答

3

爲了實現在Redis的一個簡單的隊列,可以用來重新提交損毀的作業我想嘗試這樣的事:

  • 1清單「up_for_grabs」
  • 1清單「being_worked_on」
  • 汽車即將到期的鎖

工人試圖抓住一個工作會做這樣的事情:

timeout = 3600 
#wrap this in a transaction so our cleanup wont kill the task 
#Move the job away from the queue so nobody else tries to claim it 
job = RPOPLPUSH(up_for_grabs, being_worked_on) 
#Set a lock and expire it, the value tells us when that job will time out. This can be arbitrary though 
SETEX('lock:' + job, Time.now + timeout, timeout) 
#our application logic 
do_work(job) 

#Remove the finished item from the queue. 
LREM being_worked_on -1 job 
#Delete the item's lock. If it crashes here, the expire will take care of it 
DEL('lock:' + job) 

而且我們現在每隔一段時間就可以抓住我們的列表並檢查那裏的所有工作實際上是否有鎖。 如果我們發現任何沒有鎖的工作,這意味着它過期了,我們的工作人員可能會崩潰。 在這種情況下,我們將重新提交。

這將是該僞代碼:

loop do 
    items = LRANGE(being_worked_on, 0, -1) 
    items.each do |job| 
     if !(EXISTS("lock:" + job)) 
      puts "We found a job that didn't have a lock, resubmitting" 
      LREM being_worked_on -1 job 
      LPUSH(up_for_grabs, job) 
     end 
    end 
    sleep 60 
end 
+0

我希望你在第一個模塊中不需要MULTI-EXEC。 – chx

+0

是的,那只是一個剩下的評論。但是你是對的,我們可能需要一個,所以清理過程不會殺死任何東西 –

+1

我認爲你的解決方案存在問題,根據文檔LREM是O(N),所以它會損害性能時,大名單。如果可能,最好使用O(1)替代方案。 –

1

您可以在Redis中使用[SETNX][1]設置標準同步鎖定方案。基本上,你使用SETNX來創建一個每個人都試圖獲得的鎖。要釋放鎖,您可以使用它DEL,並且您還可以設置一個EXPIRE以使鎖可釋放。這裏還有其他一些考慮因素,但是在分佈式應用程序中設置鎖定和關鍵部分並沒有什麼特別之處。

+0

嗯,我問了一下隊列。這是關於鎖。不知道如何從鎖到隊列。 – chx

+0

您應該使用鎖來表示是否聲明某個項目。如果鎖定到期,現在可以再次申報。在工人解鎖資源之前,您將其刪除,然後釋放鎖。這就是我在Redis中如何做到這一點的。 –