Previous Entry Share Next Entry
Прозрачное кэширование в nginx, для всех и каждого
Cola with Ice
sanmai

Представим, что у нас есть сайт, на который регулярно даёт ссылки navalny.
Нам нужно защитить его от всплесков посещаемости. Как это сделать?

С версии 0.8.46 в nginx появились опции, позволяющие легко и просто настроить прозрачное кэширование для анонимных пользователей.

Для работы этой схемы от сайта требуется очень мало: достаточно лишь не начинать сессию, то есть не отправлять сессионную куку, без явной на то необходимости. Редкий сайт нельзя довести до такого состояния, а значит большинство сайтов можно защитить от резких всплесков посещаемости с помощью nginx с минимальными затратами сил и времени.

Научим сайт начинать сессию только когда она нужна

Для обычных сайтов на PHP это можно сделать выставив в ноль session.auto_start в php.ini или, лучше, в настройках виртуального хоста Apache. Также нам нужно задать подходящие имя для сессионной куки:

php_admin_value session.name "session"
php_admin_value session.auto_start 0

Если сайт сам стартует сессию в коде, то session_start() следует заменить на:

if (!empty($_COOKIE[session_name()]) || $_SERVER['REQUEST_METHOD'] == 'POST') {
	session_id() || session_start();
}
Так, сессия будет начата только если
  • куки с сессией уже есть или если
  • нам отправляют форму, например, с логином и паролем.
  • Что нам и требовалось.

    Настроим nginx на кэширование запросов без сессионной куки

    После того как мы добились того, что сайт не отправляет сессионную куку гостям сайта, настроим nginx на сохранение в кэш запросов без сессионной куки.

    В любом удобном месте, например, в конфиге виртуального хоста nginx перед блоком server, добавим строки:

    proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=cache:30m max_size=1G;
    proxy_temp_path /var/lib/nginx/proxy 1 2;
    proxy_ignore_headers Expires Cache-Control;
    proxy_cache_use_stale error timeout invalid_header http_502;
    proxy_cache_bypass $cookie_session;
    proxy_no_cache $cookie_session;

    Не забываем создать соответствующие каталоги:

    mkdir -p  /var/lib/nginx/cache
    chown -R www-data /var/lib/nginx/cache
    chmod 700 /var/lib/nginx/cache

    В соответствующий блок location добавим выделенные жирным строки:

    location / {
    	proxy_cache cache;
    	proxy_cache_valid 10m;
    	proxy_cache_valid 404 1m;
    	proxy_pass http://apache-backend;
    }

    Перезапускаем nginx, удаляем куки из браузера и наслаждаемся скоростью работы сайта.

    Тонкая настройка кэширования

    Если вы хотите чтобы кэшировались только некоторые страницы, или, например, чтобы некоторые адреса кэшировались на время большее 10 минут, для явного задания времени кэширования используйте:

    header("X-Accel-Expires: $seconds");

    Для полного отключения кэширования, например, счетчиков, используйте:

    header("X-Accel-Expires: 0");

    Проверка на прочность

    Проверим главную страницу сайта на прочность в сто потоков:

    ab -n 1000 -c 100 http://www.example.com/

    C использованием кэширования тестовый сайт легко выдавал более 100 rps, оно и понятно.

    Без использования - предсказуемо показывал 503 ошибку на ~70% запросов.

    Принудительное обновление кэша

    Если в директиву proxy_cache_bypass изменить так:

    proxy_cache_bypass $cookie_session $http_x_update;

    То можно будет принудительно обновлять кэш страницы при необходимости запросом со заголовком "X-Update: 1". Например, так:

    curl -H "X-Update: 1" www.example.com

    Заголовок лучше заменить на любой другой, известный только вам.


  • 1
Имеется сервер: Centos, Virtualmin, апач, с десяток виртуальных хостов. Давно мечтается засунуть туда ngnix, но очень страшно (боюс переносить вирт. хосты). Есть добрый совет?

Переносить, не страшно. Тут есть всякие конфиги, можно попробовать на локалхосте:
https://github.com/sanmai/vhost-config

С другой стороны можно вспомнить старый инженерный принцип: работает - не трогай.

Edited at 2011-07-22 06:19 am (UTC)

>С другой стороны можно вспомнить старый инженерный принцип: работает - не трогай.

Это верно. Оно вообще работает, но вот так:
free
             total       used       free     shared    buffers     cached
Mem:       1025864     905900     119964          0      12820     253788
-/+ buffers/cache:     639292     386572
Swap:      2102456     679584    1422872

top

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
19300 apache    15   0  590m  95m 4304 S  0.0  9.5   0:00.74 httpd              
21447 apache    15   0  590m  95m 4312 S  0.0  9.5   0:00.65 httpd              
26434 root      18   0  512m  79m  10m S  0.0  8.0   1:16.71 httpd              
22757 apache    15   0  570m  76m 4816 S  0.0  7.6   0:02.27 httpd              
12527 apache    15   0  567m  73m 3092 S  0.0  7.4   0:00.67 httpd              
22500 apache    15   0  567m  73m 2896 S  0.0  7.3   0:00.18 httpd              
23885 apache    15   0  567m  73m 2904 S  0.0  7.3   0:00.13 httpd              
21878 apache    15   0  512m  72m 2424 S  0.0  7.2   0:00.21 httpd              
20456 apache    15   0  512m  71m 1844 S  0.0  7.2   0:00.28 httpd              
21446 apache    15   0  512m  71m 1840 S  0.0  7.2   0:00.23 httpd              
20458 apache    15   0  512m  71m 1808 S  0.0  7.2   0:00.28 httpd              
20461 apache    15   0  512m  71m 1812 S  0.0  7.2   0:00.27 httpd              
22684 apache    15   0  512m  71m 1828 S  0.0  7.2   0:00.18 httpd              
23592 apache    15   0  512m  71m 1828 S  0.0  7.2   0:00.12 httpd              
20449 apache    15   0  512m  71m 1812 S  0.0  7.2   0:00.27 httpd              
22688 apache    15   0  512m  71m 1836 S  0.0  7.2   0:00.17 httpd              
23883 apache    15   0  512m  71m 1756 S  0.0  7.2   0:00.11 httpd 

Насколько я понимаю, именно тут и нужен ngnix, чтобы это безобразие привести в норму…

Они реально что-то делают? Судя по %CPU и S, не очень. Потому для начала можно StartServers, MinSpareServers и MaxSpareServers подкрутить, а так же отключить KeepAlive. Если после этого ситуация улучшится - можно будет заниматься nginx.

Какой, кстати, LA?

>Они реально что-то делают?

Висят, ждут давно ушедшего пользователя, насколько я понимаю.

>отключить KeepAlive

А вреда от этого не будет?

>Какой, кстати, LA?

А что такое LA, сорри?
Если это load average то вот:

top - 16:31:54 up 143 days, 16:59,  2 users,  load average: 0.05, 0.11, 0.13
Tasks: 161 total,   1 running, 160 sleeping,   0 stopped,   0 zombie
Cpu(s): 50.0%us,  0.0%sy,  0.0%ni, 50.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

При отключеном KeepAlive сайты будут открываться медленнее у тех, кто находится далеко по сети (пинг от 300), из-за задержек на установку TCP соединения. У апача рекомендуют отключать KeepAlive чтобы процессы занимали память без дела, а обслуживали тех, кому реально что-то нужно прям сейчас.

Судя по LA никакой проблемы нет, можно вообще ничего не делать.

Спасибо.

Но как же своп? Разве факт его активного использование не есть проблема?

Нет, это не проблема, если память свободна. У тебя треть памяти свободна.

Спасибо за консультацию!

наличие чего-либо в свопе еще не говорит о его активном использовании. запустите "vmstat 1" и посмотрите на столбцы swap si/so. если там в основном бегут нули, то проблем со свопом нет

В соответствующий блок location добавим выделенные жирным строки:

location / {
proxy_cache cache;
proxy_cache_valid 10m;
proxy_cache_valid 404 1m;
proxy_pass http://apache-backend;
}

Объясните пожалуйста куда именно нужно добавить эти строки? А то как то расплывчато "в соответствующий блок"

  • 1
?

Log in

No account? Create an account