BLPOP
BLPOP
BLPOP key [key ...] timeout
- Доступно с версии:
- 2.0.0
- Сложность по времени:
- O(N), где N — количество переданных ключей.
- Категории ACL:
-
@write,@list,@slow,@blocking,
BLPOP — это примитив блокирующей очереди. Он является блокирующей версией LPOP, поскольку блокирует соединение, когда нет элементов для извлечения из любого из заданных списков. Элемент извлекается из начала первого непустого списка, и ключи проверяются в заданном порядке.
Неблокирующее поведение
Когда BLPOP вызывается, если хотя бы один из указанных ключей содержит непустой список, элемент извлекается из начала списка и возвращается вызывающему объекту вместе с key , из которого он был извлечен.
Ключи проверяются в заданном порядке. Предположим, что ключ list1 не существует, а list2 и list3 содержат непустые списки. Рассмотрим следующую команду:
BLPOP list1 list2 list3 0
BLPOP гарантирует возвращение элемента из списка, хранящегося в list2 (поскольку это первый непустой список при проверке list1, list2 и list3 в этом порядке).
Блокирующее поведение
Если ни один из указанных ключей не существует, BLPOP блокирует соединение до тех пор, пока другой клиент не выполнит операцию LPUSH или RPUSH над одним из ключей.
После появления новых данных в одном из списков клиент возвращается с именем ключа, его разблокировавшего, и извлеченным значением.
Когда BLPOP приводит к блокировке клиента и задан ненулевой таймаут, клиент разблокируется, возвращая nil многоэлементное значение, когда заданный таймаут истекает без операции push над хотя бы одним из указанных ключей.
Аргумент таймаута интерпретируется как двойное значение, задающее максимальное время блокировки в секундах. Таймаут нулевой означает неограниченное ожидание.
Порядок обработки ключей, клиентов и элементов
- Если клиент пытается заблокироваться по нескольким ключам, но хотя бы один ключ содержит элементы, возвращаемая пара ключ/элемент — это первый ключ слева направо, имеющий один или более элементов. В этом случае клиент не блокируется. Например,
BLPOP key1 key2 key3 key4 0, предполагая, что обаkey2иkey4непустые, всегда вернет элемент изkey2. - Если несколько клиентов заблокированы для одного и того же ключа, первым будет обработан клиент, который ожидал дольше (то есть, который заблокировался раньше). После разблокировки клиент не сохраняет приоритет; при повторной блокировке с помощью следующего вызова
BLPOPон будет обработан в соответствии с количеством уже заблокированных клиентов для того же ключа (все они будут обработаны до него в порядке их блокировки). - Когда клиент блокируется для нескольких ключей одновременно, и элементы доступны одновременно в нескольких ключах (из-за транзакции или скрипта Lua, добавившего элементы в несколько списков), клиент будет разблокирован с помощью первого ключа, который получил операцию push (предполагая, что в этом ключе достаточно элементов для обслуживания нашего клиента, так как могут быть и другие ожидающие клиенты). По существу, после выполнения каждой команды Redis создает список всех ключей, получивших данные И имеющих хотя бы одного заблокированного клиента. Список упорядочен по времени появления новых элементов, от первого ключа, получившего данные, до последнего. Для каждого обработанного ключа Redis обслуживает всех ожидающих его клиентов в порядке очереди FIFO, пока в этом ключе есть элементы. Когда ключ пуст или больше нет ожидающих клиентов для этого ключа, обрабатывается следующий ключ, получивший новые данные в предыдущей команде/транзакции/скрипте, и так далее.
Поведение BLPOP при одновременном добавлении нескольких элементов в список
Иногда список может получить несколько элементов в рамках одной концептуальной команды:
- Многоаргументные операции добавления, такие как
LPUSH mylist a b c. - После выполнения
EXECблокаMULTIс несколькими операциями добавления в один и тот же список. - Выполнение скрипта Lua с Redis 2.6 или более поздней версии.
При добавлении нескольких элементов в список, где есть заблокированные клиенты, поведение отличается для Redis 2.4 и Redis 2.6 или более поздних версий.
В Redis 2.6 команда, выполняющая несколько операций добавления, выполняется, а только после выполнения команды обслуживаются заблокированные клиенты. Рассмотрим эту последовательность команд.
Client A: BLPOP foo 0 Client B: LPUSH foo a b c
Если вышеупомянутое условие выполняется с использованием сервера Redis 2.6 или более поздней версии, клиент A получит элемент c, потому что после команды LPUSH список содержит c,b,a, поэтому взятие элемента слева означает возвращение c.
Вместо этого Redis 2.4 работает иначе: клиенты обслуживаются в контексте операции push, поэтому, как только LPUSH foo a b c начинает добавлять первый элемент в список, он будет передан клиенту A, который получит a (первый добавленный элемент).
Поведение Redis 2.4 создает множество проблем при репликации или сохранении данных в файле AOF, поэтому в Redis 2.6 было введено гораздо более общее и семантически простое поведение для предотвращения проблем.
Обратите внимание, что по той же причине скрипт Lua или блок MULTI/EXEC может добавлять элементы в список, а затем удалять список. В этом случае заблокированные клиенты не будут обслуживаться и будут продолжать блокироваться, пока данные не появятся в списке после выполнения одной команды, транзакции или скрипта.
BLPOP внутри транзакции MULTI / EXEC
BLPOP может использоваться с пипелингом (отправка нескольких команд и чтение ответов партиями), однако этот подход имеет смысл почти исключительно, когда это последняя команда в пипелайне.
Использование BLPOP внутри блока MULTI / EXEC не имеет большого смысла, так как потребовалось бы заблокировать весь сервер для выполнения блока атомарно, что, в свою очередь, не позволяет другим клиентам выполнять операцию push. По этой причине поведение BLPOP внутри MULTI / EXEC при пустом списке — это возвращение nil многоэлементного ответа, что аналогично тому, что происходит при достижении таймаута.
Если вы любите научную фантастику, представьте себе время, текущее с бесконечной скоростью внутри блока MULTI / EXEC...
Возврат
Многоэлементный ответ: конкретно:
nilмногоэлементный ответ, когда ни один элемент не мог быть извлечён, и истек таймаут.- Двухэлементный многоэлементный ответ, где первый элемент — имя ключа, из которого был извлечён элемент, а второй — значение извлечённого элемента.
Примеры
redis> DEL list1 list2 (integer) 0 redis> RPUSH list1 a b c (integer) 3 redis> BLPOP list1 list2 0 1) "list1" 2) "a"
Надежные очереди
Когда BLPOP возвращает элемент клиенту, он также удаляет элемент из списка. Это означает, что элемент существует только в контексте клиента: если клиент аварийно завершает работу при обработке возвращённого элемента, он теряется навсегда.
Это может быть проблемой в некоторых приложениях, где требуется более надёчная система обмена сообщениями. В этом случае ознакомьтесь с командой BRPOPLPUSH, которая является вариантом BLPOP , добавляющей возвращённый элемент в целевой список перед возвратом клиенту.
Паттерн: Уведомление о событиях
Используя блокирующие операции со списками, можно создавать различные блокирующие примитивы. Например, для некоторых приложений может потребоваться заблокироваться в ожидании элементов в наборе Redis, чтобы при добавлении нового элемента в набор его можно было получить без опроса. Это потребовало бы блокирующей версии SPOP, которая недоступна, но с помощью блокирующих операций со списками мы легко можем выполнить эту задачу.
Потребитель будет выполнять:
LOOP forever
WHILE SPOP(key) returns elements
... process elements ...
END
BRPOP helper_key
END
В то время как на стороне производителя мы будем просто использовать:
MULTI SADD key element LPUSH helper_key x EXEC
История
- Начиная с версии Redis 6.0.0:
timeoutинтерпретируется как двойное, а не целое число.
© 2006–2022 Salvatore Sanfilippo
Licensed under the Creative Commons Attribution-ShareAlike License 4.0.
https://redis.io/commands/blpop/