Пользователь
0,0
рейтинг
5 октября 2009 в 10:43

Администрирование → Кеширование 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 могут выкинуть из выдачи
Александр @rolltin
карма
23,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

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

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

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

            if (… ) {
            fastcgi_pass_header Cookie;

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

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

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

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

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

        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
      Это очень старый вариант, когда еще кажется не было @backend
  • 0
    Если с последними версиями nginx возникли проблемы с передачей cookies или авторизацией — решение:
    fastcgi_pass_header «Set-Cookie»;
    вместо
    fastcgi_pass_header Cookie;
    • 0
      О, спасибо, я как раз целый день ковырялся, почему никс сессии игнорит — скрипты упорно теряли сессии.

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