2016-01-08 11 views
7

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

Представьте последовательность двух покупок происходит так:

  • Все узлы кэша работают
  • журналы пользователь на (их данные извлекается из БД и хранится в Memcached)
  • Кэш-память узел опускается
  • Пользователь продолжает просматривать (и поскольку их данные не могут быть найдены в кеше, он извлекается из БД и сохраняется в memcached)
  • Пользователь выполняет некоторые действия, которые преобразуют ms их запись [например, выравнивание] (их запись обновляется в кеше и базе данных)
  • Кэш-узел возвращается
  • Мы снова извлекаем данные пользователя из кеша и исходим из исходного кеш-узла, который ранее было
  • Теперь у нас есть проблема: узел в кеше устарел!
  • Пользователь делает другое действие, которое превращает их запись
  • Это сохраняется в кэше и базах данных, но так как она была основана на устаревшей записи он топает по сравнению с предыдущими изменениями и эффективно возвращается его

Мы потеряли данные, потому что запись базы данных была переписана с частично устаревшей информацией.

Как я могу предотвратить это с помощью PHP5 и libmemcached с постоянными соединениями? Я думаю, что я хочу, чтобы кэш-узел не переключился на другой ресурс; он должен просто не читать и записывать на этот узел, но не удалять его из пула, чтобы я не получал дубликаты записей.

Это увеличит нагрузку на мою базу данных на 1/n (где n - общее количество узлов кэша), когда узел опускается, но это лучше, чем заканчиваться несогласованными данными.

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

+0

Узел кэша, который «возвращается», запускается, должен считаться недействительным вообще и должен быть опущен – bebbo

+0

@bebbo Есть ли настройка для этого в memcached? Я не уверен, что кэш-узел знает, что он стал недоступным (возможно, только подмножество серверов) –

+0

Мне не известны такие параметры. Мой подход заключается в том, чтобы сохранить только данные не транзакций в кеше, чтобы быть в безопасности. – bebbo

ответ

2

Мне нравится versioning and optimistic lock approach, реализованный в доктрине ORM. Вы можете сделать то же самое. Он не увеличит нагрузку на вашу базу данных, но потребует некоторого рефакторинга.

В принципе, можно добавить номер версии для всех таблиц вы кэширование, измените update запросов для увеличения версии version = version + 1 и добавить where version=$version условие (обратите внимание $version приходит из вашего PHP/кэша). Вам нужно будет проверить количество затронутых строк и выбросить исключение, если оно равно 0.

Это зависит от вас, как справиться с таким исключением. Вы можете просто сделать недействительным кеш для этой записи и попросить пользователя повторно отправить форму или попытаться объединить изменения. На этом этапе у вас есть устаревшие данные из кеша, обновление с пользовательского ввода и свежие данные из БД, поэтому единственный неисправимый случай - это когда у вас есть 3 разных значения для одного и того же столбца.

+0

Кажется, что это должно работать в теории. Спасибо за предложение. К сожалению, это добавляет много сложности –

1

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

+0

Это не устраняет проблему; вы не можете пометить его грязным, если он недоступен. Когда он вернется, он все равно будет выглядеть чистым –

+0

@BradDwyer, как только клиент не сможет попасть в кеш, пометьте его в общем доступном местоположении, например таблицу базы данных с меткой времени, а затем после того, как кэш будет работать в сети, он должен иметь некоторый тип сценария heartbeat, чтобы проверить соответствие этой таблицы базы данных, чтобы убедиться, что он должен очистить кеш или нет. – Allen