• 18971
  • 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
9049

Loading...

Комментарии

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

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

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

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

Исламская ипотека в Казахстане: в этом году выйдет на розничный рынок

Исламская ипотека в Казахстане: в этом году выйдет на розничный рынок

Многие клиенты, вздыхая о харамном ссудном проценте местных банков, сокрушались по поводу отсутствия у нас халяльного кредитования. Поддержка исламского банкинга на уровне МФЦА есть...
DanaJarlygapova
24 марта 2017 / 18:28
  • 21498
  • 63
Рианна за $2 млн. Очередные понты от «ЭКСПО-2017»

Рианна за $2 млн. Очередные понты от «ЭКСПО-2017»

Концерт Рианны всё-таки состоится летом в рамках культурно-зрелищных и спортивных мероприятий ЭКСПО-2017. Рианна крута, с этим никто не спорит. Но соберёт ли «Астана Арена» 30 тысяч зрителей при...
openqazaqstan
вчера / 14:29
  • 15768
  • 15
Компания LG Electronics открыла предзаказ на новый флагман LG G6

Компания LG Electronics открыла предзаказ на новый флагман LG G6

LG Electronics объявляет о начале предварительного заказа онлайн на новый смартфон LG G6. Оформить предзаказ можно на сайтах магазинов электроники до 16 апреля 2017 года.
LG Electronics
24 марта 2017 / 14:20
  • 5224
  • 0
Страну, где так строят дороги, победить невозможно!

Страну, где так строят дороги, победить невозможно!

Шестиминутный ролик про строительство автомобильной дороги в США - это как острый нож в пузо нашим чиновникам. Они же подавятся бешбармаком, увидев его! Похлеще любого пропагандистского фильма...
Timur_Tregulov
24 марта 2017 / 11:26
  • 4927
  • 41
Это вам не Дисней. Реальный прототип «Красавицы и Чудовища»

Это вам не Дисней. Реальный прототип «Красавицы и Чудовища»

Многие уверенны на 100%, что сказка «Красавица и Чудовище» - это интересная выдумка ее создателей. Однако, действия, происходящие в мультфильме и фильме, имели место в истории, и у главных героев...
Naomi_K
24 марта 2017 / 18:42
  • 4979
  • 34
Семь причин почему вам надо перестать откладывать переезд за границу

Семь причин почему вам надо перестать откладывать переезд за границу

Вы думаете о переезде за границу, но постоянно откладываете дату, потому что вас беспокоит тысяча мелочей, которые могут пойти не так? У меня есть семь причин, почему пора перестать мотать нервы...
Lesch
24 марта 2017 / 17:50
  • 3929
  • 14
Гонения на «Свидетелей Иеговы». Кому это выгодно?

Гонения на «Свидетелей Иеговы». Кому это выгодно?

Я не "Свидетель Иеговы". Мне приходилось защищать в судах и кришнаитов и коммунистов, хотя я и не разделяю их убеждений. Я защищаю свободу совести. Сегодня "Свидетели Иеговы", завтра,- каждый из вас.
nasreddin
25 марта 2017 / 17:18
  • 4097
  • 49
Почему наши парни выглядят как агашки? Хочется им сообщить, что мода на пафос прошла

Почему наши парни выглядят как агашки? Хочется им сообщить, что мода на пафос прошла

Когда уже люди смогут самоутверждаться за счет своего интеллекта, энергии, познаний и настоящей красоты, а не за счет авторитетного вида и не менее авторитетного дяди?
Bookenova_smartass
28 марта 2017 / 18:28
  • 3542
  • 89
Страна обыденной роскоши: Ташкент-Самарканд-Бухара

Страна обыденной роскоши: Ташкент-Самарканд-Бухара

Узбекистан - это страна, где роскошь стала обыденностью. Это и повсеместный зелёный крупнолистовой чай. И вкусная натуральная еда с минимумом специй. И то, что дети играют среди исторических памятников.
MadinaR
25 марта 2017 / 10:37
  • 3347
  • 59