【问题标题】:Redis queue with claim expire声明过期的 Redis 队列
【发布时间】:2011-12-19 22:00:56
【问题描述】:

我有一个我想在 redis 中实现的队列接口。诀窍是每个工人都可以在假定工人已经崩溃并且需要再次索取该物品之后的 N 秒内认领一件物品。完成后移除物品是工人的责任。你会如何在redis中做到这一点?我正在使用 phpredis,但这有点无关紧要。

【问题讨论】:

    标签: redis


    【解决方案1】:

    要在 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
    

    【讨论】:

    • 我希望您在第一个块中不需要 MULTI-EXEC。
    • 是的,那只是留下的评论。但你是对的,我们可能需要一个这样清理过程不会杀死任何东西
    • 我认为您的解决方案存在问题,根据文档 LREM 为 O(N),因此在处理大列表时会损害性能。如果可能,最好使用 O(1) 替代方案。
    • @MarcSeeger 包装对 RPOPLPUSH 和 SETEX 的调用的 MULTI-EXEC 将无济于事,因为您需要 RPOPLPUSH 为 SETEX 调用返回的值。从 Redis 2.6 开始,这可以使用 LUA 脚本来解决。
    【解决方案2】:

    您可以使用[SETNX][1] 在 Redis 中设置标准同步锁定方案。基本上,您使用SETNX 创建每个人都试图获取的锁。要释放锁,你可以DEL它,你也可以设置一个EXPIRE来使锁可以释放。这里还有其他注意事项,但在分布式应用程序中设置锁定和临界区并没有什么特别之处。

    【讨论】:

    • 嗯,我问的是队列。这是关于一把锁的。不知道如何从锁到队列。
    • 你应该使用一个锁来表示一个项目是否被认领。如果锁过期,现在可以再次申领。在工作人员解锁资源之前,您将其移除,然后释放锁。这就是我在 Redis 中的做法。
    猜你喜欢
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    相关资源
    最近更新 更多