环境 Redis 2.8.17
我们使用类似于redis文档中描述的模式,在RPOPLPUSH
下实现了可靠的队列但是,考虑到阻止性质,我们使用 BRPOPLPUSH ,并使用 LPUSH 来确保FIFO顺序。
制作人多个线程(来自多个服务器)使用 LPUSH 来推送项目。
消费者多个线程(来自多个服务器)使用 BRPOPLPUSH 来处理这些项目。
BRPOPLPUSH q processing-q
如记录所示,redis从队列'q'弹出项目,同时在'processing-q'中添加它们。
由于我们的应用程序具有多线程(异步)特性,当 消费者 完成处理时,我们无法控制。< / p>
因此,如果我们使用 LREM (根据文档)从 processing-q ,这只会删除 processing-q 的顶部元素。哪里无法保证,是否已删除了由相应 消费者 处理的实际元素。
因此,如果我们不做任何事情,那么 processing-q 会继续增长(食用内存),这是非常糟糕的恕我直言。
有任何建议或想法吗?
答案 0 :(得分:21)
您只需要在调用LREM时包含要删除的作业。
LREM采用以下形式:
LREM queue count "object"
它将从队列中删除等于&#34; object&#34; 的 count 项。因此,要删除您的消费者线程正在处理的特定作业,请执行此类操作。
LREM processing-q 1 "job_identifier"
有关详细信息,请参阅此处的文档:http://redis.io/commands/lrem
然后,为了处理崩溃的消费者和已放弃的作业,您可以使用SETEX创建具有过期的锁定,并定期检查没有锁定的作业。
所以整个过程看起来像这样:
<强>生产者强>
RPUSH q "job_identifier"
<强>消费强>
SETEX lock:processing-q:job_identifier 60
(先设置锁定以避免竞争条件)BRPOPLPUSH q processing-queue
LREM processing-queue "job_identifier"
过期的工作监控
LRANGE processing-queue 0 -1
GET lock:processing-q:job_identifier
LREM processing-queue "job_identifier"
RPUSH q "job_identifier"
@NotAUser发布了一个开源java实现,在这里:https://github.com/graknlabs/redisq/tree/master/src/main/java/ai/grakn/redisq
答案 1 :(得分:8)
我将采用的方法是使用每个消费者的处理q(例如 processing-q:consumer-id )。这将解决您当前的问题,但您仍然需要以某种方式处理崩溃的消费者。为此,我建议您保留每个消费者最后一次弹出任务并定期检查超时。如果使用者已达到超时,则将其任务移回主队列并删除其队列。
答案 2 :(得分:4)
在类似的项目中,我使用主机名和工作进程ID作为备份队列。每个工作人员都有自己的备份队列,如果工作人员死亡,则该项目不会丢失。
查看README和implementation了解详情。
答案 3 :(得分:0)
除了建议的解决方案之外,您还可以ltrim
将处理队列设置为对您的服务有意义的数量。这将确保处理队列永远不会超出比例。
但如果达到修剪限制,你将开始丢失物品。这可能是也可能不适用于您的用例。