Работа с типичной кэширующей системой (в том числе с memcached) заключается в выполнении трех основных операций:
save($data, $id, $lifetime): сохранить данные $data в ячейке кэша с ключом $id. Можно указать "время жизни" ключа $lifetime; спустя это время данные в кэше "протухнут" и удалятся.
load($id): загрузить данные из ячейки с ключом $id. Если данные недоступны, возвращается false.
remove($id): очистить ячейку кэша с ключом $id.
Предположим, мы хотим эакэшировать долгий SQL-запрос для быстрого отображения части страницы. В этом случае мы проверяем: имеется ли запись в ячейке кэша, соответствующей этому запросу. Если ячейка пуста, данные загружаются из СУБД и сохраняются в кэш для возможных будущих извлечений.
К сожалению, в чистом виде этот подход удается применять не так часто. Дело в том, что данные в БД могут измениться, и мы должны каким-то образом очистить ячейку кэша, чтобы пользователь увидел результаты этих изменений немедленно. Можно использовать метод remove() с указанием ключа, однако во многих случаях в момент обновления данных мы просто не знаем, в каких именно ячейках они кэшируются.
Проблема, на самом деле, гораздо сложнее. В высоконагруженных системах данные добавляются в таблицы по нескольку (сотен) раз в секунду. Поэтому логика отслеживания зависимостей и проверки, какие ячейки кэша нужно очищать, а какие нет, становится крайне сложной (а то и вовсе нереализуемой).
Тэгирование предоставляет решение этой проблемы. Каждый раз, когда данные записываютя в некоторую ячейку кэша, мы помечаем их тэгами пометками, представляющими зависимости этих данных от других частей системы. Тэги как бы позволяют объединять ячейки в множественные пересекающиеся группы. В дальнейшем мы можем дать команду "очистить все ячейки, помеченные определенным тэгом".
Давайте модифицируем предыдущий пример с использованием тэгов. Предположим, что SQL-запрос существенно зависит от ID текущего пользователя $loggerUserId, поэтому каждому такому пользователю выделяется отдельная ячейка с именем "key_{$loggedUserId}". Однако данные зависят и от ID другого человека $ownerUserId, чей профиль просматривает текущий пользователь. В этом случае мы можем пометить ячейку тэгом, связанным с пользователем $ownerUserId:
Теперь, если меняются данные в профиле пользователя $ownerUserId (например, человек поменял свое имя), нам достаточно дать команду на очистку тэга, связанного с этим профилем:
Обратите внимание, что кэш-ячейки всех остальных пользователей при этом не пострадают: очистятся только те, которые зависели от $ownerUserId.
Собственно, фраза "пометить ячейку C тэгом T" означает то же, что утверждение "ячейка C зависит от данных, описанных как T". Тэги это зависимости, ничего более.
Кэширование в Zend Framework
В PHP работа с memcached поддерживается отдельным модулем memcache. В нем есть все необходимые операции и методы, однако интерфейс модуля слишком низкоуровневый, чтобы применять его в скриптах. Отличное решение представляет Zend Framework: в нем работа с кэшем четко структурирована и разнесена по уровням абстракции. Именно на основе интерфейсов из Zend Framework работает подсистема Dklab_Cache_Backend, описанная в статье Dklab_Cache: правильное кэширование — тэги в memcached, namespaces, статистика.
В Zend Framework подсистема кэширования разнесена на два логических блока:
Zend_Cache_Backend_*: классы, поддерживающие разнобразные хранилища на низком уровне. Каждому хранилищу соответствует свой класс. Имеются, например, классы для кэширования во временных файлах, в SqLite и т. д. Есть и поддержка memcached. Все классы имеют один и тот же интерфейс Zend_Cache_Backend_Interface, включающий методы save(), load(), remove() и т. д.
Zend_Cache_Frontend_*: классы-обертки, использующие backend-классы и предоставляющие дополнительную логику по работе с кэшем. Они, например, умеют сохранять структурированные данные (массивы, объекты и т. д.), проводя прозрачную сериализацию и десериализацию.
Backend-классы обычно не используют напрямую, вместо этого применяют frontend-классы. Для каждого frontend-класса можно использовать совершенно любой backend-класс: это достигается благодаря единому интерфейсу backend-кэширования.
Самое приятное и удивительное в Zend_Cache то, что его интерфейсы изначально включают поддержку тэгов! Например, метод save() имеет следующий прототип: save($data, $id, array $tags, $lifetime); как видите, при сохранении данных можно задавать привязанные к ним тэги. Однако эта поддержка для всех backend-ов не реализована: попытка добавить хотя бы один тэг приводит к генерации исключения.
От теории к практике: Dklab_Cache_Backend
Теперь вы знаете, что такое тэгирование и как оно помогает при разработке сложных проектов. Если вам понравилось, переходите к верхней части стати Конструктора Dklab_Cache: правильное кэширование — тэги в memcached, namespaces, статистика и попробуйте предлагаемые решения на практике. В помощью библиотеки Dklab_Cache вы сможете использовать технологию тэгирования ключей на своем сайте.
Ну а затем возвращайтесь назад и, если все еще осталось желание, читайте следующую наблу Правильный способ кэширования данных, где речь пойдет уже о высокоуровневых аспектах кэширования.
автор категорически против копирования и распространения в Интернете всех статей «Куроводства» с возрастом, меньшим 6 месяцев. Печальный опыт «расползания» чрезвычайно устаревших ошибочных версий статьи про Apacheдействительно объясняет такое решение.
Орфография на «Куроводстве»:
если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмитеCtrl+Enter. Выделенный текст будет немедленно отослан вебмастеру, а Вы даже ничего и не заметите настолько быстро все произойдет.
На заметку:
если вы уже вскипели насчет дизайна этой страницы, то присмотритесь повнимательнее к названию, почитайте FAQ, сходите по лебедевским
местам, как это уже предлагалось выше. Можно ли считать пародию плагиатом? Надеюсь, что нет.