В моей организации у нас есть ряд работников redis для наших критических задач. Обычно, один или два раза в день, наши работники прекращают обработку очередей.
Код выглядит примерно так:
while ($item = $redis->blpop(array('someQueue', 'anotherQueue'), 3600)) { someFunction(); }
Если вы видите, что не так много происходит с точки зрения кода, но время от времени очередь начинает нарастать, и рабочий не выталкивает какой-либо элемент из очереди. Установка тайм-аута для blpop
совсем не полезна, поскольку мы исходим из того, что проблема связана с соединением клиента redis.
На данный момент мы создали несколько слушателей, которые предупреждают нас, когда очередь создается, а затем мы перезапускаем рабочих, но проблема все еще сохраняется. Мы также можем установить тайм-аут для нашего клиента redis, но опять же это не идеальное решение.
Наш вопрос похож на ошибку в реализации очереди сообщений, используя redis, ошибку при использовании BLPOP, но мы не получаем никаких ошибок. Рабочий просто резко останавливается.
Информация
Сервер Redis: 2.8.2
PHP Redis: phpredis
Рабочие, которые работали в течение длительного времени, прекратили обработку очереди. После запуска CLIENT LIST
мы заметили, что эти рабочие имеют большой простор по сравнению с остальными, а их флаг установлен на N
вместо b
. Что может быть причиной этого?
Проблема была в someFunction()
. Был фрагмент кода, из-за которого функция не возвращала контроль, из-за которого клиент долгое время находился на холостом ходу, и, следовательно, флаг «N» при запуске CLIENT LIST
.
Я предлагаю проверить, есть ли проблема, и сообщить о проблеме в проект Redis как проблему, если вы найдете что-то серверное. Однако следующие шаги помогут вам устранить проблему, даже если в какой-либо другой части вашего стека (что, вероятно, так как нет известных проблем, подобных описанным выше).
Шаги, чтобы проверить, что происходит:
LLEN
команды LLEN
. CLIENT LIST
что на самом деле есть ваш клиент, выполняющий блокировку (вы увидите имя команды) и проверьте размер ответа, чтобы узнать, является ли это ваш клиент, который фактически не потребляет отвечает. Случайные замечания:
У нас бы другая проблема: если сервер приложений теряет связь с сервером 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(); }