Автоинкремент в Redis - PullRequest
       6

Автоинкремент в Redis

6 голосов
/ 16 марта 2011

Я начинаю использовать Redis и столкнулся со следующей проблемой.

У меня есть группа объектов, скажем, Messages в моей системе.Каждый раз, когда подключается новый User, я делаю следующее:

  1. INCR некоторую глобальную переменную, скажем g_message_id, и сохраняю возвращаемое значение INCR (текущее значение g_message_id).

  2. LPUSH новое сообщение (включая id и фактическое сообщение) в список.

Другие клиенты используют значениеиз g_message_id, чтобы проверить, есть ли новые сообщения для получения.

Проблема в том, что один клиент может INCR g_message_id, но не успеть LPUSH сообщение, прежде чем другой клиент попытается его прочитать, предполагая, что есть новое сообщение.

Другими словами, я ищу способ сделать эквивалент добавления строк в SQL и иметь автоматически увеличиваемый индекс для работы.

Примечания :

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

Моя ситуация в действительности немного сложнее, это более простая версия.

Текущее решение :

Лучшее решение, которое я придумал, и что я планирую сделать, это использовать WATCH и Transactions, чтобы попытаться выполнитьСам "autoincrement".

Но это такой распространенный вариант использования в Redis, что я удивлен, что не существует ответа на него, поэтому я волнуюсь, что делаю что-то не так.

Ответы [ 3 ]

7 голосов
/ 16 марта 2011

Если я правильно читаю, вы используете g_message_id как в качестве последовательности идентификаторов, так и в качестве флага, указывающего на наличие новых сообщений.Один из вариантов состоит в том, чтобы разделить это на две переменные: одну для назначения идентификаторов сообщений, а другую как флаг, чтобы сигнализировать клиентам о доступности нового сообщения.

Клиенты могут затем сравнить текущее / предыдущее значение g_new_message_flag чтобы узнать, когда появятся новые сообщения:

> INCR g_message_id
(integer) 123

# construct the message with id=123 in code

> MULTI
OK
> INCR g_new_message_flag
QUEUED
> LPUSH g_msg_queue "{\"id\": 123, \"msg\": \"hey\"}"
QUEUED
> EXEC

Возможная альтернатива, если ваши клиенты могут ее поддерживать : возможно, вы захотите заглянуть в Redis publish/ Подписаться команды, например, пользователи могут публиковать уведомления о новых сообщениях и подписываться на один или несколько каналов сообщений для получения уведомлений.Вы можете оставить g_msg_queue , чтобы при необходимости поддерживать резервирование N сообщений для новых клиентов.

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

 # assuming the message queue contains "123", "456", "789"..
 # a client detects there are new messages, then runs this:

> WATCH g_msg_queue
OK
> LRANGE g_msg_queue 0 100000
QUEUED
> DEL g_msg_queue
QUEUED
> EXEC
1) 1) "789"
   2) "456"
   3) "123"
2) (integer) 1

Обновление 2 : с учетом новой информациивот что я хотел бы сделать:

  1. Пусть ваши клиенты писателя используют RPUSH для добавления новых сообщений в список.Это позволяет клиентам считывателя начинать с 0 и выполнять итерацию по списку для получения новых сообщений.
  2. Читатели должны помнить только индекс последнего сообщения, полученного ими из списка.
  3. Читатели читают g_new_message_flag , чтобы узнать, когда следует выбирать из списка.
  4. Каждый клиент-читатель будет затем использовать " LRANGE list index limit " для извлечения новых сообщений.Предположим, что клиент-читатель просмотрел в общей сложности 5 сообщений, и для получения следующих 10 сообщений он запустил бы « LRANGE g_msg_queue 5 15 ».Предположим, 3 возвращены, поэтому он запоминает индекс 8 .Вы можете установить ограничение настолько большим, насколько хотите, и можете просматривать список небольшими партиями.
  5. Клиент-жнец должен установить в списке WATCH и удалить его внутри транзакции,прерывание, если какой-либо клиент одновременно читает с него.
  6. Когда клиент считывателя пытается LRANGE и получает 0 сообщений, он может предположить, что список был усечен, и сбросить его индекс на 0 .
5 голосов
/ 16 марта 2011

Вам действительно нужны уникальные последовательные идентификаторы?Вы можете использовать UUID для уникальности и отметки времени для проверки новых сообщений.Если вы синхронизируете часы на всех ваших серверах должным образом, то временные метки с разрешением в одну секунду должны работать очень хорошо.

Если вам действительно нужны уникальные последовательные идентификаторы, вам, вероятно, придется установить Билетный сервер в стиле Flickr для правильного управления центральным списком идентификаторов.Это, по сути, переместит ваш g_message_id в базу данных с правильной обработкой транзакций.

0 голосов
/ 22 ноября 2018

Вы можете имитировать автоматическое увеличение уникального ключа для новых строк. Просто используйте DBSIZE, чтобы получить текущее количество строк, затем в своем коде увеличьте это число на 1 и используйте это число в качестве ключа для новой строки. Это просто и атомарно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...