在我的组织中,我们有许多 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 项目。但是,以下步骤将帮助您解决问题,即使在堆栈的其他部分也是如此(这很可能,因为没有类似于上述的已知问题(。
检查正在发生的事情的步骤:
- 等待一个客户端停止。
- 使用
LLEN
命令验证列表中是否确实存在元素。 CLIENT LIST
检查是否确实列出了您的客户端,正在执行阻止弹出(您将看到命令名称(,并检查回复的大小,以查看是否是您的客户端实际上没有消耗它得到的回复。
随机备注:
- Redis 2.8.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();
}