Как сохранить в Redis отсортированный набор с отметкой времени на стороне сервера в качестве оценки?

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

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

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

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

1 ответ

Решение

Решение - использовать скрипт 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, поскольку мы храним в одном ключе. Чтобы использовать несколько ключей, убедитесь, что они размещены на одном узле с помощью хэш-тегов, если вы хотите сравнить временные метки.

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

Здесь 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 (недетерминированная команда), а затем напишите с ZADD.
  • Версия Redis выше 3.2, но < 5.0: Добавить redis.replicate_commands()поверх сценария. Смотрите скрипты как чистые функции
  • Redis 5.0 и выше: все хорошо.
Другие вопросы по тегам