Уверен, что многие здесь уже сталкивались с проблемой кеширования данных в своих проектах. Также я уверен, что многие уже использовали для этого memcached. Недавно с этим всем пришлось столкнуться и мне =). Но также мне была инетресна возможность работать с пространствами имен в memcached.
К сожалению у memcahced нет поддержки этой удобной возможности, но это не повод, чтобы отчаяться и впасть в депрессию =)
Пространства имен мне понадобились для того, чтобы отмечать порции данных в кеше как не действительные, если часть этих данных уже была отмечена как недействительная. Вот простой пример:
у меня есть объект, который может выбираться из БД как сам по себе, так и среди других объектов с помощью массового SELECT'а; таким образом, если кешировать одиночный объект и массовую выборку из БД, то при обновлении одиночного объекта и инвалидации его кеша, возникает проблема инвалидации кеша выборки. А таких выборок, сохраненнных в кеш, может быть гораздо бльше чем одна.
Долго поломав себе голову, придумывая всевозможные комбинации ключей, решил вернуться к документации к memcached… И о чудо (надо было внимательнее читать в первый раз =)) — в FAQ'e я нашел строчки, решившие мою проблему:
Может кому-то сразу не все стало понятно после прочтения этого куска кода, поэтому я поясню, что здесь «происходит»:
Тут все просто, получаем ключ пространства имен из кеша по ключу "foo_namespace_key" (это можно назвать именем пространства имен).
Это инициализация пространства имен (в моем случае я использовал в качетсве начального значения 0). Пространсвто имен нужно инициализировать целочисленным значением. Зачем? Узнаете чуть позже.
Это пример использование пространства имен. Т.е. то значение, которое мы получили из кеша по ключу "foo_namespace_key", мы совмещаем («встраиваем») с ключем для хранения данных и потом по этому ключу сохраняем необходимые данные. Пример:
Ну а это инвалидация пространства имен (функция increment увеличивает хранимое по заданному ключу значение на 1 или же на величину указанную в качестве второго параметра). Таким образом, в моем примере значение, хранящее в кеше по ключу "foo_namespace_key" увеличится и будет равняться 1. Следовательно, ячейка кеша с ключему $my_key = «foo_».$ns_key."_12345" будет пуста, потому что $my_key будет равен "foo_1_12345", а старые данные будут храниться по ключу "foo_0_12345" и будут не доступны через обращение через пространство имен, обращения к ним больше не будет и со временем они будут вытеснены из кеша.
В случае с моими объектами и массовой выборкой этот метод находит свое место в следующем случае: Все массовые выборки храняться в пространстве имен Objects, а единичные объекты — в Object. Таким образом при изменении или удалении одиночного объекта, я инвалидирую пространство имен Objects, а при массовом обновлении или удалении я инвалидирую и Objects, и Object, что позволяет сохранить актуальность данных в кеше.
К сожалению у memcahced нет поддержки этой удобной возможности, но это не повод, чтобы отчаяться и впасть в депрессию =)
Пространства имен мне понадобились для того, чтобы отмечать порции данных в кеше как не действительные, если часть этих данных уже была отмечена как недействительная. Вот простой пример:
у меня есть объект, который может выбираться из БД как сам по себе, так и среди других объектов с помощью массового SELECT'а; таким образом, если кешировать одиночный объект и массовую выборку из БД, то при обновлении одиночного объекта и инвалидации его кеша, возникает проблема инвалидации кеша выборки. А таких выборок, сохраненнных в кеш, может быть гораздо бльше чем одна.
Долго поломав себе голову, придумывая всевозможные комбинации ключей, решил вернуться к документации к memcached… И о чудо (надо было внимательнее читать в первый раз =)) — в FAQ'e я нашел строчки, решившие мою проблему:
$ns_key = $memcache->get("foo_namespace_key");
// if not set, initialize it
if($ns_key===false) $memcache->set("foo_namespace_key", rand(1, 10000));
// cleverly use the ns_key
$my_key = "foo_".$ns_key."_12345";
$my_val = $memcache->get($my_key);
//To clear the namespace do:
$memcache->increment("foo_namespace_key");
Может кому-то сразу не все стало понятно после прочтения этого куска кода, поэтому я поясню, что здесь «происходит»:
$ns_key = $memcache->get("foo_namespace_key");
Тут все просто, получаем ключ пространства имен из кеша по ключу "foo_namespace_key" (это можно назвать именем пространства имен).
if($ns_key===false) $memcache->set("foo_namespace_key", rand(1, 10000));
Это инициализация пространства имен (в моем случае я использовал в качетсве начального значения 0). Пространсвто имен нужно инициализировать целочисленным значением. Зачем? Узнаете чуть позже.
$my_key = "foo_".$ns_key."_12345";
$my_val = $memcache->get($my_key);
Это пример использование пространства имен. Т.е. то значение, которое мы получили из кеша по ключу "foo_namespace_key", мы совмещаем («встраиваем») с ключем для хранения данных и потом по этому ключу сохраняем необходимые данные. Пример:
- Снача у нас список не инициализирован
- Записываем в кеш пространства имен значение 0
- В результате $my_key будет иметь значение "foo_0_12345"
- Сохраняем данные по этому ключу
$memcache->increment("foo_namespace_key");
Ну а это инвалидация пространства имен (функция increment увеличивает хранимое по заданному ключу значение на 1 или же на величину указанную в качестве второго параметра). Таким образом, в моем примере значение, хранящее в кеше по ключу "foo_namespace_key" увеличится и будет равняться 1. Следовательно, ячейка кеша с ключему $my_key = «foo_».$ns_key."_12345" будет пуста, потому что $my_key будет равен "foo_1_12345", а старые данные будут храниться по ключу "foo_0_12345" и будут не доступны через обращение через пространство имен, обращения к ним больше не будет и со временем они будут вытеснены из кеша.
В случае с моими объектами и массовой выборкой этот метод находит свое место в следующем случае: Все массовые выборки храняться в пространстве имен Objects, а единичные объекты — в Object. Таким образом при изменении или удалении одиночного объекта, я инвалидирую пространство имен Objects, а при массовом обновлении или удалении я инвалидирую и Objects, и Object, что позволяет сохранить актуальность данных в кеше.