Кэширование nginx для анонимных пользователей на примере Drupal

Опубликовано admin в Пнд, 25/04/2011 - 11:54
Как известно, Drupal является примером крайне тяжелой CMS/CMF, и нагруженные сайты строить на нем не так просто. Поскольку моя компания использует в своей разработке преимущественно Drupal — нам иногда приходится сталкиваться с оптимизацией производительности, и я бы хотел рассказать о том, как мы справляемся с нагрузкой.

В этой статье я рассмотрю один из самых эффективных методов повышения производительности — кэширование веб-сервером nginx контента для анонимных пользователей. Благодаря этому приему запросы от анонимных пользователей не вызывают обращения к бекэнду(не важно какому — apache или fastcgi). Таким образом, такое кэширование эффективнее любых средств CMS.


Постановка задачи


Drupal имеет встроенное кэширование для анонимных пользователей. Однако работает оно крайне неэффективно и приносит скорее больше проблем при большой посещаемости. Поэтому разумно применять как минимум 2 меры:
1. Кэшировать контент для анонимных пользователей при помощи nginx
2. Хранить таблицы cache_form и cache_filter в Cacherouter + APC

Drupal


Для того, чтобы отделить анонимных пользователей от залогиненных, мы будем выдавать куку при логине, а при логауте — отбирать ее. Напишем небольшой модуль nginxcache:

nginxcache.info
name = Nginx cache
description = Nginx cache for anonymous users
package = ISFB
version = VERSION
core = 6.x


nginxcache.module
<?php
function nginxcache_user($type, &$edit, &$user) {
switch($type){
case 'login' :
setcookie('logged', TRUE, time()+60*60*24*30, "/");
break;
case 'logout':
setcookie('logged', FALSE);
break;
}
}


Очищаем таблицу sessions, кэш и включаем модуль.

nginx


Я не буду приводить весь конфиг, опишу только то, что имеет отношение к статье.

В секции http нам надо объявить зону:
proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=hrportal:10m inactive=60m;

Предварительно надо озаботиться созданием каталога /var/nginx/cache с нужными правами. Если к данным кэща не обращаются в течении времени inactive — они удаляются вне зависимости от свежести.

В локейшне нужного виртуального хоста пишем:
proxy_cache hrportal;
proxy_cache_key $host$uri?$args;
proxy_no_cache $cookie_logged;
proxy_cache_bypass $cookie_logged;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_pass_header Set-Cookie;
proxy_ignore_headers "Expires" "Cache-Control";
proxy_cache_valid 200 301 302 304 1h;


proxy_no_cache — директива задаёт условия, при которых ответ не будет сохраняться в кэш, в нашем случае, при наличии куки logged. Если забыть про эту директиву — в кэш будут записываться ответы авторизованных пользователей, которые будут отдавать анонимным и другим авторизованным пользователям.
proxy_cache_bypass — ответ не будет браться из кэша для пользователей, у которых есть кука logged
proxy_cache_use_stale — позволяет отдавать устаревший ответ из кэша, если бекэнд не доступен, очень полезно
proxy_pass_header — нужно, чтобы пользователи получали кукисы
proxy_ignore_headers — Drupal всегда отправляет эти заголовки, мы вынуждены игнорировать их
proxy_cache_valid — задает время кэширования ответов

Результаты


Как известно, поисковые системы анализируют производительность сайта и не направляют на него больше пользователей, чам он может обработать. Вот пример http://www.hr-portal.ru качественного с точки зрения ПС сайта, которому не хватало производительности для обработки трафика с ПС. Как видно по графику http://www.liveinternet.ru/stat/hr-portal.ru/index.html?period=month , после установки данного решения, трафик начал расти.
Этот сайт использует CMS Drupal и расположен на нашей технической площадке на VPS.

P.S. Данный подход, естественно, применим к любой CMS.

UPD. Уже не раз слышал вопрос, почему не boost.
Ответ достаточно сложен. попробую объяснить.
Начнем с того, что как вы верно заметили — мое решение не коробочное, и оно должно применяться, когда посещаемость действительно высока — и любые способы повышения производительности важны.

1. nginx-фронтэнд может находиться на отдельном сервере от бекэнда — кэш будет лежать там же — и отдаваться значительно быстрее
2. nginx в любом случае быстрее отдает статику
3. Drupal может стоять на nginx — в этом случае надо переделывать реврайты boost — оно надо?
4. В случае с boost задача кэширования отдается на бекэнд — это можно делать прямо на фронтэнде



Источник: http://habrahabr.ru/blogs/drupal/110958/