Nginx. Кеширование с помощью fastcgi_cache
Устал я от того что мой блог долго грузится, но менять движок с Wordpress на что-либо другое пока нет времени, а переезд на новый более мощный сервер всё время затягивается и решил прикрутить кеширование на стороне Nginx. Так как блог работает на fastcgi, то буду использовать fastcgi_cache, если вы используете связку Nginx+Apache, то вам следует использовать proxy_cache, как я понял там отличий особых нет.
Некоторые блоки мне всетаки надо оставить вне кеша, поэтому буду использовать ssi.
Настройка
У меня много хостов на одном сервере, но мне надо настроить кеш только для одного хоста. Определим кеш для моего блога в nginx.conf, секция http:
fastcgi_cache_path /var/cache/nginx/adw0rd levels=1:2 keys_zone=adw0rd:16m max_size=256m inactive=1d;
fastcgi_cache_path- путь до каталога кеша, создайте его заблаговременно.
levels=- разделять файлы кеша на сабкаталоги заданного уровня, то есть "1:2" - это так: /0/ab/b7f54b2df7773722d382f4809d650ab0
либо так, если не указывать LEVEL, то есть levels оставить пустым (levels=):/b7f54b2df7773722d382f4809d650ab0
max_size - максимальный размер кеша.
incative - время жизни кеша.
Настройка виртуального хоста
Я разделяю конфиги на основной (nginx.conf) и на хосты (adw0rd.conf, pyha.conf, etc). Сейчас мы разберемся с adw0rd.conf:
server { # Порт который слушаем listen 80; # Имя хоста server_name adw0rd.ru; # Путь до htdocs (document_root) root /path/to/www; # включаем использование ssi ssi on; location / { # Если такой файл не существует физически, то переходить на крайний аргумент, то есть @wordpress try_files $uri @wordpress; } # обработчик для wordpress location @wordpress { # Проксируем на php-fpm fastcgi_pass php-fpm; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; fastcgi_param SCRIPT_NAME /index.php; # Настройки кеширования fastcgi_temp_path /tmp/nginx 1 2; # Каталог для хранение временных файлов fastcgi_cache adw0rd; # Имя зоны кеша fastcgi_cache_key "$request_method|$host|$request_uri"; # Из этих данных строится хеш fastcgi_hide_header "Set-Cookie"; # Не передавать клиенту заголовки кук fastcgi_cache_min_uses 1; # Кол-во запросов, после которых ответ будет закеширован fastcgi_cache_valid 10m; # Время жизни кеша fastcgi_cache_use_stale error timeout invalid_header http_500; # Случаи при которых будет использоватся старый кеш } # обработчик для динамических данных на странице, ниже я покажу как юзать это location ~ ^/ssi/ { fastcgi_pass php-fpm; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } # Обработчик *.php файлов, например "wp-comments-post.php" location ~ \.php$ { # если файл физически не существует, то переходим в @wordpress try_files $uri @wordpress; # иначе обрабатываем запрос fastcgi_pass php-fpm; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
Обо всех директивах можете прочитать в оф. доке Директивы модуля ngx_http_fastcgi_module.
Тестирование
Перезагружаем Nginx:
nginx -s reload
Для тестирования кеша я встроил в шаблон html-комментарий, который формирую так:
<!-- cache: <?php echo time() ?> -->
И теперь вижу в сорце странице закешировалась страница или нет.
Вставка динамических блоков при помощи SSI
Отредактируйте шаблон своей страницы и вставьте нечто подобное:
<!-- uncached_data: <!--# include virtual="/ssi/uncached.php" wait="no" --> -->
Теперь приведите файл "/ssi/uncached.php" к следующему виду:
<?php echo time();
Так как у нас есть обработчик действующий для /ssi/* и он не отдает кешированные данные, то у нас будет подгружатся динамика, все просто! :)
Дополнение
Раздел добавлен 8 августа 2011 г., чтобы дополнить эту статью недостоющими материалами. В основном причиной была статья Прозрачное кэширование в nginx для всех и каждого, спасибо авторам.
Директива fastcgi_ignore_headers для игнорирования инструкци от FastCGI-сервера
Директива fastcgi_ignore_headers запрещает обработку некоторых строк заголовка из ответа FastCGI-сервера.
В директиве можно указать строки "X-Accel-Redirect", "X-Accel-Expires", "Expires" и "Cache-Control".
fastcgi_ignore_headers Expires Cache-Control;
То есть указываем Nginx кэшировать страницы в любом случае, независимо от заголовков кэширования выставленных FastCGI-сервером.
Директивы fastcgi_cache_bypass и fastcgi_no_cache
Директива задаёт условия, при которых ответ не будет браться из кэша.
Если значение хотя бы одной из строк переменных не пустое и не равно "0", то ответ не берётся из кэша:
fastcgi_cache_bypass $cookie_session $cookie_nocache;
Директива задаёт условия, при которых ответ не будет сохраняться в кэш.
Если значение хотя бы одной из строк переменных не пустое и не равно "0", то ответ не будет сохранён:
fastcgi_no_cache $cookie_session $cookie_nocache;
Управление кеширование через заголовок X-Accel-Expires
Будем управлять кеширование из PHP:
<?php header("X-Accel-Expires: $seconds"); // ставим на $seconds секунд header("X-Accel-Expires: 0"); // или отключаем кеширование для определенной страницы
Принудительное обновление кэша
Обновим наш bypass, добавим еще одну переменную для заголовка "X-Update":
fastcgi_cache_bypass $cookie_session $http_x_update;
Ну а теперь обновим кеш:
curl -s -o /dev/null -H "X-Update: 1" example.com
Как и рекомендуют авторы статьи необходимо изменить "$http_x_update" и "X-Update" на что-то своё, чтобы скрипткидесы не баловались.
Полезные материалы
Вот небольшой список статей, который вам могут пригодится:
- Директивы модуля ngx_http_fastcgi_module (оф. документация)
- Описание модуля NginxHttpFcgiModule на wiki.nginx.org
- Кеширование FastCGI-запросов в nginx
- 56. Подводные камни при использовании кэширования в nginx
- Ubuntu. Рабочее окружение Nginx+PHP5.3+FPM+MySQL
- Nginx. Использование PHP в режиме FastCGI с помощью php-fpm
- Настройка Gzip в Nginx
- Nginx и Apache2. Установка и быстрая настройка!
Комментарии
круто! :)
объясни плз различие: inactive=1d; между fastcgi_cache_valid 10m;
И правильно ли я понял, если у стоит fastcgi_cache_valid 10m; то новые комментарии будут появляться через 10минут? Или же за счет того что try_files $uri @wordpress; у нас будет генериться новый кеш при создании коммента?
а вот и нет... кеш заново не генерируется, но страница открывается "налету"! :)
Спасибо! :) Ты как всегда крут! Слушай, drupal на таком конфиге должен летать :)
А если требуется вручную обновить кэш, как это сделать?
И еще вопрос, в этом примере я так понимаю весь кэш генерирует только файл /index.php ?
Очистить каталог и ребутнуть nginx наверное
кеш "генерирует" nginx, а index.php входная точка для роутов
Насчет обновления кэша есть purge
>index.php входная точка для роутов
ну то есть этот скрипт как я понимаю и отдает данные, которые потом кэшируются nginx'ом
fastcgi_temp_path и fastcgi_cache_path
в чем отличие ?
все заметил описано в самом вверху =_
На одном своем проекте заметил, что кеш не создается, если брать страницы через wget или apache jmeter. Но если через браузер открывать, то все нормально. У меня параметр proxy_cache_key "$request_method|$host|$request_uri";
А вы не сталкивались с подобным?
Нет, не сталкивался, возможно дело в заголовках
Дело похоже в session_start(), вызов которой автоматически приводит к отдаче сервером заголовков expires/cache-control/pragma, т.к. без старта сессии при запросе через wget nginx кеширует.
Но в конфиге у меня прописано
proxy_hide_header "Set-Cookie" ;
proxy_ignore_headers "Cache-Control" "Expires";
Осталось разобраться почему при старте сессии в браузере nginx из кеша отдает, а через wget кеш не работает.
keys_zone=adw0rd:120m
А ещё если здесь поставить побольше времени на пример 120m или ещё больше то жаде если php и база данных перестанут работать, Nginx по прежнему будет 2 часа показывать статику!
После того как пройдёт 120 минут, а php и база данных так и не заработала бдет ошибка базы данных или 502.
Читайте об этом тут
Вообщем вам надо использовать inactive.
И прочитайте про fastcgi_cache_use_stale
Может вы мне поможете
limit_req_zone $server_name zone=one:10m rate=30r/m;
нужно что бы лимит срабатывал не на всех php запросах, а только на php запросах которые ещё не закэшированы.
То есть если новые запросы - ставим их в очередь 1 запрос за 2 секунды на обработку в php-fpm и кешируем, а если запрос уже закэширован тогда отдаём сразу без лимита.
limit_req zone=one burst=30;
Или что-то нужно в PHP-FPM крутить чтобы нельзя было одновременно запускать несколько php сразу, не более одного php запроса в две секунды? Нужно очередь создать из php но не из кешированых.
Я особо не понял зачем вам это надо, но кешируются не реквесты, а респонсы, вам надо продумать ключ "fastcgi_cache_key" и тогда будут кешировать только то что надо.
Какую проблему вы решаете? Снизить нагрузку?
Я с php уже не работал года 3, так что лучше спросить актуальные данные на каком-нибудь форуме пхпшников
Настраиваю мониторинг удалённых видео VK. PHP подключается к другому серверу, нужно ограничить число подключений в секунду - то есть выстраивать в очередь если их много, а потом кешировать.
То есть у вас есть приложение, которое ходит на сервера VK и проверяет наличие видео? Вам надо ограничить кол-во запросов к серверам VK и кешировать ответы на запросы?
Тогда не пойму причем тут fastcgi_cache
Для того чтобы избавиться от дублирующихся запросов и кэшировать то что уже проверялось на два дня или больше.
Получилось в IIS, оказывается нужно зайти в Парметры FastCGI и поставить максимальное число экземпляров 1, а в php файле добавить sleep(2);
// текущее время
echo date('h:i:s') . "\n";
// ожидание в течении 10 секунд
sleep(10);
// завершение ожидания
echo date('h:i:s') . "\n";
Осталось только в php-fpm.conf настроить pm = static и разрешить запускать только 1 процесс php-fpm, а потом это закэшировать в Nginx на два дня и отдавать кеш редирект со страшной скоростью!
Вместо того, чтобы написать логику на ЯП, для получения и кеширования респонсов, вы колдуете с настройками Nginx/php-fpm. Все верно?
Верно, я разбираюсь только в Nginx/php-fpm, а ЯП что это? Ним можно проверить размер?
ЯП - язык программирования
А как отключить кеширования в админке?
Видимо сделать отдельный локейшен для админки и почитать http://nginx.org/ru/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache :
У меня на сайте всё кешируется без php сессии, а когда не надо кэшировать специальная картинка ставит Cookies которое отключает всё кэширование Nginx для конкретного чела и включается php сессия. Все роботы и программы для автоматических регистраций ходят по кэшированной версии сайта - они не загружают графику кроме капчи, а люди которые желают зарегистрироваться или войти на сайт видят специальную картинку c Cookies и динамические страницы.
Это позволяет снизить нагрузку в разы!
не понял про обновление fastcgi кеша
Если в конфигурации прописал fastcgi_cache_bypass $http_cache_update;
то теперь чтоб обновить индексную страницу сайта необходимо выполнить
curl -s -o /dev/null -H "CACHE-UPDATE: 1" http://example.com/
или где определяется переменная $http_cache_update или как в прошлой конфигурации $http_x_update.
Где описывается значение X-Update ?
Извините если туплю. вышлите полный конфиг на почту
Оставьте свой комментарий