Pull to refresh

nginx, ещё раз про кэширование

Reading time 3 min
Views 14K
Иногда скорость роста проекта несколько выше чем скорость оптимизации веб-приложения или приобретение более мощного оборудования под backend.

Наиболее простая схема «распараллеливания» нагрузки — вынос основной нагрузки на несколько frontend. Раньше приходилось мучиться (или наслаждаться, кому как) с webdav'ами, кластерными ФС и прочими хитростями чтобы обеспечить актуальную информацию, так было до тех пор, пока не появился nginx, а точнее proxy_store и proxy_cache в нём.



В общем случае, схема работы выглядит следующим образом:
Несколько frontend (дешевые сервера без raid и прочих взрослых примудростей) через round robin отдаются клиентам.
frontend отдаёт с себя статику, проксирует и отдаёт с себя кэшированную динамику для гостей и осуществляет прозрачное проксирование для зарегистрированных пользователей.
ТТХ backend в данном случае большого значения не имеет, вопрос правильной конфигурации его нужно обсуждать индивидуально. Дополнительное кэширование всего чего можно на backend приветствуется.

Преимущества такого подхода — в стоимости данной «кластеризации» за счёт бюджетных характеристик frontend. Отказ любого frontend не критичен, достаточно поднять его ipшку (при наличие такой возможности) на другом frontend или изменить конфигурацию DNS (что может чревато недоступностью для ряда пользователей). На практике, городской портал где видео\фото хранилище на 4Тбайт (занято на backend) на frontend'ах лежит не более 300Гбайт того, что реально запрашивают пользователи (чистить можно по atime но учитывая, что на frontend ФС монтируется с noaime то по дате создания файла). Статичное содержимое на backend генерируется с новым именем, модификация файла также приводит к созданию нового имени файла, чтобы frontend корректно работал.

http {
proxy_cache_path /var/www/cache levels= keys_zone=mycache:150m;
...
}

server {
#устанавливаем дефолтовый флаг, не кэшировать
set $cached 0;
listen server;
server_name server *.server;
#нужно чтобы отдавать красивую 500Ашипку с себя
error_page 502 503 504 509 /500.html;
#если где-то что-то забыли, то будет работать схема прозрачного проксирования
error_page 404 = @nocached;

expires epoch;
root /var/www/html;

location = /500.html {
}

#динамику будем брать с frontend и если отсутствует, то скачивать
location ~* ^.+\.(jpg|jpeg|gif|gz|zip|flv|rar|wmv|avi|css|swf|png|htc|ico|mpeg|mpg|txt|mp3|mov|js)$ {
expires 1y;
error_page 404 = @fetch;
}

#кэшируем статику на себя
location @fetch {
proxy_pass httр://backend;
proxy_store on;
proxy_temp_path /var/www/_fetch;
proxy_set_header Host mydomain;
proxy_set_header If-Modified-Since "";
}

#для зарегистрированных проксируем прозрачно
location @nocached {
proxy_pass httр://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

#гостям проксируем и кэшируем
location @cached {
proxy_pass httр://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache mycache;
proxy_cache_valid 200 301 302 304 5m;
proxy_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
proxy_hide_header "Set-Cookie";
proxy_ignore_headers "Cache-Control" "Expires";
}

#иначе морда домена не будет работать
location = / {
return 404;
}

location / {
#если нет нашей куки
if ($http_cookie !~ "userid" ) {
set $cached 1;
}

if ($request_method = POST) {
set $cached 0;
}

if ($request_method != GET) {
set $cached 0;
}

if ($cached = 1) {
error_page 404 405 502 504 = @cached;
break;
}

if ($cached = 0) {
error_page 404 405 502 504 = @nocached;
break;
}

}

}


Всё это дело служит на благо моего новосибирского сайта
Tags:
Hubs:
+45
Comments 27
Comments Comments 27

Articles