Рассмотрим создание тегированной системы кеширования сущностей для high load сайта на Drupal. В ходе доклада будут рассмотрены наиболее интересные моменты реализации (построение цепочки тегов) так же рассмотрены проблемы и способы их решения.
Системы управления взаимоотношениями с клиентами. Drupal CRM Core. - Вадим Ми...
Caching on highload Drupal site - Alexander Shumenko
1. 25 -27 April, 2014 http://camp2014.drupal.dn.ua
Caching on highload
Drupal site.
2. ❏Как мы работаем с кешем в
Drupal
❏Зачем нам нужны цепочки тегов
❏Принцип построения цепочки
тегов
❏Где можно использовать цепочки
тегов
❏Частный пример использования
О чем мы сегодня будем говорить
3. function my_module_function() {
// Проверяем доступен ли кеш
if ($cache = cache_get('my_module_data')) {
// Если да то возвращаем данные.
$my_data = $cache->data;
}
else {
// Если кеш недоступен то выполняем нужные операции.
$my_data = my_module_get_some_data();
// Сохраянем кеш.
cache_set('my_module_data', $my_data, 'cache');
}
return $my_data;
}
Проверка доступности кешированных данных.
Операции с какими либо данными. Сохранение данных в кеш
Обычная работа с кешем
4. ❏Всегда знаем в каком кеше
участвуют данные
❏Возможность получить
управляемый кеш
❏Высокая релевантность данных
хранимых в кеше
❏Снижение нагрузки на сайт при
очистке кеша
Зачем нам нужны цепочки тегов
5. Время потраченное на генерацию
страницы
Для примера возьмем ноду, при выводе которой используется еще 10
референс нод
Без кеширования Контент из
кеша
700
мс
1 мс
7. Принцип построения цепочки тегов
Знаем момент
начала и конца
работы с
кешируемыми
данными
Можем сопроводить
наши данные и
составить цепочку
тегов
function my_module_function() {
$cache_id = ‘some_id’;
if ($cache = qtools_api__cache_get($cache_id, 'cache')) {
$mydata = $cache->data;
}
else {
// Момент начала работы с кешем.
$locked = qtools_api__cache_start($cache_id);
$mydata = my_module_get_some_data();
if ($locked) {
// Создаем и применяем тег.
$tag = qtools_api__cache_tag(‘node’, ‘1’);
qtools_api__cache_tag_apply($tag);
// Момент когда работа с кешем закончена.
$tags = qtools_api__cache_set($cache_id, $mydata, 'cache', ‘600’);
}
}
return $mydata;
}
8. Необходимо сделать механизм гибкого кеширования данных, с учетом отображения
специфической информации в зависимости от контекста кешируемых данных.
Разделение кеша
9. Разделение кеша
❏ Разделить кеш нам поможет уникальный cache_id.
❏ Для данных хорошим вариантом при генерации cache_id будет использование
глобальных данных относящихся к этому кешу, например язык на котором он доступен,
id домена, роли пользователя.
Пример генерации cache_id используемый при рендере сущности:
$cache_id = implode(':', array(
$entity_type,
$entity_id,
$view_mode,
implode('_', array_keys($user->roles)),
$domain['domain_id'],
$language->language,
));
10. function qtools_api__cache_get($cid, $bin = 'cache', $wait = 3, $stale = 60) {
$lid = 'qtools_api__cache_lock:' . $cid;
// Check if we not rebuilding this $cid.
if ($wait > 0 && !lock_may_be_available($lid)) {
if (lock_wait($lid, $wait) == FALSE) {
// If not we only interested in cache that does not expire.
$stale = 0;
}
}
else {
// Rely only on expire if wait = 0.
$stale = 0;
}
// Load cache from a bin.
$cache = cache_get($cid, $bin);
// Reset cache if it is expire, or temporary.
if (!empty($cache) && !empty($cache->expire)
&& ($cache->expire < (time() - $stale))) {
$cache = NULL;
}
// Return cache if exists.
return $cache;
}
Функция
получения кеша,
использует
стандартный
cache_get Drupal.
Также добавлена
проверка на время
жизни кеша.
Cache get
11. /**
* Cache start.
*/
function qtools_api__cache_start($cid, $lock = 30) {
// Prepare fresh tags array.
$tags = &drupal_static('qtools_api__cache_tag', array());
$tags[$cid] = array();
// Attempt to aquire lock.
$lid = 'qtools_api__cache_lock:' . $cid;
return lock_acquire($lid, $lock);
}
Работу с
цепочкой
начинаем
функцией ее
открытия,
объявляем
статик
переменную где
будем хранить
цепочку, и
ставим lock.
Открытие цепочки тегов
Cache
start
12. /**
* Make simple tag.
*/
function qtools_api__cache_tag($type, $value) {
$short = qtools_api__cache_tag_short();
if (!empty($short[$type])) {
$type = $short[$type];
}
// Normalize tag.
$tag = current(qtools_api__cache_tags_prepare($type . '|' . $value));
return $tag;
}
Эта функция создает
тег, также тут мы
пытаемся получить
шорт имя для тега.
В результате
выполнения для ноды
с nid=1 получим тег
вида “n|1”
Создание тега
Cache
tag
13. /**
* Cache tag.
* If seed are not specified mark all opened cache pipes.
* Note that any ';' will be replaced with dash.
*/
function qtools_api__cache_tag_apply($tag, $cids = array()) {
$tags = &drupal_static('qtools_api__cache_tag', array());
$keys = !empty($cids)
? $cids
: array_keys($tags);
// Normalize tag.
$tag = qtools_api__cache_tags_prepare($tag);
$return = array();
foreach ($keys as $key) {
if (isset($tags[$key])) {
$tags[$key] = array_unique(array_merge($tags[$key], array_values($tag)));
$return[$key] = $tags[$key];
}
}
return $return;
}
Собираем цепочку
из тегов. На
выходе будем
иметь теги всех
данных
участвовавших в
генерации
контента. Пример
цепочки
“n|5376;n|1285;t|165;n|
530;n|169;n|214”
Добавление тега в цепочку
Cache
tag
apply
14. /**
* Cache set.
*/
function qtools_api__cache_set($cid, $data, $bin = 'cache', $expire =
CACHE_PERMANENT) {
$track_tags = qtools_api__cache_tags_for($cid, TRUE);
// Add tags to cache object if required.
if (is_array($data) && isset($data['tags']) && is_array($data['tags'])) {
$data['tags'] = array_unique(array_merge($data['tags'], $track_tags));
}
// Set cache.
cache_set($cid, $data, $bin, $expire);
// Release lock.
$lid = 'qtools_api__cache_lock:' . $cid;
lock_release($lid);
return $track_tags;
}
Сохраняем кеш
и снимаем lock
Возвращаем
полученную
цепочку тегов
Cache
set
Сохраняем кеш
Cache
set
15. Связь с Drupal кешем
Чтоже делать с полученной цепочкой тегов? Например мы можем ее использовать для
очищения только нужного кеша в Drupal. Для этого нам понадобится таблица для связи
cache id и тегов которые участвовали в создании этого кеша.
Эта таблица может быть такого вида:
Поле cid bin expire tags
Тип поля varchar varchar int text
Описание Хранит кеш ID для
связи с кешем
Храним имя корзины
чтобы в
последующем найти
кеш
Срок жизни кеша Теги примененные к
кешу
В эту таблицу мы будем производить запись сразу после того как закрываем цепочку тегов.
Таким образом мы получаем связь между таблицей кеша и полученными тегами и можем
найти и очистить кеш в который маркирован этими тегами.
16. Где можно использовать цепочки
тегов
1. При стандартном кешировании в Drupal.
2. Теги можно проставлять в загловок страницы и
использовать как cache id для кеширования данных
реверс прокси сервером, к примеру Varnish.
3. В целом полученные теги Вы можете адаптировать к
любой системе кеширования.