Redis BRPOP и ZADD атомарно

Мне нужно BRPOP, а затем добавить полученное значение в отсортированный набор с помощью ZADD. Я вижу два решения для этого (я использую Ruby):

  1. Напишите сценарий Lua, который выполняет эти две операции. Однако скрипты Lua не могут блокироваться, так как тем временем они будут удерживать весь сервер. Так что это решение не работает;
  2. Используйте блок multi { ... } redis-rb. Однако здесь я не могу использовать значение popped в команде ZADD, так как redis-rb не реализует этот блок.

С ними у меня остался только неатомарный способ добиться этого, то есть использовать redis-rb для последовательного запуска этих команд. Однако мне действительно нужна атомарность здесь. Каким был бы способ добиться этого?


person linkyndy    schedule 20.04.2018    source источник


Ответы (3)


TL;DR невозможное возможно.

Вы можете, если вы не зациклены на всплывающих окнах из списков, проверить как мой новый модуль, так и новый блестящий запрос на включение в ядро ​​​​Redis.

  1. Модуль Ze POP: https://github.com/itamarhaber/zpop
  2. Запрос на слияние № 4879 «Реализует [B]Z[REV]POP и соответствующие модульные тесты»: https://github.com/antirez/redis/pull/4879
person Itamar Haber    schedule 02.05.2018
comment
Модуль Redis кажется более мощным, чем скрипты. Я должен обновить свои знания о модуле Redis :) - person for_stack; 03.05.2018
comment
Спасибо за ваш ответ. Я зациклен на списках, а также, как упоминалось ранее, я хотел бы полагаться только на стандартный Redis, так как я создаю библиотеку, которую можно легко подключить к любому приложению. - person linkyndy; 03.05.2018
comment
Модули @for_stack намного мощнее, но Lua проще и доступнее (т. е. не каждый разработчик может разрабатывать на C модуль Redis). Но модули OTO - это так весело - если вам нужна помощь, вы знаете, как меня найти ;) - person Itamar Haber; 03.05.2018
comment
@linkyndy попался. Итак, как только ZPOP станет стандартным Redis, вы сможете его использовать. Тем не менее, возможно, стоит подумать о дополнении ZPOP возможностью извлекать из списков и помещать в отсортированный набор, а также чем-то вроде BZPOPZADD. - person Itamar Haber; 03.05.2018

Вы можете обернуть RPOP и ZADD в сценарий Lua, например. RPOPZADD, чтобы запустить их атомарно, и выполнить некоторую работу на стороне клиента, чтобы имитировать поведение блокировки.

Ниже приведен псевдокод:

while (true) {
    bool ret = redis.eval(RPOPZADD);    // return immediately
    if (!ret) {
        // No item in the list, wait for a while
        sleep(1);
    }
}
person for_stack    schedule 20.04.2018
comment
Я бы предпочел использовать более надежное решение, основанное на существующих функциях, чем использовать собственный метод. Я все еще надеюсь, что он существует, и я скучаю по нему... - person linkyndy; 20.04.2018
comment
Если вы не хотите запускать цикл на стороне клиента, вы можете попробовать более сложный метод с функцией уведомления о ключевом пространстве. См. guara/49935299?noredirect=1#comment86905474_49935299">мой комментарий к другому похожему вопросу для получения подробной информации. - person for_stack; 20.04.2018
comment
Это выглядит многообещающе, но я разрабатываю инструмент, который должен работать по принципу plug-and-play, поэтому настройка Redis не является тем направлением, которому я стремлюсь следовать. Кроме того, это сильно усложняет вещи, что мне не обязательно. - person linkyndy; 20.04.2018
comment
Естественно, я тоже проголосовал за этот, но добавил и свой. - person Itamar Haber; 03.05.2018

Вы не указали причину, по которой вам нужен отсортированный набор, если вы можете обойти это и использовать список вместо этого, вы можете использовать BRPOPLPUSH атомарно переместить элемент в другой список и отсортировать его позже не атомарным образом.

Другой вариант — написать модуль Redis, который сделает это за вас — модули, блокирующие операции.

person Ofir Luzon    schedule 20.04.2018
comment
Мне нужен отсортированный набор, потому что мне нужно извлечь элемент и добавить его в место, где я могу сохранить также текущее время вместе с добавленным элементом. Мне бы очень хотелось использовать BRPOPLPUSH, но я не могу в данных обстоятельствах. Что касается модулей... это будет сильно зависеть от установки Redis, что будет мешать переносимости и простоте моего инструмента. - person linkyndy; 22.04.2018
comment
@linkyndy звучит так, будто вы уже добавили их по порядку. Если это только метка времени, почему бы просто не добавить или не добавить строку данных? - person Ofir Luzon; 22.04.2018
comment
Потому что мне нужна отметка времени, когда было выполнено BRPOPLPUSH. Единственным местом, где я могу это сделать, было бы место назначения BRPOPLPUSH, но это создало бы излишнее количество отдельных ключей, которые нужно было бы обрабатывать после. - person linkyndy; 24.04.2018
comment
@linkyndy в таком случае разбейте его на 3 операции. Выталкивайте, добавляйте TS и нажмите. Загрузите его как lua ​​для атомарности и разгрузки вычислений на стороне сервера. (вам придется принести TS из дома или использовать повторяющиеся эффекты, чтобы использовать команду TIME) - person Ofir Luzon; 25.04.2018
comment
@OfirLuzon, хотя ты был моим другом ... IQ и все такое ... посмотри мой ответ об использовании модуля и новом PR, который я сделал - person Itamar Haber; 03.05.2018
comment
@OfirLuzon Мне также нужна блокирующая часть, которую я действительно не хочу обрабатывать вручную на клиенте. - person linkyndy; 03.05.2018