2011-10-02 50 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中如何做到这一点的。 –