• 19218
  • 16
  • 3
Нравится блог?
Подписывайтесь!

Кеширование блоков с помощью nginx

nginx + SSIМногим разработчикам знакома ситуация когда кешировать страницы сайта, скажем, на 5-10 минут нельзя всего из-за одного небольшого блочка, актуальность которого нужно поддерживать если не в реальном времени, то с временем «старения» не больше 5-10 секунд. При этом посещаемость сайта продолжает расти, растет время генерации страниц и c этим надо что-то делать…

  • Вариант решения 1: Подкрутить то, до чего не доходили руки последнее полгода. Все Вас поймут и передвинут сроки на другие задачи. Вы будете в роли «Супермена» один спасать сайт от непомерной нагрузки, решая проблему «бесплатно» (без доп. вливаний в оборудование). Вам может пригодиться статья «Тюнинг nginx».

     
  • Вариант решения 2: Улучшить техническую базу (докупить мозгов на сервер, улучшить дисковую систему, поставить под БД отдельный сервер). В принципе проблема не решена, а скорее отложена. Теперь у Вас есть время «окопаться» и подготовиться ко второй волне наплыва нагрузки, она будет больше и накроет сильнее.

     
  • Вариант решения 3: Ваш вариант, о котором я, вероятно, узнаю из комментариев.

     

Позвольте предложить и мне проверенное и относительно простое решение на базе одной из старейших технологий в Web-разработке.




Как это должно работать



Cайт всегда можно разбить на некоторое число независимых блоков, генерацией которых может заниматься (при необходимости) разные сервера.



При этом сборкой блоков в единое целое занимается некий «сборщик» и если любой из блоков по какой-то причине не создан за отведенное ему время, то это еще не повод выдавать клиенту «Gateway timeout» или «Internal Server Error». Можно собрать успешно созданные блоки, а на месте «сбойных» показывать устаревший контент из кеша.



Для реализации такой модели нам понадобиться технология-ветеран Web-разработки: ssi. В качестве «сборщика», как ясно из названия статьи, выступает nginx. «Чудеса» станут возможны благодаря модулю fastcgi_cache.



Итак, поехали:




Исключаем лишнее звено



Нам не пригодиться apache, наличие которого, как правило объясняется использованием RewriteRules. В nginx есть аналог mod_rewrite или комбинация location/alias с регулярными выражениями, возможности которых позволяют написать аналог любому RewriteRule от apache. Кроме того в современных фреймворках разбором входного URL может заниматься сам движек (например Zend_Controller_Router_Rewrite в Zend Framework)



В качестве fastcgi-бекенда может использоваться любая платформа. Примеры будут на php, но это не означает что нельзя написать аналогичный код на python-е или perl-е.



Запускаем php в режиме fastcgi:

# /bin/su -m www_user -c "PHP_FCGI_CHILDREN=8 /usr/bin/php-cgi -q -b 127.0.0.1:7777 &"



Можно еще прописать путь к лог-файлу в php.ini (error_log = /var/log/fastcgi/fastcgi.log), но при этом придется перезагружать php-cgi.



Делаем:

# killall php-cgi

и запускаем все по-новой



Более продвинутый вариант запуска fastcgi — установка php-fpm.




Устанавливаем nginx



Можно ставить стандартный из репозитория/портов… Но если хотите чтоб работала возможность «почистить» любой файл в кеше, придется компилировать.



Нам понадобиться модуль: ngx_cache_purge



Я подробно опишу, как это можно сделать для redhat-подобной системы, а вы уж по аналогии компилируйте под вашу систему.



# cd ~/rpmbuild/SRPMS
# yumdownloader --source nginx
# rpm -ivh nginx-0.7.65-1.fc12.src.rpm


редактируем файл nginx.spec, где-нибудь в список ./configure вставляем строчку--add-module=/root/rpmbuild/BUILD/ngx_cache_purge-1.0 \. Тут же можно удалить строчки с ненужными модулями (например --with-ipv6 \, --with-http_dav_module \, --with-mail \, --with-mail_ssl_module \ ...)



теперь распаковываем содержимое http://labs.frickle.com/files/ngx_cache_purge-1.0.tar.gz в папку /root/rpmbuild/BUILD/ngx_cache_purge-1.0.

Все можно компилировать:



# cd ~/rpmbuild/SRPMS
# rpmbuild -ba nginx.spec


Это не совсем красивый способ, т.к. полученный в результате .src.rpm не будет содержать файла с модулем ngx_cache_purge. Если для вас, все же, это критично, то здесь можете загрузить «правильный» вариант nginx .src.rpm для ветки 8.xx. Правда я часть ненужных мне модулей закомментировал.



Устанавливаем пересобранный nginx на наш сервер:



# rpm -ivh nginx-0.7.65-1.fc12.x86_64.rpm




Настройка nginx для проекта на php



В файл /etc/hosts (добавляем):



# Virtual hosts 
127.0.0.1 myproject


В основном конфиге /etc/nginx/nginx.conf в секцию http добавляем:



fastcgi_cache_path /var/spool/nginx/cache levels=1:2 keys_zone=mycache:64m;
include /etc/nginx/conf.d/*.conf;


(Не забудьте создать папку /var/spool/nginx/cache и установить для нее пользователя, под которым запускается nginx)



В папке /etc/nginx/conf.d/ создаем конфиги для виртуальных хостов



Пример кофига (/etc/nginx/conf.d/myproject.conf):



server {
        listen       80;
        server_name  myproject;

        root   /var/www/myproject/public;
        ssi on;

        # Включаем кеш если есть такая необходимость
        fastcgi_cache mycache;
        fastcgi_cache_min_uses 1;
        # Время кеширования равно нулю. кеш включен но кеширования нет
        # Время кеширования для конкретных страниц указиваем в заголовке "Cache-Control"
        fastcgi_cache_valid 200 0m;
        fastcgi_cache_valid 404 1m;
        fastcgi_cache_valid 500 0m;
        fastcgi_cache_use_stale updating error timeout invalid_header http_500; # Используем вариант из кеша (даже если он устарел) в случае ошибки
        fastcgi_cache_key $uri$is_args$args;

        # Раскоментируйте эту секцию если nginx собран с модулем ngx_cache_purge
#         location ~ ^/purge(/.*) {
#               fastcgi_cache_purge   mycache   $1$is_args$args;
#         }

        location ~ /(img|css|js|assets) {
#               access_log  off;
                access_log  /var/log/nginx/myproject_img_access.log  main;
                expires 1h;
        }

        location / {
                access_log  /var/log/nginx/myproject_main_access.log  main;
                error_log  /var/log/nginx/myproject_error.log;

                fastcgi_pass 127.0.0.1:7777;
                fastcgi_index    index.php;

                include         fastcgi.conf;
        }
}


Устанавливаем тестовый проект на php в /var/www/myproject. Исходный код примера можно посмотреть и скачать здесь.



Запускаем nginx. Для RedHat-подобных систем это выглядит приблизительно так:



# service nginx start


Все, система готова к работе! Пробуем запустить http://myproject/




Учим backend управлять временем кеширования



Дело в том, что в nginx время кеширования указывается в параметре fastcgi_cache_valid 200 0m; и распространяется на все страницы, в которых заголовком оно не переопределено.



В конфиге «по умолчанию» время кеширования я указал равным 0, т.е. кеширование отключено. Но если бекенд сгенерирует заголовок приблизительно такого вида:



Cache-Control: public, max-age=20
либо
Expires: Thu, 18 Mar 2010 20:57:07 GMT


То страница nginx-ом будет закеширована на 20 секунд. В php заголовок можно поменять с помощью функции header() (Со слов автора nginx самым приоритетным является «X-Accel-Cache-Control», потом «Cache-Control», потом «Expires»).



Напишем небольшую функцию. котрая будет управлять временем кеширования:

function cacheHeaders($lifetime=0) {
#        $date = gmdate("D, d M Y H:i:s", time() + $lifetime);
#        header('Expires: ' . $date . ' GMT');
        header('Cache-Control: public, max-age=' . $lifetime);
}





Мастерим блоки



Блоком будем называть любую логически выделенную часть html-кода без стандартных заголовков html-старницы, например:



<div>
    Это простой блок
</div>


Чтоб визуально контролировать состояние свежести каждого из блоков добавим код, наших тестовых блоков вывод времени.



<?php echo date('G:i:s')?>


Смотрим рабочий пример с использованием SSI блоков.




Удаляем страницы из кеша



К сожалению у nginx-а пока что нету родного (штатного) способа удаления страничек из кеша. Иногда это может создавать неудобства.



Если вы добавили при компиляции модуль ngx_cache_purge, то в конфиг (/etc/nginx/conf.d/myproject.conf) добавим приблизительно такую секцию, перед секцией «location / {...» :



location ~ ^/purge(/.*) {
        #allow     127.0.0.1;
        #allow     10.1.1.0/24;
        #deny     all;
        fastcgi_cache_purge   mycache   $1$is_args$args;
}


Для того чтоб удалить закешированную страницу: http://myproject/mypage.php?lang=ru, мне достаточно загрузить страницу http://myproject/purge/mypage.php?lang=ru



В php это можно сделать командой file_get_contents(«http://myproject/purge/mypage.php?lang=ru»);



С помощью директив allow и deny можно ограничить круг хостов с которых можно «чистить» кеш.




Тестируем



Напоминаю, ссылка для тестов http://linux.ria.ua/SsiBlocks/src/bin/index.php.



Обратите внимание, «каркас» страницы обновляется раз в 10 секунд, остальные блоки обновляются согласно примечаниям под временем создания блока.



Самый большой интерес, на мой взгляд, представляет «Збойный блок». Если вы введете его в режим имитации сбоя, вы все равно будете видеть «несбойную» версию этого блока пока не очистите кеш.



Кроме того, помните, что вы не одни сейчас проводите эксперименты с этой страничкой, если хотите поэкспериментировать — самостоятельно настройте локальную копию примера.




Делаем выводы



Даже если такой подход покажется Вам примитивным, и функциональность его сильно ограниченной, обратите внимание на то, что это работает не просто быстро, а очень быстро!



Узким местом может быть только дисковая система, если кеш «распухнет» до больших размеров и не будет помещаться в дисковый кеш.



PS: Если эта статья будет интересна читателям, я планирую написать вторую часть о применении описанного подхода к кешированию блоков на Zend Framework.

16 августа 2010, 21:10
9079

Загрузка...
Loading...

Комментарии

Оставьте свой комментарий

Спасибо за открытие блога в Yvision.kz! Чтобы убедиться в отсутствии спама, все комментарии новых пользователей проходят премодерацию. Соблюдение правил нашей блог-платформы ускорит ваш переход в категорию надежных пользователей, не нуждающихся в премодерации. Обязательно прочтите наши правила по указанной ссылке: Правила

Также можно нажать Ctrl+Enter

Популярные посты

Прогноз эксперта: в Казахстане будут жить 5 миллионов китайцев

Прогноз эксперта: в Казахстане будут жить 5 миллионов китайцев

В ближайшие годы в Центральной Азии будут проживать восемь миллионов китайцев, считает заведующий отделением востоковедения национального исследовательского университета высшей школы экономики.
kurmanovainur
23 июня 2017 / 11:23
  • 40894
  • 37
Они сделали это! Kaspi Bank презентовал свое мобильное приложение

Они сделали это! Kaspi Bank презентовал свое мобильное приложение

Изучив ошибки предшественников и собрав воедино новейшие идеи онлайн-банкинга, Kaspi Bank наконец выпустил... свое мобильное приложение!
niyazov
20 июня 2017 / 15:05
  • 8830
  • 10
Почему мы должны быть благодарны журналисту Джеймсу Палмеру за критику ЭКСПО

Почему мы должны быть благодарны журналисту Джеймсу Палмеру за критику ЭКСПО

Как одним критичным постом зарубежному журналисту Джеймсу Палмеру удалось вскрыть сразу несколько гнойников казахстанского общества.
anotherblogger
21 июня 2017 / 0:39
  • 6956
  • 64
В каких случаях у вас могут изъять удостоверение личности?

В каких случаях у вас могут изъять удостоверение личности?

Недавно один знакомый задал вопрос: «Я сейчас выступаю как свидетель по одному делу. У меня забрали удостоверение личности (УЛ) в РУВД и не вернули обратно. Так можно?». Я сразу задалась вопросом...
asselsabekova
21 июня 2017 / 10:17
  • 3222
  • 10
На каких улицах города Алматы вы точно попадете в «пробку»

На каких улицах города Алматы вы точно попадете в «пробку»

Строятся пешеходные и велосипедные дорожки, трамвайные пути "сносят", а главная традиция нашего мегаполиса - замена подземных коммуникаций и в этом году не была нарушена.
beoblod
вчера / 17:22
  • 2498
  • 3
Где отлично провести летние месяцы с пользой для здоровья и кошелька?

Где отлично провести летние месяцы с пользой для здоровья и кошелька?

Я обратил внимание, что в случае с уникальными природными зонами Павлодарской области применима поговорка: «что имеем – не ценим», а ведь они легко могли бы стать международными курортами.
Muzalevskiy
23 июня 2017 / 22:57
  • 3097
  • 11
Это «колхозное сооружение» вредит имиджу города. Я, как алматинка, против!

Это «колхозное сооружение» вредит имиджу города. Я, как алматинка, против!

Почему эту трубу не проложили под землей? Она обезображивает улицу, как дикий багровый шрам от раны, зашитой равнодушным, криворуким и ленивым хирургом, обезображивает лицо.
ValentinaVladimirska
23 июня 2017 / 12:10
  • 2568
  • 37
На Иссык-Куль через Юг. Не бойтесь ехать в Киргизию своим ходом!

На Иссык-Куль через Юг. Не бойтесь ехать в Киргизию своим ходом!

Очень живописная и бюджетная поездка вдоль всего берега по Иссык-Кулю! Мы, две обаятельные девушки, поехали вдвоем, подготовленные к совершенно автономной жизни в палатке, и ни разу ничего не...
yelenasergiyenko
22 июня 2017 / 13:20
  • 2747
  • 23
Инструкции по сопроводительному письму и собеседованию, которые подойдут всем

Инструкции по сопроводительному письму и собеседованию, которые подойдут всем

Наткнулась на статью Ассоциации юристов Новой Зеландии, в которой они дают советы выпускникам юрфака по поиску работы. Статья меня поразила, поскольку там описано все до мелочей, а их советы подойдут абсолютно всем.
asselsabekova
20 июня 2017 / 16:10
  • 2789
  • 8