Кэширование в Nginx

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

Исходные данные

В качестве PHP-сценария для проведения тестов использовался небольшой скрипт, выбирающий все строки из таблицы БД MySQL и выводящий результаты при помощи var_dump ():

$oPDO = new PDO("mysql:server=localhost;dbname=test;", 'user', 'password');
$oQRes = $oPDO->query("SELECT * FROM test1");
var_dump($oQRes->fetchAll());

Структура таблицы test1 БД следующая:

+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
| name  | text    | YES  |     | NULL    |                |
+-------+---------+------+-----+---------+----------------+

Таблица содержит 10000 записей, где в каждом поле name записан MD5-хеш случайного числа в диапазоне от 0 до time (). URL сценария, работающего под Apache — http://test.ashep:80/test.php. Давайте посмотрим при помощи siege как сервер будет обрабатывать запросы к этому сценарию.

Прямые запросы к Apache

Эмулируем 10 серий по 10 одновременных запросов:

$ siege -c 10 -r 10 http://test.ashep:80/test.php
Transactions:		         100 hits
Availability:		      100.00 %
Elapsed time:		      109.66 secs
Data transferred:	       32.65 MB
Response time:		       10.30 secs
Transaction rate:	        0.91 trans/sec
Throughput:		        0.30 MB/sec
Concurrency:		        9.39
Successful transactions:         100
Failed transactions:	           0
Longest transaction:	       12.76
Shortest transaction:	        3.66

Сервер успешно обработал все запросы, однако время на обработку каждого составило в среднем 10,3 секунд.

Проксирование через Nginx

Теперь создадим реверс-прокси сервер в Nginx так, как мы это делали в предыдущей статье, в качестве upstream-сервера будем использовать наш Apache по http://test.ashep:80.

server {
    listen 8080;
    server_name test.ashep;
    access_log /var/log/nginx/test.access_log;
    error_log /var/log/nginx/test.error_log;
    location / {
        proxy_pass http://test.ashep:80;
    }
}

Повторим тест, на этот раз уже через Nginx:

$ siege -c 10 -r 10 http://test.ashep:8080/test.php
Transactions:		         100 hits
Availability:		      100.00 %
Elapsed time:		      104.97 secs
Data transferred:	       32.65 MB
Response time:		        9.77 secs
Transaction rate:	        0.95 trans/sec
Throughput:		        0.31 MB/sec
Concurrency:		        9.31
Successful transactions:         100
Failed transactions:	           0
Longest transaction:	       14.54
Shortest transaction:	        2.89

Результаты примерно те же. Логично, поскольку Nginx всего лишь транслирует запросы к upstream-серверу, ничего при этом не кэшируя.

Кэширующее проксирование через Nginx

И теперь самое интересное. Прежде, чем можно будет оперировать кэшированием в настройках серверов Nginx, сперва нужно определить место для хранения и параметры кэша Nginx. Кэшей в Nginx можно определить больше одного, каждый с нужными вам параметрами и затем использовать их в зависимости от ситуации в том или ином месте конфигурации сервера.

Определять кэш можно лишь в контексте секции http, которая, например, в моём Debian описана в /etc/nginx/nginx.conf. Для определения кэша используется опция proxy_cache_path, которая имеет следующий формат:

proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];

В квадратных скобках приведены необязательные параметры. Теперь обо всём по порядку:

В ходе моих экспериментов, рассматриваемых в этой заметке, я использовал следующее значение опции proxy_cache:

proxy_cache_path /var/cache/nginx levels=2:2 keys_zone=default:100m;

Приведённой выше строкой создаётся двухуровневый кэш в каталоге /var/cache/nginx с именем 'default' и размером 100 мегабайт. Теперь определённый кэш default можно использовать в конфигурации серверов Nginx. Слегка дополненная конфигурация сервера, приводившаяся выше:

server {
    listen 8080;
    server_name test.ashep;
    access_log /var/log/nginx/test.access_log;
    error_log /var/log/nginx/test.error_log;
    location / {
        proxy_pass http://test.ashep:80;
        proxy_cache default;
        proxy_cache_valid   200 302 10m;
        proxy_cache_valid   404 1m;
    }
}

Обратите внимание на две новых опции. При помощи параметра proxy_cache мы указываем Nginx какой кэш необходимо использовать при кэшировании данных от upstream-сервера, в данном случае — это 'default', определённый ранее в /etc/nginx/nginx.conf. Опция proxy_cache_valid определяет время в течение которого не устаревшими будут считаться объекты кэша, полученные полученные в результате ответов upstream-сервера. Формат опции следующий:

proxy_cache_valid код_ответа [код_ответа код_ответа ...] время

Таким образом ответы upstream-сервера с кодами 200 и 302 будут кэшироваться на 10 минут, а ошибки 404 — в течение одной минуты.

Сохранив конфиг-файлы и перезапустив Nginx, попробуем провести нагрузочное тестирование с включённым кэшированием:

$ siege -c 10 -r 10 http://test.ashep:8080/test.php
Transactions:		         100 hits
Availability:		      100.00 %
Elapsed time:		       15.68 secs
Data transferred:	       32.65 MB
Response time:		        0.73 secs
Transaction rate:	        6.38 trans/sec
Throughput:		        2.08 MB/sec
Concurrency:		        4.65
Successful transactions:         100
Failed transactions:	           0
Longest transaction:	        9.51
Shortest transaction:	        0.02

Среднее время ответа от сервера составило 0,73 секунды. Неплохо, правда? ;)

Источник статьи