Как сохранить в Redis отсортированный набор с отметкой времени на стороне сервера в качестве оценки? - PullRequest
1 голос
/ 21 января 2020

Я хочу использовать отсортированный набор для хранения объектов, используя метку времени сервера redis в качестве оценки.

Я знаю, что могу использовать потоки Redis с * id, но в потоках Redis есть ограничения, в том числе я не могу редактировать объекты, я не могу использовать ранговую или лексикографическую сортировку, я не могу действительно удалить объекты в середине, объединения или пересечения и т. д. c.

Я хочу сделать это атомарно и использовать метку времени сервера redis так что я могу использовать несколько клиентов для ZADD, не беспокоясь о синхронизации часов c.

Как это сделать?

1 Ответ

1 голос
/ 21 января 2020

Решение заключается в использовании сценария Lua:

local time = redis.call('TIME')
local ts = time[1]..string.format('%06d', time[2])
return redis.call('ZADD', KEYS[1], ts, ARGV[1])

Здесь мы используем команду Redis TIME . Команда возвращает:

  • unix время в секундах
  • микросекунды

Таким образом, мы можем объединить эти два и использовать метку времени микросекунды. Нам нужно заполнить микросекундами нулями.

Поскольку отсортированные наборы хороши с целыми значениями до 2 ^ 53, наша временная метка безопасна вплоть до 2255 года.

Это Redis-Cluster-safe, поскольку мы храним в одном ключе. Чтобы использовать несколько ключей, обязательно поместите их на один и тот же узел, используя га sh теги , если вы хотите сравнить метки времени.

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

Здесь команда EVAL, простой ключ передачи и значение в качестве аргументов, нет необходимости создавать отсортированный набор перед рукой:

EVAL "local time = redis.call('TIME') local ts = time[1]..string.format('%06d', time[2]) return redis.call('ZADD', KEYS[1], ts, ARGV[1])" 1 ssetKey myVal

Как всегда, вы можете захотеть загрузите скрипт и используйте EVALSHA.

> SCRIPT LOAD "local time = redis.call('TIME') local ts = time[1]..string.format('%06d', time[2]) return redis.call('ZADD', KEYS[1], ts, ARGV[1])"
"81e366e422d0b09c9b395b5dfe03c03c3b7b3bf7"
> EVALSHA 81e366e422d0b09c9b395b5dfe03c03c3b7b3bf7 1 ssetKey myNewVal
(integer) 1

Примечание по версии Redis. Если вы используете:

  • Версия Redis до 3.2: извините, вы не можете использовать TIME (недетерминированная c команда), а затем писать с ZADD.
  • Версия Redis больше 3.2, но <5.0: добавьте <code>redis.replicate_commands() поверх скрипта. См. Сценарии как чистые функции
  • Redis 5.0 и выше: вы хороши.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...