Nginx

индекс
267,67

Кеширование FastCGI-запросов в nginx

Доброе утро, Хабр!

В данной статье я приведу пример конфигурации nginx для кеширования FastCGI-запросов. При желании его можно использовать его для защиты от хабраэффекта, частично от DDoS'а и, как вариант, для облегчения жизни сервера с высокой нагрузкой.

В секции «http» объявляем кеш-зону fastcgi_cache, с хранением кеша в папке /tmp/nginx с 2 уровнями вложенности, с максимальным размером 256Мб и кешем ключей 16Мб (неиспользуемые более 1 дня объекты будут автоматически удаляться):
fastcgi_cache_path /tmp/nginx/ levels=1:2 keys_zone=fastcgi_cache:16m max_size=256m inactive=1d;

Далее, в секции «server» правим соответствующий location:
location ~ \.php$ {
            # Стандартная конфигурация для php
            fastcgi_pass   unix:/tmp/php-fcgi.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /usr/local/www/somedir/$fastcgi_script_name;
            include        fastcgi_params;
            fastcgi_param  DOCUMENT_ROOT /usr/local/www/somedir/;
            
            fastcgi_pass_header Cookie; # Необходимо для передачи cookie в соответствующие переменные, например cookie с именем phpsessid будет находится в переменной $cookie_phpsessid

            fastcgi_ignore_headers Cache-Control Expires Set-Cookie; # Игнорируем заголовки, относящиеся к кешированию, полученные от FastCGI-сервера

            fastcgi_cache_key "$server_addr:$server_port$request_uri|$cookie_phpsessid"; # Формируем уникальный ключ; в данном случае различаем пользователей с помощью $cookie_phpsessid

            fastcgi_cache fastcgi_cache; # Говорим о том, что использовать надо вышеобъявленную кеш-зону fastcgi_cache

            fastcgi_temp_path  /tmp/nginx/temp 1 2; # Указываем папку для хранения временных файлов

            fastcgi_cache_use_stale updating error timeout invalid_header http_500; # Используем вариант из кеша (даже если он устарел) в случае ошибки

            fastcgi_cache_valid 10s; # Время жизни кеша для ответов 200, 301 & 302

            #fastcgi_cache_valid any 10s; # Таким образом можно закешировать любые ответы
            }

Конфиг опробован на nginx версии >= 0.7.60 (на => 0.8.1 должен работать, но не тестировался).

Документация: Директивы модуля ngx_http_fastcgi_module, Changelog.

upd: Если не игнорировать заголовки Cache-Control и Expires, nginx ведёт себя соответственно их содержанию (что, в принципе, логично).

upd/28.01.2011: добавлен параметр Set-Cookie к fastcgi_ignore_headers (начиная с nginx/0.8.44)

upd/07.02.2011: необходимо реализовать отделение поисковых краулеров, т.к. при игнорировании cookies могут выкинуть из выдачи
+25
5 октября 2009, 10:43
112

комментарии (27)

+4
Stamm #
Наверное, стоит ещё исключить POST-запросы, заключив всё в условие
if ($request_method = GET ) {

}
0
Porfel #
Каким образом? У меня вылетает например:
[emerg]: «fastcgi_index» directive is not allowed here in /usr/local/nginx/conf/nginx.conf:182
0
t3ran #
Эм… location { } внутри server { } быть должен, соблюдается? У меня такое работает точно.
0
Porfel #
Игорь, location-то внутри server разумеется, а вот куда воткнуть if ($request_method = GET )?
0
t3ran #
Внутрь location, в него загнать все про кеш, т.е.

if (… ) {
fastcgi_pass_header Cookie;

}
0
Porfel #
Да вот нифига.
[emerg]: «fastcgi_pass_header» directive is not allowed here in /usr/local/nginx/conf/nginx.conf:186
0
Porfel #
Есть смысл попробовать через if () отправлять в именованый локейшн я думаю, позже попробую.
0
t3ran #
Есть, но это тебе полностью пост обрубит, чего я старался избежать
0
Porfel #
Как вариант — 2 условия, на POST и на GET, соответственно 2 локейшна.
+3
isysoev #
Начиная с 0.7.48, по умолчанию кэшируются только GET и HEAD. Чтобы POST кэшировался нужно добавить
fastcgi_cache_methods GET HEAD POST;
0
Porfel #
Спасибо!
* Пора учить себя читать changelog'и
* Мне все-таки удасться сегодня поспать! =)
+1
Stamm #
Спасибо, Игорь! Нужно действительно читать changelog, а то в документации про это не написано.
+1
docomo #
Спасибо!

N.B. Сделайте уже кто-нибудь сайт «Секреты Nginx'а» =)
0
gra #
Зачем сайт? Достаточно тут правильно расставлять теги
+4
V2NEK #
он уже есть — sysoev.ru/nginx/docs/ :)
0
alexeym #
> fastcgi_ignore_headers Cache-Control Expires;

а это зачем?
0
Fredy314 #
Это чтоб скрипт не считал себя умнее сервера и не мешал кешировать как ему нравится
0
rolltin #
Если не игнорировать эти заголовки, nginx ведёт себя согласно их содержанию.
0
alexeym #
т.е. он «заменяет» данные в кеше согласно этому заголовку?
и если его не будет, то контент будет отдаваться из кеша вечно (если не сработает inactive=1d)?
0
rolltin #
Смотря что указано в них:
0
rolltin #
Извиняюсь, не дописал.

Если в Expires указана дата в будущем, будет отдавать вариант из кеша вплоть до этой даты;
Если в прошлом — будет постоянно запрашивать с FastCGI сервера;

Аналогично и с Cache-Control, см. RFC 2616, section 14
0
alexeym #
Т.е. если мы их игнорируем, то всегда будет отдаваться из кеша?
0
rolltin #
Да, если в кеше есть копия и её срок годности согласно fastcgi_cache_valid не истёк.
0
alrond #
Не плохо бы добавить как вообще не кешировать для некоторых юзеров, например залогиненных (можно по кукам определять)
Я такое использовал когда еще не было встроенного кеширования (сам генерировал статику). Как сейчас такое сделать с внутренним кешем даже не смотрел.

    set $django 1;
    set $args_old "";
    if ($is_args = "?") {
        set $args_old ?$args;
    }

    location / {
        if (-f $request_filename/index.html$args_old) {
            set $django 0;
        }
        if ($http_cookie ~* "sessionid=([^;]+)(?:;|$)" ) {
            set $django 1;
        }
        if ($request_method = POST) {
            set $django 1;
        }
        if ($django = 0) {
            rewrite (.*) $1/index.html$args_old break;
        }
        if ($django) {
            fastcgi_pass unix:/www/myserver/server.sock;
            break;
        }
        index       index.html;
        access_log      /var/log/nginx/myserver.log main;
    }
0
alrond #
Это очень старый вариант, когда еще кажется не было @backend
0
svin0 #
Если с последними версиями nginx возникли проблемы с передачей cookies или авторизацией — решение:
fastcgi_pass_header «Set-Cookie»;
вместо
fastcgi_pass_header Cookie;
0
Greendq #
О, спасибо, я как раз целый день ковырялся, почему никс сессии игнорит — скрипты упорно теряли сессии.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.