BLPpop 会在一段时间后停止处理队列


blpop stops processing queue after a while

在我的组织中,我们有许多 Redis 工作人员来执行我们的关键任务。通常,一天一两次,我们的工人会停止处理队列。

代码基本上如下所示:

while ($item = $redis->blpop(array('someQueue', 'anotherQueue'), 3600)) {
    someFunction();
}

如果你看到,在代码方面没有发生太多事情,但每隔一段时间,队列就会开始建立,工作人员不会从队列中弹出任何项目。设置blpop超时根本没有用,因为我们假定问题出在 Redis 客户端连接上。

目前,我们已经设置了一些侦听器,当队列建立时会提醒我们,然后我们重新启动工作线程,但问题仍然存在。我们也可以为 redis 客户端设置超时,但话又说回来,这不是一个理想的解决方案。

  • 还有其他人遇到过这种情况吗?
  • 可能有什么问题?
  • 我们做错了什么吗?

我们的问题类似于使用 redis 实现消息队列时的错误,使用 BLPOP 时的错误,但我们没有得到任何错误。工人只是突然停止。

信息

Redis 服务器:2.8.2

PHP Redis: phpredis

更新 #1

长时间运行的工作线程已停止处理队列。运行 CLIENT LIST 后,我们注意到与其他工作人员相比,这些工作人员的空闲时间很长,并且他们的标志设置为 N 而不是 b 。这背后的原因可能是什么?

更新 #2

问题出在someFunction().有一段代码导致函数不返回控制权,由于客户端长时间空闲,因此在运行CLIENT LIST时出现"N"标志。

我建议验证是否存在问题,并在发现服务器端问题时将问题报告给 Redis 项目。但是,以下步骤将帮助您解决问题,即使在堆栈的其他部分也是如此(这很可能,因为没有类似于上述的已知问题(。

检查正在发生的事情的步骤:

  1. 等待一个客户端停止。
  2. 使用 LLEN 命令验证列表中是否确实存在元素。
  3. CLIENT LIST检查是否确实列出了您的客户端,正在执行阻止弹出(您将看到命令名称(,并检查回复的大小,以查看是否是您的客户端实际上没有消耗它得到的回复。

随机备注:

  1. Redis 2.8.2.太旧了,建议升级。
  2. phpredis 可能有可能导致此问题的错误,如果它与 Redis 服务器一样旧。

我们会有一个不同的问题:如果应用程序服务器暂时失去与 Redis 服务器的连接,Redis 句柄将变得无效(顺便说一句,我们希望这样做 - 这不是一个错误(。尽管您的问题有所不同,但我们使用的解决方法可能也适合您:

你可以做这样的事情:

while (true) {
    // The factory method below will check whether handle is valid. If not, create a new one and return
    $redis = MyRedisFactory::getInstance(); 
    $item = $redis->blpop(array('someQueue', 'anotherQueue'), 3600);
    someFunction();
}