2015-03-05 7 views
0

Представьте следующий сценарий:Redis в качестве LRU состояния гонки кэш

  1. Client # 1 запрашивает объект А из Redis
  2. Redis ответы с нулевым
  3. Client # 1 запрашивает объект А из базы данных
  4. базы данных возвращает объект A
  5. Client # 1 сохраняет объект А в Redis

Все работает отлично. Давайте добавим еще один клиент между 4 и 5:

  1. Client # 1 запрашивает объект А из Redis
  2. Redis ответы с нулевым
  3. Client # 1 запрашивает объект А из базы данных
  4. базы данных возвращает объект

    • Client # 2 запрашивает объект А из Redis
    • Redis ответы с нулевым
    • Client # 2 запрашивает объект А из dtabase
    • базы данных возвращает объект
    • Client # 2 магазина объект А на Redis
    • Client # 2 обновления объекта А, как в базе данных и Redis
  5. Client # 1 хранит объект A в Redis

Теперь объект A обновлен в базе данных, но устарел в Redis. Существуют ли какие-либо шаблоны для предотвращения такого поведения? Очевидно, что блокировка базы данных, ожидая, что Redis сохранит ее копию, не является решением.

Следует также отметить, что я использую NodeJS, который поддерживает пул соединений фиксированного размера для Redis, и запросы обрабатываются асинхронно, поэтому мы не можем предположить, что порядок запросов от разных клиентов не будет смешиваться в одном подключение.

ответ

0

Вы ищете Redis transactions. Ключом является команда WATCH. Вы вызываете WATCH на объект A перед первоначальным чтением и устанавливаете объект внутри MULTI.Теперь ваши два сценария выглядит следующим образом:

  1. Client # 1 ВАХТ объект А в Redis
  2. Client # 1 запрашивает объект А из Redis
  3. Redis ответы с нулевым
  4. Client # 1 запрашивает объект А из базы данных
  5. базы данных возвращает объект A
  6. Client # 1 сохраняет объект А в Redis, в/EXEC блоке MULTI

и

  1. Client # 1 ВАХТ объект А в Redis
  2. Client # 1 запрашивает объект А из Redis
  3. Redis ответы с нулевым
  4. Client # 1 запрашивает объект А из базы данных
  5. База данных возвращает объект A

    • Клиент №2 запрашивает объект A из Redis
    • Redis ответы с нулевым
    • Client # 2 запрашивает объект А из dtabase
    • базы данных возвращает объект
    • Client # 2 сохраняет объект А в Redis
    • Client # 2 обновления объекта А, как в базе данных и Redis
  6. Клиент # 1 сохраняет объект а в Redis в MULTI/EXEC блока, но терпит неудачу, потому что объект а изменилось после ЧАСЫ

После сбоя клиент № 1 может повторить попытку, но, вероятно, лучше просто проигнорировать сбой, так как кажется, что вы просто используете его в качестве кеша.

Клиент № 2, конечно же, должен был также сделать образец WATCH/MULTI/EXEC.

+0

Я боюсь, что команды 'watch' не работают с объединенными соединениями и асинхронной обработкой в ​​NodeJS. Команды разных клиентов смешиваются вместе. –

+0

@SebastianNowak Это проблема с вашей библиотекой или использованием, а не с Node.js. Я отлично использовал 'watch' /' multi' в NodeJS. Если вы добавите подробности о своем использовании, я с удовольствием покажу вам, как это сделать. –

+0

Мне нужно было создать новое соединение с Redis для каждого клиента, чтобы заставить 'watch' работать. Это поведение объясняется здесь: http://stackoverflow.com/a/20186334/853906 и здесь: http://stackoverflow.com/a/20216928/853906 –

0

Если на объекте нет операции обновления (5-й шаг), вы должны использовать SETNX для его сохранения. Таким образом, вы не храните устаревший объект.

Факс: Факс:
+0

Существует несколько сценариев, когда может произойти сбой. Например, клиент # 2 может полностью удалить объект, а затем клиент # 1 восстановит его в кеше. –

+0

Зачем вам нужно что-то удалить из хранилища кеша? – enesismail

1

Если ваши данные не изменяется часто (энергонезависимо), как и в исторических данных со вчерашнего месяца или месяца назад, вы можете спокойно проигнорировать состояние гонки, потому что независимо от того, кто получил последнее сообщение, данные все еще остаются одинаково для клиентов.

Для чувствительных ко времени данных, особенно данные об операциях, вы можете отделить кэш, основанный на идентификатор пользователя, используя идентификатор пользователя (Client # 1, Клиент 2 #) в качестве дополнительного ключа. Это будет устранить состояние гонки между клиентами, не прибегая к блокировке и синхронизации транзакций с Недостаток использования более высокой памяти.

Этот метод может быть объединенный с первым способом, например. если данные относятся к пользовательским данным, вы можете использовать ключ идентификатора пользователя, а с другой стороны, если данные содержат общую/группирующую информацию, такую ​​как доступ к меню на основе роли, вы можете использовать вместо этого идентификатор группы.

Смежные вопросы