Pull to refresh

nginx + apache. Кеширование

Reading time 4 min
Views 20K
Привет, %username%
Тут я хочу рассказать о том, как я настраивал кеширование на одном сервере, точнее VDS. Характеристики сервера: 2000MHz, 2GB RAM, 80Gb HDD, технология виртуализации — OpenVZ.
Было решено использовать Nginx версии 0.7.64. На сервере находилось около 200 сайтов. И несколько высоко нагруженных проектов. Вот эти самые проекты и давали ощутимые тормоза и нагрузку на сервер. Мы будем рассматривать DLE в этом примере.
Итак, основные моменты кеширования:
  • Кешировать «гостей» сайта
  • Залогиненных посетителей отправлять напрямую к апачу


0. Придумываем «технологию»


Если в урлах встречаются строки: index.php?action=logout и admin.php то мы будем посылать эти запросы напрямую к апачу. Потом, нам нужно научить nginx отделять залогиненых пользователей от гостей. Разделять мы их будем с помощью кукисов. В моем случае, Кукисы dle_user_id и dle_password означают, что пользователь залогинен и мы не хотим отдавать ему страничку 5-ти минутной давности. И плюс, нам нужно отправлять POST заброс на авторизацию вне кеша, я думаю понятно почему и зачем (:.

1. Поехали. Пишем конфиг


Собственно, я не буду описывать полный конфиг, я буду описывать только те моменты, которые необходимы для кеширования. Я не претендую на правильность и оптимальность моего решения, но то что здесь показано, работает, и неплохо работает в боевых условиях. Сильно не пинайте, я не так давно полез в дебри nginx'a, но чувствуется что документации и тех пример очень не хватает!
Основные директивы конфига — кликабельны, ведут на оф документацию.

1.1 Сам конфиг



http {
proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=one:16m inactive=7d max_size=1024m;
proxy_temp_path /var/cache/nginx/temp; #эта директива будет наследоваться из http секции, если не задано другое.

server {
listen 127.0.0.1:80;
server_name example.com www.example.com;
proxy_temp_path /var/cache/nginx/example.com;

location @nocached {
proxy_pass 127.0.0.1:8080;
proxy_redirect example.com:8080/ /;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}

location / {
proxy_pass 127.0.0.1:8080;
proxy_redirect example.com:8080/ /;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
#здесь мы фильтруем наших залогиненых пользователей
if ($cookie_dle_user_id) { return 412; }
if ($cookie_dle_password) { return 412; }
if ($request_method = POST ) {
return 412;
}
error_page 412 = @nocached;
proxy_cache one;
proxy_cache_key "$request_method|$is_args|$host|$request_uri";
proxy_hide_header "Set-Cookie";
proxy_ignore_headers "Cache-Control" "Expires";
proxy_cache_valid 200 302 304 5m;
proxy_cache_valid 301 1h;
proxy_cache_valid 503 4s;
proxy_cache_valid any 1m;
proxy_cache_use_stale http_502 http_503 http_504;
}

location ~ (admin.php|index.php?action=logout) {
proxy_pass 127.0.0.1:8080;
proxy_redirect example.com:8080/ /;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}

location ~* ^.+\.(jpg|jpeg|gif|png|svg|htm|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar)$ {
root /var/www/example/data/www/example.com;
expires 1y;
access_log /var/www/httpd-logs/example.com.access.log;
error_page 404 = @fallback;
}
location @fallback {
proxy_pass 127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
}


$cookie_name, эта переменная равная cookie name;

Собственно, далее будем разбирать, что же мы здесь намулевали. Предложения по улучшениям и правкам приветствуются!

2. Разбор полетов



Итак, нам необходимо было разграничить пользователей на 2 типа, и в зависимости от типа, давать или не давать ему кеш.
В location @nocached мы будем пускать тех, кто является владельцем двух кук — dle_user_id, dle_password, следовательно эти пользователи будут у нас ходить напрямую, не кешируясь. Я уже писал, что для авторизации используются POST запросы, как и для регистрации ;), следовательно нам не нужно их кешировать. В этом случае, мы просто добавляем проверку на $request_method.
error_page 412 = @nocached собственно и посылает обладателей кукисов, или кто пытается залогинится, напрямую к апачу.
Хотелось бы отметить директиву proxy_cache_key. В ней, для ключа, я указываю лишь «уникальность» страницы, тоесть, если ктонибудь обратился к любой нашей странице «Гостем», то nginx, проксируя первый ответ, сразу кладет его в кеш. После этого, любой другой пользователь, который уложился в отведенное время жизни страницы (proxy_cache_valid 200… 5m) получает ту самую страницу, которую сгенерировал апач для предыдущего пользователя, так будет продолжаться, пока не кончится срок жизни, в нашем случае для ответа 200 выделяется — 5 минут. После этого все будет продолжаться по тому же самому сценарию.
Дальше, я хотел бы отметить 2 строчки: proxy_hide_header, proxy_ignore_headers которые обязательны при кешировании. Вы ведь не хотите чтобы Вася Пупкин смог получить кукисы Пети Васечкиного, и тем самым делать от его имени… ??? Вторая строчка, proxy_ignore_headers Позволяет нам сохранять ответы апача, которые помечены, как не кешировать или еше чемнибудь в этом роде. Ведь даже для таких вещей нам придется дергать неповоротливый апач, когда можно один раз закешировать, и отдавать быстрым nginx'ом.
Придавать особого внимания параметру proxy_cache_valid я не буду, все и так хорошо описано в документации.
proxy_cache_use_stale очень правильная директива, она позволяет нам отдать клиенту закешированную «нормальную» страницу в то время, когда апач или повесился, или сдох или еще чего… 502, и 504 ошибки соответственно.
В следущем location ~ (admin.php|index.php?action=logout) мы говорим что хотим отправлять запросы в которых содержаться строки напрямую к апачу.
Два следущих location говорят nginx'у что статику (картинки таблицы стилей видюшечки и т.д.) отдавать самому. И если nginx не нашел такого файла на диске, то может быть он просто находится в .htaccess и апач нам его отдаст.

Ну вот, надеюсь что все. Я очень надеюсь, что мой хабра топик вам помог, или поможет в будущем избежать некоторых неприятных моментов.
Спасибо за внимание.

P.S. Парсер съел мои http://, а nginx'у они нужны, как мне их восстановить? Иначе при копировании моего куска конфига у вас nginx может заругаться, а если нет, то уже не известно что будет.
Кросспост
Tags:
Hubs:
+53
Comments 38
Comments Comments 38

Articles