Одна из самых больших проблем в быстродействии друпала - блоки. Блоки в шестом друпале практически не кэшируются. В своё время для пятой версии был написан замечательный модуль blockcache, а мною - его модификация. В Друпал-6 blockcache вошел в урезанном виде, оставив минимальные настройки кэширования блоков лишь для разработчиков модулей, а для простых пользователей не осталось ничего. Небольшие подвижки произошли с выходом модуля blockcache_alter, который позволяет админу сайта менять режим кэширования для каждого блока, но это лишь слабая пародия на всё то, что предлагает blockcache для пятёрки. Поэтому мною был модифицирован blockcache_alter, и теперь в нём есть все фичи от оригинального blockcache + мои модификации. К сожалению, без патча ядра не обошлось. Но это того стоит.
Итак, новые возможности.
- можно выбрать тип кэширования (не кэшировать, кэшировать раз и навсегда, кэшировать для каждой роли отдельно, отдельно для каждого пользователя, для каждой страницы + комбинации)
- можно выбирать насколько закешировать блок. По истечении указанного времени блок будет обновлён
- можно выбрать события, когда блок будет обновлен, даже если время из п.2 ещё не истекло (обновление нод/обновление комментария/регистрация пользователя/логин-логаут).
- Если в п.3 отмечены пункты а) и б), то можно указать ноды какого типа вызовут обновление блока. Это полезно чтобы не обновлять лишние блоки, а обновлять только нужные. Подробнее об этом я писал в моей модификации под пятерку.
В сумме комбинация этих настроек позволяет ОЧЕНЬ гибко настроить кэширование блоков. И это особенно полезно будет на тех сайтах, где много блоков на странице. Мой мод кэширует любые блоки, даже от views.
Однако, как я говорил, требуется хак ядра, ибо кэширование блоков производится лишь в одном месте, когда формируется регион шаблона. Находим файл block.module, нужная нам функция - block_list(). Примерно 400ая строка.
Находим эту часть (примерно 469 строка):
if (!count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
$array = $cache->data;
}
else {
$array = module_invoke($block->module, 'block', 'view', $block->delta);
if (isset($cid)) {
cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
}
}
?>
и заменяем на такую:
if (!count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
$array = $cache->data;
}
else {
$array = module_invoke($block->module, 'block', 'view', $block->delta);
if (isset($cid)) {
$blocklife = variable_get('bc_life_' . $block->module . '_' . $block->delta, '');
$blocklife = (int)$blocklife;
if($blocklife > 1) {
cache_set($cid, $array, 'cache_block', $blocklife + time());
}
else {
cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
}
if (variable_get('bca_debug', FALSE) && user_access('administer nodes')) {
drupal_set_message('Block re-cached: ' . $block->title . '_' . $block->module . '_' . $block->delta . '_' . $blocklife . '_' . time());
}
}
}
?>
Без патча ничего кэшироваться не будет.
Также в моём моде появилась страница настроек (admin/settings/blockcache_alter), где можно включить вывод отладочной информации о том, когда какой блок обновился.
И еще одно замечание: многие друпальщики любят выводить блоки в произвольных местах следующим сниппетом
Выяснилось, что в шестерке данный код выведет блок без кэширования, потому что обычно в этом случае блок не активирован и он не привязан ни к одному региону. Для обхода этой проблемы используйте следующий сниппет:
$block = module_invoke('blockcache_alter', 'block', 'view', 'block,14');
print $block['content'];
?>
В последнем параметре через запятую укажите модуль и дельту нужного блока и всё получится Например, код выше выведет блок 14 из модуля block, а код
$block = module_invoke('blockcache_alter', 'block', 'view', 'views,popular-block');
print $block['content'];
?>
выведет блок "popular-block" из вьюсов.
К посту прикреплена моя, уже готовая версия модуля blockcache_alter.
Вложение | Размер |
---|---|
blockcache_alter_new_by_batbug1.zip | 13.5 КБ |
Комментарии
Спасибо, пригодится.
Хоть и не пользовался, но кэширование это одна из проблем Друпала и любые попытки ее решения - уже хорошо.
Спасибо, полезно
У себя этот модуль включен уже месяц, никаких глюков не замечено, но было бы неплохо, если бы кто-то еще попробовал его в действии. Багрепорты тоже приветствуются.
Может на drupal.org написать, пусть они добавят в ядро этот код. А в архив модуля добавить инструкции по хаку ядра.
Спасибо.
Добавил.
Я написал автору модуля blockcache_alter в issues, но пока нет никакой реакции. В принципе почти все это можно было взять из blockcache5, а почему разработчики ядра не стали - не знаю, наверно это массам не нужно. Даже друпалу.ру интереснее кнопки к буедитору доделать
А как проверить, что кэширование работает? Модуль использует таблицу cache_block? У меня она пуста, и судя по логу запросов, сниппет из одного блока выполняется при каждом обновлении страницы, хотя в настройках блока включено вечное кэширование.
block.module я патчил
Включить отображение дебаг информации.
Какие параметры кэширования заданы, кроме времени? И, кстати, сколько это "вечное"?
Включил, ничего не изменилось. Таблица cache_block пуста. Это не может быть связано с тем, что обновлял сайт с пятерки, на которой стоял Block Cache?
В "производительности" стоит время жизни кэша 5 минут. В настройках блоков ставлю Cache once for everything (global), Cache lifetime оставляю пустым и ставлю Refresh when A comment is added/updated/deleted в одном блоке, A node is added/updated/deleted и A comment is added/updated/deleted в другом, и т.п. relation в первом случае оставляю пустым, во втором отмечаю требуемые типы.
Кстати! Совсем забыл! На странице настроек производительности сайта не забудьте разрешить кэширование блоков!
в favorites. спасибо
надо не инструкцию, а патч.
Да-да, скорее всего, у меня тоже возникали с этим проблемы. Вам нужно пересоздать таблицу cache_block. Можете посмотреть ее в инсталляторе д.6 или воспользоваться моим кодом для мускула
`cid` varchar(255) NOT NULL default '',
`data` longblob,
`expire` int(11) NOT NULL default '0',
`created` int(11) NOT NULL default '0',
`headers` text,
`serialized` smallint(6) NOT NULL default '0',
PRIMARY KEY (`cid`),
KEY `expire` (`expire`)
)
Ага, спасибо, теперь записи в ней появляются.
Уфф, полчаса искал причину того, почему блоки не берутся из кэша - оказалось, что это только под админом.
Супер. Вывод кэшированного блока со сниппетом через вьюс вместо просто вывода сниппета через вьюс сократил Page execution time в 2 раза
Кстати, Drupal позволяет перекрыть свой механизм кэширования своими функциями. Вы прошерстили эту тему, может быть возможно без хака ядра заюзать дополнительное кэширование для блоков?
Блоки кэшируются лишь в одном месте - в block_list(), во время рендера страницы. Я искал способ перекрыть эту функцию, но ничего не придумал. Если кто-то подскажет, буду сильно благодарен.
А что касается "перекрывать механизм кэширования", я так понимаю, под этим имеется в виду функции cache_set/cache_get, а в нашем случае требуется перекрыть момент кэширования.
У меня на главной 11 вьюсов выводятся за 200 запросов и полсекунды - и это для авторизованных юзеров!
batbug, просмотрев ваш все-таки состоявшийся разговор с автором blockcache_alter, а также dev-версию оригинального blockcache_alter и ваши патчи, я так понял, что эти патчи он все-таки включил к себе в модуль?
Правда, в одном патче условие у него
<?php if (!count(module_implements('node_grants'))
&& $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block))
&& ($cache = cache_get($cid, 'cache_block'))) ?>
зачем-то проверяется 2 раза
Какие у вас дальнейшие планы по поводу своего модуля, если выйдет релиз blockcache_alter с вашими патчами? Будете параллельно поддерживать свою версию с доп. настройками?
P.S. Кстати, обновление кэша блока после неких событий (ваши доп. настройки), по идее, можно сделать через триггеры, которые появились в шестерке.
Да, можно брать дев-релиз http://drupal.org/node/395422
Хмм, в дев-версии не нашел такого.
Моя версия она вполне самодостаточна и рабочая. Для всех рекомендовал бы сейчас ставить версию автора, так как он ее сделал покрасивее, а работает она также как и моя. Еще важный момент, автор модуля предусмотрел ситуации c node_grants хуком, что для многих может быть важно.
Я лично пока не ставил на свой production эту новую дев-версию, так как я консерватор у меня все работает и ладно
Собственных новых версий пока не планирую.
Да, вполне, делайте
Я триггеры вообще никогда не трогал, так что заниматься этим не планирую пока.
Но была мысль добавить в настройки блоков обновление по крону, что несложно.
Да, я забыл, что это патч Там одна строка меняется на другую, а я подумал, что в исходнике 2 одинаковых строки.
Поставил blockcache_alter-6.x-1.x-dev.tar.gz пропатчил block.module этим патчем blockcache_alter_with_node_grants.patch, поставил кеширование на блок последних новостей cache once for everything, refresh when: A node is added/updated/deleted и A comment is added/updated/deleted для Relation: Новости. Cache lifetime: оставил пустым, но в cache_block так ничего и не записывается. Пересоздавал таблицу cache_block, как здесь написано - ничего не помогает. У меня стоит модуль ограничения доступа: Content Access, поэтому стандартное кеширование блоков друпала не работает (Написано: кеширование блоков не работает при использовании модулей ограничивающих доступ к содержанию) Может, из-за этого? Но я пробовал отключать модуль Content Access (но не удалял его) но все равно в cache_block ничего не записывается. Подскажите, пожалуйста, в чем может тут быть дело? Спасибо
1) На странице настроек производительности сайта не забудьте разрешить кэширование блоков.
2) Кэширование никогда не работает под рутом (uid = 1)
Тоже возможно.
Модуль Content Access удалил, На странице настроек -->быстродействие --> разрешил кеширование блоков, но записей в таблице cache_block все равно не появляется. Может, что-то еще упустил?
Пожалуйста. Так в чем ошибка была?
Новость запоздала на 2 недели, но все же
Появился новый релиз "оригинального" blockcache_alter
Есть и патчи, и настройки кэширования, и страница настроек модуля. В readme - инструкции при выводе блоков программным способом, которые приводил batbug.
И это прекрасно
В новом релизе два патча, один из них вроде как раз для вашего случая, там нет проверки на node_grants, но его надо применять осторожно.
node_grants - это проверки на доступ к данным на уровне отдельных пользователей (не ролей). если вы отмените их, то возможно возникновение ситуаций, когда человек с одними правами зайдет на страницу, блок закэшируется и туда попадут данные, которые не должны видеть другие пользователии. Т.о. в данном случае надо аккуратно расставлять параметры кэширования для блоков, чтобы не кэшировалось то, что может представлять опасность.
Пример? Скорее не опасность, а приватность Потому как даже если закешируется админ-меню, в любом случае нельзя будет залезть в админку, если нет прав.
Это вопрос семантики, и он меня не сильно волнует. В любом случае, яндексу с гуглом не стоит тыкаться по системным ссылкам, тем самым вызывая 403 ошибку, тем самым создавая ненужную нагрузку, а уж посетителям сайта видеть системные пути вообще нельзя, среди них бывают разные школьнеги-кулхацкеры.
Думаю, да.
Спасибо за модуль и наводку! Полез тестить
отличный модуль, спасибо! Поставил на 6.х точно не замерял, но по ощущениям, в минимум в 2 раза быстрее все стало работать!
Там нужно патчить с помощью .paptch. А можете обьяснить как вручную пропатчить block.module, потому как патчами я пользоваться не умею
Открываете патч и файл, который нужно пропатчить. В патче строки, перед которым стоит минус, находите в исходном файле и заменяете на те, что с плюсом.
или посмотрите http://drupal.ru/node/28171
Здравствуйте, хочется то же blockcache на drupal 6, а не получается, помогите пожалуйста? На drupal 5 он работал нормально, а на drupal 6 так и не работает. Включаю выдает кучу ошибок, выключаю ни одной ошибки. То что здесь выше советовали, не знаю как реализовать, может помогло бы, а именно "пересоздать таблицу cache_block" как это сделать, подскажите пожалуйста?
Вот некоторые из возникающих ошибок:
user warning: Unknown column 'serialized' in 'field list' query: SELECT data, created, headers, expire, serialized FROM cache_block WHERE cid = 'sape:0:tapestry:ru:r.1' in /home/k/knatalya/fizkult-ura.ru/public_html/includes/cache.inc on line 26.
user warning: Unknown column 'serialized' in 'field list' query: UPDATE cache_block SET data = 'a:2:{s:7:\"subject\";s:19:\"Sape - блок - 0\";s:7:\"content\";s:40:\"
\n \n\";}', created = 1250780544, expire = -1, headers = '', serialized = 1 WHERE cid = 'sape:0:tapestry:ru:r.1' in /home/k/knatalya/fizkult-ura.ru/public_html/includes/cache.inc on line 109.
Открываете phpmyadmin, находите таблицу cache_block, удаляете её целиком, затем находите в phpmyadmin кнопку для вставки SQL-кода и вставляете:
`cid` varchar(255) NOT NULL default '',
`data` longblob,
`expire` int(11) NOT NULL default '0',
`created` int(11) NOT NULL default '0',
`headers` text,
`serialized` smallint(6) NOT NULL default '0',
PRIMARY KEY (`cid`),
KEY `expire` (`expire`)
)
Спасибо за советы. Сделала так:
помогло, все ошибки исчезли, спасибо большущее batbug.
Пожалуйста
На друпале 6.14 почему-то опять не работает кэширование в Block Cache Alter... Пересоздал таблицу cache_block - не помогло. Кто-нибудь сталкивался?
Блин, всё перепробовал и таблицу удалял и кэш чистил и всё что описано выше, но белую страницу после сохранения в админке исправить не могу....
а что за Show debug information опция в настройках модуля?
где эта дебаг информация отображается?
В $messages на каждой странице пишется, какой блок обновился.
Спасибо Ваши комменты помогли найти и решить проблему "не кэширования" блоков из-за Content Access.
Поставил Block Cache Alter
Таблица block cache пустая. Захожу в блоки, ставлю кешировать. Сохраняю, выхожу - захожу заново в блок - стоит "не кешировать".
Вернее не так, на каких то блоках настройка сохраняется, а на каких то - сколько не меняй - все равно стоит не кешировать
На странице модуля написано:
Currently this module doesn't work anymore on Drupal core 6.22, see #1173012: Blocks lose settings during update.php and cache clears and #1194880: _block_rehash() overwrites the caching mode set by Block_Cache_Alter module.