srcache: Прозрачная кэширование на основе подсетевых запросов для произвольных местоположений NGINX
Установка
Вы можете установить этот модуль в любом дистрибутиве на базе RHEL, включая, но не ограничиваясь:
- RedHat Enterprise Linux 7, 8, 9 и 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-srcache
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-srcache
Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:
load_module modules/ngx_http_srcache_filter_module.so;
Этот документ описывает nginx-module-srcache v0.32, выпущенный 28 июня 2022 года.
upstream my_memcached {
server 10.62.136.7:11211;
keepalive 10;
}
location = /memc {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
memc_ignore_client_abort on;
set $memc_key $query_string;
set $memc_exptime 300;
memc_pass my_memcached;
}
location /foo {
set $key $uri$args;
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
srcache_store_statuses 200 301 302 307 308;
# proxy_pass/fastcgi_pass/drizzle_pass/echo/etc...
# или даже статические файлы на диске
}
location = /memc2 {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
memc_ignore_client_abort on;
set_unescape_uri $memc_key $arg_key;
set $memc_exptime $arg_exptime;
memc_pass unix:/tmp/memcached.sock;
}
location /bar {
set_escape_uri $key $uri$args;
srcache_fetch GET /memc2 key=$key;
srcache_store PUT /memc2 key=$key&exptime=$srcache_expire;
# proxy_pass/fastcgi_pass/drizzle_pass/echo/etc...
# или даже статические файлы на диске
}
map $request_method $skip_fetch {
default 0;
POST 1;
PUT 1;
}
server {
listen 8080;
location /api/ {
set $key "$uri?$args";
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
srcache_methods GET PUT POST;
srcache_fetch_skip $skip_fetch;
# proxy_pass/drizzle_pass/content_by_lua/echo/...
}
}
Описание
Этот модуль предоставляет прозрачный кэширующий слой для произвольных местоположений nginx (например, тех, которые используют upstream или даже обслуживают статические файлы с диска). Поведение кэширования в основном совместимо с RFC 2616.
Обычно модуль memc-nginx-module используется вместе с этим модулем для предоставления конкретного кэшируемого хранилища. Но технически любые модули, которые предоставляют REST-интерфейс, могут использоваться в качестве подсетевых запросов для извлечения и хранения, используемых этим модулем.
Для основных запросов директива srcache_fetch работает в конце фазы доступа, поэтому директивы allow и deny стандартного модуля доступа ngx_http_access_module выполняются до нашей, что обычно является желаемым поведением по соображениям безопасности.
Рабочий процесс этого модуля выглядит следующим образом:

Кэширование подсетевых запросов
Для подсетевых запросов мы явно запрещаем использование этого модуля, потому что это слишком сложно сделать правильно. Ранее существовала реализация, но она была с ошибками, и я в конце концов сдался, пытаясь ее исправить, и забросил ее.
Тем не менее, если вы используете lua-nginx-module, легко сделать кэширование подсетевых запросов на Lua самостоятельно. То есть сначала выполните подсетевой запрос к местоположению memc-nginx-module для явного поиска в кэше, если кэш попадает, просто используйте возвращенные кэшированные данные; в противном случае вернитесь к истинному бэкенду и, наконец, выполните вставку в кэш, чтобы добавить данные в кэш.
Использование этого модуля для кэширования основных запросов и Lua для кэширования подсетевых запросов — это подход, который мы используем в нашем бизнесе. Это гибридное решение отлично работает в производстве.
Распределенное кэширование Memcached
Вот простой пример, демонстрирующий распределенный механизм кэширования memcached, построенный на основе этого модуля. Предположим, у нас есть три разных узла memcached, и мы используем простой модуль для хеширования наших ключей.
http {
upstream moon {
server 10.62.136.54:11211;
server unix:/tmp/memcached.sock backup;
}
upstream earth {
server 10.62.136.55:11211;
}
upstream sun {
server 10.62.136.56:11211;
}
upstream_list universe moon earth sun;
server {
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
location = /memc {
internal;
set $memc_key $query_string;
set_hashed_upstream $backend universe $memc_key;
set $memc_exptime 3600; # в секундах
memc_pass $backend;
}
location / {
set $key $uri;
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
# proxy_pass/fastcgi_pass/content_by_lua/drizzle_pass/...
}
}
}
Вот что происходит в приведенном выше примере:
1. Сначала мы определяем три upstream, moon, earth и sun. Это наши три сервера memcached.
2. Затем мы группируем их вместе в единое целое под названием universe с помощью директивы upstream_list, предоставленной set-misc-nginx-module.
3. После этого мы определяем внутреннее местоположение с именем /memc для общения с кластером memcached.
4. В этом местоположении /memc мы сначала устанавливаем переменную $memc_key с помощью строки запроса ($args), а затем используем директиву set_hashed_upstream для хеширования нашего $memc_key по списку upstream universe, чтобы получить конкретное имя upstream, которое будет присвоено переменной $backend.
5. Мы передаем эту переменную $backend в директиву memc_pass. Переменная $backend может содержать значение среди moon, earth и sun.
6. Также мы определяем время истечения кэширования memcached в 3600 секунд (т.е. час), переопределяя переменную $memc_exptime.
7. В нашем основном публичном местоположении / мы настраиваем переменную $uri как наш ключ кэша, а затем настраиваем srcache_fetch для поиска в кэше и srcache_store для обновления кэша. Мы используем два подсетевых запроса к нашему местоположению /memc, определенному ранее, в этих двух директивах.
Можно использовать директивы set_by_lua или rewrite_by_lua из lua-nginx-module, чтобы внедрить пользовательский код Lua для вычисления переменных $backend и/или $key в приведенном выше примере.
Следует учесть, что memcached имеет ограничения по длине ключей, т.е. 250 байт, поэтому для ключей, которые могут быть очень длинными, можно использовать директиву set_md5 или ее аналоги, чтобы предварительно хешировать ключ в фиксированное значение перед присвоением его переменной $memc_key в местоположении /memc или подобном.
Кроме того, можно использовать директивы srcache_fetch_skip и srcache_store_skip, чтобы контролировать, что кэшировать, а что нет, на основе каждого запроса, и Lua также можно использовать здесь аналогичным образом. Таким образом, возможности действительно безграничны.
Чтобы максимизировать скорость, мы часто включаем пул соединений TCP (или Unix Domain Socket) для наших upstream memcached, предоставляемых HttpUpstreamKeepaliveModule, например,
upstream moon {
server 10.62.136.54:11211;
server unix:/tmp/memcached.sock backup;
keepalive 10;
}
где мы определяем пул соединений, который содержит до 10 соединений с поддержкой живости (на каждый рабочий процесс nginx) для нашего upstream moon (кластера).
Кэширование с Redis
Redis — это альтернативное хранилище ключ-значение с множеством дополнительных функций.
Вот рабочий пример с использованием модуля lua-resty-redis:
location ~ '\.php$|^/update.php' {
# настройка кэша
set $key $request_uri;
try_files $uri =404;
srcache_fetch_skip $skip_cache;
srcache_store_skip $skip_cache;
srcache_response_cache_control off;
srcache_store_statuses 200 201 301 302 307 308 404 503;
set_escape_uri $escaped_key $key;
srcache_fetch GET /redis-fetch $key;
srcache_store PUT /redis-store key=$escaped_key;
more_set_headers 'X-Cache-Fetch-Status $srcache_fetch_status';
more_set_headers 'X-Cache-Store-Status $srcache_store_status';
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
# Примечание по безопасности: Если вы используете версию PHP старше
# последней 5.3, у вас должно быть "cgi.fix_pathinfo = 0;" в php.ini.
# См. http://serverfault.com/q/627903/94922 для получения подробной информации.
include fastcgi_params;
# Блокировка атак httproxy. См. https://httpoxy.org/.
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
fastcgi_pass upstream-name;
}
location /redis-fetch {
internal;
resolver 8.8.8.8 valid=300s;
resolver_timeout 10s;
content_by_lua_block {
local key = assert(ngx.var.request_uri, "no key found")
local redis = require "resty.redis"
local red, err = redis:new()
if not red then
ngx.log(ngx.ERR, "Не удалось создать переменную redis, ошибка -> ", err)
ngx.exit(500)
end
assert(red:connect("redis-master.default.svc.cluster.local", 6379))
if not red then
ngx.log(ngx.ERR, "Не удалось подключиться к redis, ошибка -> ", err)
ngx.exit(500)
end
local res, err = red:auth("redispassword")
if not res then
ngx.say("не удалось аутентифицироваться, ", err)
ngx.exit(500)
end
local data = assert(red:get(key))
assert(red:set_keepalive(10000, 100))
if res == ngx.null then
return ngx.exit(404)
end
ngx.print(data)
}
}
location /redis-store {
internal;
resolver 8.8.8.8 valid=300s;
resolver_timeout 10s;
content_by_lua_block {
local value = assert(ngx.req.get_body_data(), "no value found")
local key = assert(ngx.var.request_uri, "no key found")
local redis = require "resty.redis"
local red, err = redis:new()
if not red then
ngx.log(ngx.ERR, "Не удалось создать переменную redis, ошибка -> ", err)
ngx.exit(500)
end
assert(red:connect("redis-master.default.svc.cluster.local", 6379))
if not red then
ngx.log(ngx.ERR, "Не удалось подключиться к redis, ошибка -> ", err)
ngx.exit(500)
end
local res, err = red:auth("redispassword")
if not res then
ngx.say("не удалось аутентифицироваться, ", err)
ngx.exit(500)
end
local data = assert(red:set(key, value))
assert(red:set_keepalive(10000, 100))
if res == ngx.null then
return ngx.exit(404)
end
}
}
Вот рабочий пример с использованием модулей HTTPRedis (fetch) и Redis2 (store):
location /api {
default_type text/css;
set $key $uri;
set_escape_uri $escaped_key $key;
srcache_fetch GET /redis $key;
srcache_store PUT /redis2 key=$escaped_key&exptime=120;
# fastcgi_pass/proxy_pass/drizzle_pass/postgres_pass/echo/etc
}
location = /redis {
internal;
set_md5 $redis_key $args;
redis_pass 127.0.0.1:6379;
}
location = /redis2 {
internal;
set_unescape_uri $exptime $arg_exptime;
set_unescape_uri $key $arg_key;
set_md5 $key;
redis2_query set $key $echo_request_body;
redis2_query expire $key $exptime;
redis2_pass 127.0.0.1:6379;
}
Этот пример использует переменную $echo_request_body, предоставленную echo-nginx-module. Обратите внимание, что вам нужна последняя версия echo-nginx-module, v0.38rc2, поскольку более ранние версии могут работать ненадежно.
Кроме того, вам нужны как HttpRedisModule, так и redis2-nginx-module. Первый используется в подсетевом запросе srcache_fetch, а второй — в подсетевом запросе srcache_store.
У ядра Nginx также есть ошибка, которая может помешать поддержке конвейеризации redis2-nginx-module работать должным образом в определенных экстремальных условиях. И следующий патч исправляет это:
http://mailman.nginx.org/pipermail/nginx-devel/2012-March/002040.html
Обратите внимание, однако, что если вы используете пакет OpenResty версии 1.0.15.3 или более поздней, то у вас уже есть все необходимое в этом пакете.
Предобработка ключа кэша
Часто требуется предварительно обработать ключ кэша, чтобы исключить случайные шумы, которые могут повредить коэффициент попадания в кэш. Например, случайные идентификаторы сессий в аргументах URI обычно следует удалить.
Рассмотрим следующую строку запроса URI:
SID=BC3781C3-2E02-4A11-89CF-34E5CFE8B0EF&UID=44332&L=EN&M=1&H=1&UNC=0&SRC=LK&RT=62
мы хотим удалить аргументы SID и UID из нее. Это легко достижимо, если вы используете lua-nginx-module одновременно:
location = /t {
rewrite_by_lua '
local args = ngx.req.get_uri_args()
args.SID = nil
args.UID = nil
ngx.req.set_uri_args(args)
';
echo $args;
}
Здесь мы используем директиву echo из echo-nginx-module, чтобы вывести конечное значение $args в конце. Вы можете заменить это на ваши конфигурации srcache-nginx-module и конфигурации upstream вместо вашего случая. Давайте протестируем этот интерфейс /t с помощью curl:
$ curl 'localhost:8081/t?RT=62&SID=BC3781C3-2E02-4A11-89CF-34E5CFE8B0EF&UID=44332&L=EN&M=1&H=1&UNC=0&SRC=LK'
M=1&UNC=0&RT=62&H=1&L=EN&SRC=LK
Стоит отметить, что если вы хотите сохранить порядок аргументов URI, вы можете выполнить строковые замены на значение $args напрямую, например,
location = /t {
rewrite_by_lua '
local args = ngx.var.args
newargs, n, err = ngx.re.gsub(args, [[\b[SU]ID=[^&]*&?]], "", "jo")
if n and n > 0 then
ngx.var.args = newargs
end
';
echo $args;
}
Теперь протестируем это с оригинальной командой curl снова, и мы получаем именно то, что ожидаем:
RT=62&L=EN&M=1&H=1&UNC=0&SRC=LK
Но для целей кэширования хорошо нормализовать порядок аргументов URI, чтобы увеличить коэффициент попадания в кэш. И порядок записей хеш-таблицы, используемой LuaJIT или Lua, может быть использован для нормализации порядка как приятный побочный эффект.
Директивы
srcache_fetch
синтаксис: srcache_fetch <method> <uri> <args>?
по умолчанию: нет
контекст: http, server, location, location if
фаза: post-access
Эта директива регистрирует обработчик фазы доступа, который будет выполнять подсетевой запрос Nginx для поиска в кэше.
Когда подсетевой запрос возвращает код состояния, отличный от 200, это сигнализирует о промахе кэша, и управление будет продолжено к более поздним фазам, включая фазу контента, настроенную модулем ngx_http_proxy_module, ngx_http_fastcgi_module и другим. Если подсетевой запрос возвращает 200 OK, это сигнализирует о попадании в кэш, и этот модуль отправит ответ подсетевого запроса как ответ текущего основного запроса клиенту напрямую.
Эта директива всегда будет выполняться в конце фазы доступа, так что allow и deny модуля ngx_http_access_module всегда будут выполняться до этой.
Вы можете использовать директиву srcache_fetch_skip, чтобы выборочно отключить поиск в кэше.
srcache_fetch_skip
синтаксис: srcache_fetch_skip <flag>
по умолчанию: srcache_fetch_skip 0
контекст: http, server, location, location if
фаза: post-access
Аргумент <flag> поддерживает переменные nginx. Когда значение этого аргумента не пусто и не равно 0, процесс извлечения будет безусловно пропущен.
Например, чтобы пропустить кэширование запросов, которые имеют cookie с именем foo со значением bar, мы можем написать
location / {
set $key ...;
set_by_lua $skip '
if ngx.var.cookie_foo == "bar" then
return 1
end
return 0
';
srcache_fetch_skip $skip;
srcache_store_skip $skip;
srcache_fetch GET /memc $key;
srcache_store GET /memc $key;
# proxy_pass/fastcgi_pass/content_by_lua/...
}
$skip на (более ранней) фазе переписывания. Аналогично, переменную $key можно вычислить с помощью Lua, используя директиву set_by_lua или rewrite_by_lua.
Стандартная директива map также может быть использована для вычисления значения переменной $skip, используемой в приведенном выше примере:
map $cookie_foo $skip {
default 0;
bar 1;
}
но ваше выражение map должно быть помещено в блок конфигурации http в вашем файле nginx.conf.
srcache_store
синтаксис: srcache_store <method> <uri> <args>?
по умолчанию: нет
контекст: http, server, location, location if
фаза: output-filter
Эта директива регистрирует обработчик фильтра вывода, который выполнит подсетевой запрос Nginx для сохранения ответа текущего основного запроса в кэшируемом бэкенде. Код состояния подсетевого запроса будет проигнорирован.
Вы можете использовать директивы srcache_store_skip и srcache_store_max_size, чтобы отключить кэширование для определенных запросов в случае промаха кэша.
Начиная с релиза v0.12rc7, в кэш будут помещены как строка ответа, заголовки ответа, так и тела ответа. По умолчанию следующие специальные заголовки ответа не будут кэшироваться:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailers
- Transfer-Encoding
- Upgrade
- Set-Cookie
Вы можете использовать директивы srcache_store_pass_header и/или srcache_store_hide_header, чтобы контролировать, какие заголовки кэшировать, а какие нет.
Данные оригинального ответа передаются сразу, как только они поступают. srcache_store просто копирует и собирает данные в фильтре вывода, не откладывая их отправку вниз по потоку.
Но обратите внимание, что даже если все данные ответа будут отправлены немедленно, текущий срок жизни запроса Nginx не завершится, пока не завершится подсетевой запрос srcache_store. Это означает задержку в закрытии TCP-соединения на стороне сервера (когда HTTP keepalive отключен, но правильные HTTP-клиенты должны активно закрывать соединение на стороне клиента, что не добавляет никаких дополнительных задержек или других проблем) или обслуживании следующего запроса, отправленного по тому же TCP-соединению (когда HTTP keepalive в действии).
srcache_store_max_size
синтаксис: srcache_store_max_size <size>
по умолчанию: srcache_store_max_size 0
контекст: http, server, location, location if
фаза: output-header-filter
Когда длина тела ответа превышает этот размер, этот модуль не будет пытаться сохранить тело ответа в кэше, используя шаблон подсетевого запроса, указанный в srcache_store.
Это особенно полезно при использовании кэшируемого хранилища, которое имеет жесткий верхний предел на входные данные. Например, сервер Memcached имеет стандартный лимит в 1 МБ на элемент.
Когда указано 0 (значение по умолчанию), никаких проверок на лимит не будет.
srcache_store_skip
синтаксис: srcache_store_skip <flag>
по умолчанию: srcache_store_skip 0
контекст: http, server, location, location if
фаза: output-header-filter
Аргумент <flag> поддерживает переменные Nginx. Когда значение этого аргумента не пусто и не равно 0, процесс сохранения будет безусловно пропущен.
Начиная с релиза v0.25, выражение <flag> (возможно, содержащее переменные Nginx) может быть оценено до двух раз: первый раз сразу после отправки заголовка ответа, а когда выражение <flag> не оценивается в истинные значения, оно будет оценено снова сразу после окончания потока данных тела ответа. До v0.25 выполнялась только первая оценка.
Вот пример использования Lua для установки $nocache, чтобы избежать сохранения URI, содержащих строку "/tmp":
set_by_lua $nocache '
if string.match(ngx.var.uri, "/tmp") then
return 1
end
return 0';
srcache_store_skip $nocache;
srcache_store_statuses
синтаксис: srcache_store_statuses <status1> <status2> ..
по умолчанию: srcache_store_statuses 200 301 302 307 308
контекст: http, server, location, location if
фаза: output-header-filter
Эта директива контролирует, какие ответы сохранять в кэше в зависимости от их кода состояния.
По умолчанию только ответы с кодами 200, 301, 302, 307 и 308 будут сохранены в кэше, а любые другие ответы пропустят srcache_store.
Вы можете указать произвольные положительные числа для кода состояния ответа, который вы хотите кэшировать, даже включая коды ошибок, такие как 404 и 503. Например:
srcache_store_statuses 200 201 301 302 307 308 404 503;
Должен быть указан хотя бы один аргумент для этой директивы.
Эта директива была впервые введена в релизе v0.13rc2.
srcache_store_ranges
синтаксис: srcache_store_ranges on|off
по умолчанию: srcache_store_ranges off
контекст: http, server, location, location if
фаза: output-body-filter
Когда эта директива включена (по умолчанию off), srcache_store также будет сохранять ответы 206 Partial Content, сгенерированные стандартным модулем ngx_http_range_filter_module. Если вы включите эту директиву, вы ДОЛЖНЫ добавить $http_range к вашим ключам кэша. Например,
location / {
set $key "$uri$args$http_range";
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
}
Эта директива была впервые введена в релизе v0.27.
srcache_header_buffer_size
синтаксис: srcache_header_buffer_size <size>
по умолчанию: srcache_header_buffer_size 4k/8k
контекст: http, server, location, location if
фаза: output-header-filter
Эта директива контролирует буфер заголовка при сериализации заголовков ответа для srcache_store. Размер по умолчанию — это размер страницы, обычно 4k или 8k в зависимости от конкретных платформ.
Обратите внимание, что буфер не используется для хранения всех заголовков ответа, а только для каждого отдельного заголовка. Таким образом, буфер должен быть достаточно большим, чтобы вместить самый длинный заголовок ответа.
Эта директива была впервые введена в релизе v0.12rc7.
srcache_store_hide_header
синтаксис: srcache_store_hide_header <header>
по умолчанию: нет
контекст: http, server, location, location if
фаза: output-header-filter
По умолчанию этот модуль кэширует все заголовки ответа, кроме следующих:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailers
- Transfer-Encoding
- Upgrade
- Set-Cookie
Вы можете скрыть еще больше заголовков ответа от srcache_store, перечислив их имена (без учета регистра) с помощью этой директивы. Например,
srcache_store_hide_header X-Foo;
srcache_store_hide_header Last-Modified;
Разрешены несколько вхождений этой директивы в одном местоположении.
Эта директива была впервые введена в релизе v0.12rc7.
См. также srcache_store_pass_header.
srcache_store_pass_header
синтаксис: srcache_store_pass_header <header>
по умолчанию: нет
контекст: http, server, location, location if
фаза: output-header-filter
По умолчанию этот модуль кэширует все заголовки ответа, кроме следующих:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailers
- Transfer-Encoding
- Upgrade
- Set-Cookie
Вы можете заставить srcache_store сохранить один или несколько из этих заголовков ответа, перечислив их имена (без учета регистра) с помощью этой директивы. Например,
srcache_store_pass_header Set-Cookie;
srcache_store_pass_header Proxy-Autenticate;
Разрешены несколько вхождений этой директивы в одном местоположении.
Эта директива была впервые введена в релизе v0.12rc7.
См. также srcache_store_hide_header.
srcache_methods
синтаксис: srcache_methods <method>...
по умолчанию: srcache_methods GET HEAD
контекст: http, server, location
фаза: post-access, output-header-filter
Эта директива указывает HTTP-методы запросов, которые учитываются либо srcache_fetch, либо srcache_store. HTTP-методы запросов, не указанные в списке, будут полностью пропущены из кэша.
Разрешены следующие HTTP-методы: GET, HEAD, POST, PUT и DELETE. Методы GET и HEAD всегда неявно включены в список, независимо от их присутствия в этой директиве.
Обратите внимание, что начиная с релиза v0.17 запросы HEAD всегда пропускаются srcache_store, поскольку их ответы никогда не содержат тела ответа.
Эта директива была впервые введена в релизе v0.12rc7.
srcache_ignore_content_encoding
синтаксис: srcache_ignore_content_encoding on|off
по умолчанию: srcache_ignore_content_encoding off
контекст: http, server, location, location if
фаза: output-header-filter
Когда эта директива выключена (что является значением по умолчанию), непустой заголовок ответа Content-Encoding приведет к тому, что srcache_store пропустит сохранение всего ответа в кэш и выдаст предупреждение в файле error.log Nginx, например:
[warn] 12500#0: *1 srcache_store пропущен из-за заголовка ответа "Content-Encoding: gzip"
(возможно, вы забыли отключить сжатие на бэкенде?)
Включение этой директивы проигнорирует заголовок ответа Content-Encoding и сохранит ответ как обычно (и также без предупреждения).
Рекомендуется всегда отключать сжатие gzip/deflate на вашем сервере бэкенда, указав следующую строку в вашем файле nginx.conf:
proxy_set_header Accept-Encoding "";
Эта директива была впервые введена в релизе v0.12rc7.
srcache_request_cache_control
синтаксис: srcache_request_cache_control on|off
по умолчанию: srcache_request_cache_control off
контекст: http, server, location
фаза: post-access, output-header-filter
Когда эта директива включена, заголовки запроса Cache-Control и Pragma будут учитываться этим модулем следующими способами:
- srcache_fetch, т.е. операция поиска в кэше, будет пропущена, когда присутствуют заголовки запроса
Cache-Control: no-cacheи/илиPragma: no-cache. - srcache_store, т.е. операция сохранения в кэше, будет пропущена, когда указан заголовок запроса
Cache-Control: no-store.
Выключение этой директивы отключит эту функциональность и считается более безопасным для загруженных сайтов, в основном полагающихся на кэш для скорости.
Эта директива была впервые введена в релизе v0.12rc7.
См. также srcache_response_cache_control.
srcache_response_cache_control
синтаксис: srcache_response_cache_control on|off
по умолчанию: srcache_response_cache_control on
контекст: http, server, location
фаза: output-header-filter
Когда эта директива включена, заголовки ответа Cache-Control и Expires будут учитываться этим модулем следующими способами:
Cache-Control: privateпропускает srcache_store,Cache-Control: no-storeпропускает srcache_store,Cache-Control: no-cacheпропускает srcache_store,Cache-Control: max-age=0пропускает srcache_store,- и
Expires: <date-no-more-recently-than-now>пропускает srcache_store.
Эта директива имеет приоритет над директивами srcache_store_no_store, srcache_store_no_cache и srcache_store_private.
Эта директива была впервые введена в релизе v0.12rc7.
См. также srcache_request_cache_control.
srcache_store_no_store
синтаксис: srcache_store_no_store on|off
по умолчанию: srcache_store_no_store off
контекст: http, server, location
фаза: output-header-filter
Включение этой директивы заставит ответы с заголовком Cache-Control: no-store сохраняться в кэше, когда srcache_response_cache_control включена и выполнены другие условия. По умолчанию значение off.
Эта директива была впервые введена в релизе v0.12rc7.
srcache_store_no_cache
синтаксис: srcache_store_no_cache on|off
по умолчанию: srcache_store_no_cache off
контекст: http, server, location
фаза: output-header-filter
Включение этой директивы заставит ответы с заголовком Cache-Control: no-cache сохраняться в кэше, когда srcache_response_cache_control включена и выполнены другие условия. По умолчанию значение off.
Эта директива была впервые введена в релизе v0.12rc7.
srcache_store_private
синтаксис: srcache_store_private on|off
по умолчанию: srcache_store_private off
контекст: http, server, location
фаза: output-header-filter
Включение этой директивы заставит ответы с заголовком Cache-Control: private сохраняться в кэше, когда srcache_response_cache_control включена и выполнены другие условия. По умолчанию значение off.
Эта директива была впервые введена в релизе v0.12rc7.
srcache_default_expire
синтаксис: srcache_default_expire <time>
по умолчанию: srcache_default_expire 60s
контекст: http, server, location, location if
фаза: output-header-filter
Эта директива контролирует стандартный период времени истечения, который разрешен для значения переменной $srcache_expire, когда ни Cache-Control: max-age=N, ни Expires не указаны в заголовках ответа.
Значения аргумента <time> по умолчанию указаны в секундах. Но разумно всегда явно указывать единицу времени, чтобы избежать путаницы. Поддерживаемые единицы времени: "s" (секунды), "ms" (миллисекунды), "y" (годы), "M" (месяцы), "w" (недели), "d" (дни), "h" (часы) и "m" (минуты). Например,
srcache_default_expire 30m; # 30 минут
Это время должно быть меньше 597 часов.
Семантика нулевого времени истечения зависит от фактического хранилища кэша, которое вы в данный момент используете, что не имеет отношения к этому модулю. В случае memcached, например, нулевые времена истечения означают, что элемент никогда не истечет.
Эта директива была впервые введена в релизе v0.12rc7.
srcache_max_expire
синтаксис: srcache_max_expire <time>
по умолчанию: srcache_max_expire 0
контекст: http, server, location, location if
фаза: output-header-filter
Эта директива контролирует максимальный период времени истечения, который разрешен для значения переменной $srcache_expire. Эта настройка имеет приоритет над другими методами вычисления.
Значения аргумента <time> по умолчанию указаны в секундах. Но разумно всегда явно указывать единицу времени, чтобы избежать путаницы. Поддерживаемые единицы времени: "s" (секунды), "ms" (миллисекунды), "y" (годы), "M" (месяцы), "w" (недели), "d" (дни), "h" (часы) и "m" (минуты). Например,
srcache_max_expire 2h; # 2 часа
Это время должно быть меньше 597 часов.
Когда указано 0, что является значением по умолчанию, то не будет никаких ограничений.
Эта директива была впервые введена в релизе v0.12rc7.
Переменные
$srcache_expire
тип: integer
кэшируемая: нет
записываемая: нет
Эта переменная Nginx дает рекомендуемый период времени истечения (в секундах) для текущего ответа, который сохраняется в кэше. Алгоритм вычисления значения следующий:
- Когда заголовок ответа
Cache-Control: max-age=Nуказан, тоNбудет использован как время истечения, - в противном случае, если заголовок ответа
Expiresуказан, то время истечения будет получено путем вычитания текущей временной метки из времени, указанного в заголовкеExpires, - когда ни заголовки
Cache-Control: max-age=N, ниExpiresне указаны, используйте значение, указанное в директиве srcache_default_expire.
Конечное значение этой переменной будет равно значению, указанному в директиве srcache_max_expire, если значение, полученное в алгоритме выше, превышает максимальное значение (если таковое имеется).
Вам не обязательно использовать эту переменную для времени истечения.
Эта переменная была впервые введена в релизе v0.12rc7.
$srcache_fetch_status
тип: string
кэшируемая: нет
записываемая: нет
Эта переменная Nginx оценивается по статусу фазы "извлечения" для системы кэширования. Возможны три значения: HIT, MISS и BYPASS.
Когда подсетевой запрос "извлечения" возвращает код состояния, отличный от 200, или его данные ответа не являются корректными, эта переменная оценивается в значение MISS.
Значение этой переменной имеет смысл только после фазы обработки запроса access, или всегда дается BYPASS.
Эта переменная была впервые введена в релизе v0.14.
$srcache_store_status
тип: string
кэшируемая: нет
записываемая: нет
Эта переменная Nginx дает текущий статус кэширования для фазы "сохранения". Можно получить два возможных значения: STORE и BYPASS.
Поскольку ответы для подсетевого запроса "сохранения" всегда игнорируются, значение этой переменной всегда будет STORE, пока подсетевой запрос "сохранения" действительно выполняется.
Значение этой переменной имеет смысл только тогда, когда заголовки запроса текущего (основного) запроса отправляются. Конечный результат можно получить только после того, как все тело ответа будет отправлено, если заголовок ответа Content-Length не указан для основного запроса.
Эта переменная была впервые введена в релизе v0.14.
Известные проблемы
- На некоторых системах включение aio и/или sendfile может остановить работу srcache_store. Вы можете отключить их в местоположениях, настроенных с помощью srcache_store.
- Директива srcache_store не может быть использована для захвата ответов, сгенерированных директивами подсетевых запросов echo-nginx-module, такими как echo_subrequest_async и echo_location. Рекомендуется использовать HttpLuaModule для инициации и захвата подсетевых запросов, которые должны работать с srcache_store.
Предостережения
- Рекомендуется отключить сжатие gzip вашего сервера бэкенда и использовать модуль Nginx ngx_http_gzip_module для выполнения этой задачи. В случае ngx_http_proxy_module вы можете использовать следующую настройку конфигурации, чтобы отключить сжатие gzip на бэкенде:
proxy_set_header Accept-Encoding ""; - Не используйте директиву if модуля ngx_http_rewrite_module в том же местоположении, что и этот модуль, потому что "if — это зло". Вместо этого используйте ngx_http_map_module или lua-nginx-module в сочетании с директивами srcache_store_skip и/или srcache_fetch_skip этого модуля. Например:
map $request_method $skip_fetch { default 0; POST 1; PUT 1; } server { listen 8080; location /api/ { set $key "$uri?$args"; srcache_fetch GET /memc $key; srcache_store PUT /memc $key; srcache_methods GET PUT POST; srcache_fetch_skip $skip_fetch; # proxy_pass/drizzle_pass/content_by_lua/echo/... } }
Устранение неполадок
Чтобы отладить проблемы, вы всегда должны сначала проверять файл error.log Nginx. Если сообщения об ошибках не выводятся, вам нужно включить отладочные логи Nginx, чтобы получить больше деталей, как объясняется в debugging log.
Несколько распространенных ошибок для новичков:
- Оригинальный ответ содержит заголовок
Cache-Control, который явно отключает кэширование, и вы не настраиваете директивы, такие как srcache_response_cache_control. - Оригинальный ответ уже сжат с помощью gzip, который по умолчанию не кэшируется (см. srcache_ignore_content_encoding).
- Memcached может вернуть
CLIENT_ERROR bad command line format, когда используется слишком длинный ключ (250 символов на версии 1.4.25). Поэтому безопаснее использоватьset_md5 $key $uri$args;вместоset $key $uri$args;. Директиваset_md5(и другие) доступны из модуля OpenResty set-misc. - Nginx может вернуть
client intended to send too large body, когда пытается сохранить объекты размером более 1 м в хранилище, в этом случаеclient_max_body_sizeNginx должен быть установлен на более высокое значение. - Memcached может не сохранять объекты размером более 1 м, вызывая ошибки, такие как
srcache_store subrequest failed status=502. Начиная с версии 1.4.2, memcached поддерживает командную опцию-I, чтобы переопределить стандартный размер каждой страницы. Пожалуйста, прочитайте его man-страницу для получения дополнительной информации.
Набор тестов
Этот модуль поставляется с набором тестов на Perl. Тестовые случаи также являются декларативными. Спасибо модулю Test::Nginx в мире Perl.
Чтобы запустить его у себя:
$ PATH=/path/to/your/nginx-with-srcache-module:$PATH prove -r t
Поскольку один сервер nginx (по умолчанию, localhost:1984) используется во всех тестовых скриптах (.t файлы), бессмысленно запускать набор тестов параллельно, указывая -jN, когда вы вызываете утилиту prove.
Некоторые части набора тестов требуют, чтобы модули ngx_http_rewrite_module, echo-nginx-module, rds-json-nginx-module и drizzle-nginx-module также были включены при сборке Nginx.
См. также
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-srcache.