Используем мемкеш - паттерны и антипаттерны
Чего никогда не стоит делать при работе с мемкешом
1. Быть уверенным, что там есть те данные, что мы положили. Мемкеш не гарантирует хранение данных.
2. Менять какие-то данные в структуре, записанной под одним ключом, т.е. операция вида get -> change -> set. Гарантированны коллизии.
3. Услышав слово "блокировки" реализовывать их для того, что бы предыдущий пункт работал. Блокировки - зло.
4. Хотеть получить список ключей. Это очень часто хочется получить, и с этим желанием нужно боротся, ибо это путь к неверному пониманию принципа "зачем нужен мемкеш"
Неймспейсы.
Реализация неймспейсов, которая позволить очистить весь неймспейс, достаточно проста. Введите ключ типа mynamespacename_version в котором храните... м.. таймстамп. К каждому ключу (при чтении и записи) в этом неймспейсе приделывайте сам неймспейс и вот тот таймстамп из ключа _version. Теперь, стоит лишь поменять значение ключа _version, все последующие чтения перестанут находить старые ключи. Со временем старые ключи удаляться за счет вытеснения.
Теги.
Теги более интересны, так как позволяют вешать зависимость одного ключа от нескольких тегов. Например, когда мы кешировали данные выборки, сначала использовали неймспейсы (по имени модели). Когда пошли join-ы, выборка стала зависеть от нескольких моделей - при изменении каждой нужно было удалить кеш. Принцип тут похожий, но немного другой. Для каждого тега в отдельном ключе мы храним его версию - таймстамп. При сохранении данных, мы оборачиваем их в массив (хеш), и храним таймстамп (т.е. время создания объекта в кеше) и теги. При получения объекта смотрим теги и запрашиваем их из мемкеша. Теперь к нас набор таймстампов - у каждого тега (время "очистки" этого тега) и у объекта - время его создания. Сравниваем, если объект устарел - просто про него забываем (или даже можнем сказать delete в мемкеш)
Бизи-локи.
Своеобразные блокировки. Задача проста - если ключ в кеше протух, не допустить, что бы *дцать процессов ломанулись за ним в базу. Суть проста - не найдя ключ ставим флаг блокировки, лезем в базу, пишем в кеш, снимаем блокировку. Другие процессы, не найдя ключ проверяют блокировку... и если она есть - ждут ее снятия или протухания (на блокировку имеет смысл ставить мальненькое время жизни, ибо огромная очередь "ожидающих" может оказаться хуже, чем запросы в базу).
Читаем-сохраняем.
Если очень нужно делать п.2 из списка того, чего не нужно делать - есть средство. Появилось оно не так давно. Делаем специальный запрос get, который возвращает не только значение, но и уникальное число. Это число привязано к ключу внутри мемкеша и увеличивается при каждой операции над ключом. При сохранении ключа мы так же передаем это число. Операция успешна только если переданное при записи и сохраненное внутрях мемкеша числа совпадают (т.е. изменений не было). Эта операция лучше хотя бы тем, что мы не тратим время на установку блокировок, а значит вероятность коллизии уменьшается. Хотя под активной нагрузкой это решение особо не поможет.
В общем, это банальности, по которым мы прошли... может еще потом что вспомню.
17 комментариев
Рекомендуемые комментарии