Как стать автором
Обновить

Комментарии 27

Добрый день, вы каким либо образом мониторите эффективность работы и настроек кеша nginx?
например увеличение времени жизни кеша 2 раза дает ли какой либо прирост?
Каких-то специальных метрик не снимали, эффективность работы можно проверить по графикам мониторинга — в нашем случае это zabbix.
Из графиков интересны показатели «число активных процессов», «количество соединений в секунду», вашего бэкенда(fpm/apache). Соответственно, чем ниже показатели, тем лучше.

Так как сбросом кэша управляете вы сами, можете смело увеличивать время кэширования.
Главное не переусердствовать, чтобы на каждую новую запись не происходило вытеснение, лишние операции на файловую систему никому не нужны.

В большинстве случаев рост нагрузки происходит равномерно и кэш основных страниц в пиковые моменты уже набран, а процент прохода на запрятанные url не так велик.

Если же вам это не подходит, можно самостоятельно прогревать кэш, также можете посмотреть в сторону директивы «proxy_cache_background_update».
А в чем смысл кэшировать nginx, а не redis, например?
Nginx кэш — это не замена основному кэшированию(redis/memcached/и тд), а скорее дополнение.
Наша задача — как можно меньше пропустить запросов на бэкенд.
Меньше запросов — меньше нагрузка на сервер.

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

В случае с redis все запросы проходят на бэкенд, и уже бэкенд, обращаясь к redis, формирует ответ.
Если же вы имели в виду модуль «ngx_http_redis_module», то его мы не рассматривали.

В свое время мы очень долго играли в игру "сделай кеш вместо разработчика".
В итоге когда нам удалось их заставить переписать приложение по человечески — все проблемы магическим образом исчезли.
Если не хотите по ночам разбираться почему вдруг анонимным пользователям показывает профиль (админа/другого юзера/подставить по вкусу) лучше вообще не лезть в эту сторону.

Ну, а что если использовать nginx cache для сервера который отдаёт статику: css/js/png/jpg/svg?

Это имеет смысл только если статика генерится бекендом, если же она просто лежит на диске то с точки зрения стоимости ресурсов кеш будет дороже
Но в любом случае приложение должно либо само уметь инвалидировать кеш либо все версии объектов должны иметь уникальные имена

Вполне возможно избежать перемешивания сессий анонима и админа.
В качестве примера можете посмотреть на проект Engintron. Это плагин к cPanel, который добавляет поддержку nginx.
В этом примере можете посмотреть как исключить кеш для важных локаций поплуярных CMS:
github.com/engintron/engintron/blob/master/nginx/proxy_params_dynamic
И таким образом можно добавить в исключения то, что не должно кэшироваться.

Я же не говорю что нельзя, можно, только будьте готовы к сюрпризам:


  1. разработчики не знают о существовании http_cache_control и зачем это нужно
  2. request_uri постоянно меняются (удаляются/добавляются)
  3. http_cookie поменяли а вам ничего не сказали

Метод вполне рабочий, но лучше таки идти путем исправления самого приложения
Добавляя кеш ну 50% вы выжмете в сторону увеличения производительности
А вот переписав код можно и 5000% — это вполне реальная цифра из личного опыта


Кстати расскажите мне как будет производиться инвалидация кеша при N+1 серверах фронта?

Директива “proxy_cache_purge” доступна как часть коммерческой подписки
а жаль, очень не хватает.

Она работает и в обычной версии. Только видимо нельзя инвалидировать с помощью PURGE.
У нас в проде используется такой подход:


proxy_cache_key "$host$request_filename";
....
        location ~ /drop(/.*) {
            allow *.*.*.*/*;
            deny all;
            proxy_cache_purge images "$host/usr/share/nginx/html$1";
        }

И все успешно инвалидируется, достаточно дописать /drop в начало пути.

cat $1 | tr "\n" " "
Антипаттерн. Команда cat вообще редко нужна в скриптах. Тут можно было бы написать так:
xargs < "$1"
> Возможные проблемы при кэшировании страниц

Еще одна проблема (кроме описанных тут закэшированных кукисов) это кэширование документа, сжатого каким-то одним алгоритмом (например brotli), и выдача его по запросу клиента, который не поддерживает этот алгоритм и не передавал его в заголовке запроса accept-encoding.
Vary: Accept-Encoding
Как верно подмечено, nginx хранит кеш в виде файлов. И тот же самый nginx точно также быстро отдает простые статические файлы. Поэтому, есть достаточно простой вариант, как обойтись без кеширования nginx. Ну или хотя бы частично.

Вот реальный пример этой идеи из продакшена проекта средней нагруженности:

Есть ресурс, который производит некоторые трансформации над изображениями, он расположен там же, на фронтенд сервере, где и стоит собственно nginx.

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

proxy_set_header X-IMAGE-CACHE-EXPIRY 31d; # s - sec, m - minute, h - hour, d - day

Бекенд проверяет время модификации файла, определяет актуальность ранее созданного файла на основе этого заголовка и отдает nginx-у либо 304, либо делает трансформацию и сохраняет свежий результат в файл с тем же именем. Nginx соотвественно, либо отдает 304, либо берет этот свежий файл и отдает его.

Теперь, если нам надо сбросить наш кеш для этой конкретной разновидности картинки, мы передаем этот header со значением "-1", либо если нужно сбросить весь кеш ставим в конфиге "-1", делаем рестарт nginx и ждем 5...10...15 минут. Точно также можно удалить весь наш локальный кеш, не останавливая nginx.

Методология хранения файлов в кеше самая простая, делаем MD5 из полного урла со всеми get параметрами, и создаем структуру хранения наших файлов:

/ab/cd/abcdxxxxxxxxxxxxxxxx

Смысл в том, чтобы не вызывать backend в принципе, там где его вызов не нужен.


Если Вы держите кэш в redis, то это будет обращение от nginx к бэкэнду,
бэкэнд должен будет обратиться к redis. В любом случае, это лишние задержки и лишняя нагрузка и на redis, и на backend.


Отдача на стороне nginx исключает эти задержки. Он просто отдаст клиенту бинарный файл с кэшем ответа.

Для Nginx есть модули redis/redis2, и не нужно обращаться к бэкэнду, чтоб сходить в redis, редис и будет бэкэндом для nginx

В редисе что хранится? Готовый бинарный ответ? Тогда, в принципе, да, можно наверное даже выиграть в скорости на небольших проектах. Если там лежат сырые данные (хотяб и скэшированные) из которых нужно сделать ответ, то это лишний оверхед.

Там хранится ответ, в ключе по урлу. html/json/etc, контент собственно.
Оверхед на генерацию хидеров? Не смешите, из кеша nginx делает практически всю ту же работу, а если учесть еще вырезание заголовков кук, то еще больше.
По скорости оно кстати вполне ок, у нас 1 сервер выдает овер 10кк хитов html5 баннеров в сутки. И это виртуалка 1 ядро, 4 gb ram.

Если благодаря директиве proxy_cache_bypass nginx обратился к бекенду, то он обновит свой кэш новым ответом, или нет?

Да.
Все верно, если любой из параметров «proxy_cache_bypass» не пустота и не «0», тогда запрос отправится на бэкенд. При этом полученный результат будет сохранен в кэш.
Если вам не нужно сохранять ответ от севера в кэш, то используйте совместно с директивой «proxy_no_cache».
Тоже использую Nginx как быстрый кеширующий SSL реверс-прокси. Пробовал сначала Varnish, с ним гораздо проще, но увы, он не умеет в HTTPS.
proxy_ignore_headers — там же вроде все немного по другому, по дефолту nginx не кеширует с куками (что выглядит правильным — user-specific контент не закешируешь), а сейчас вы наоборот, заставляете это делать, и работа сайта может быть нарушена во многопользовательской среде?
Боюсь, что в nginx кэш попадает весь результат, полученный от сервера — как содержимое, так и заголовки. Вся работа nginx заключается в том, чтобы собрать ключ страницы по правилу из «proxy_cache_key», проверить кэш, и если он валиден, вернуть его клиенту, либо вначале сходить на бэкенд.
Понятия уникальности контента пользователя для nginx нет. Поэтому все, что ему вернуть, он с радостью сохранит.
Директива «proxy_ignore_headers» помогает нам указать, какие заголовки не следует обрабатывать от бэкенда. Как следствие — nginx будет их игнорировать и клиенту они не дойдут.
Вы смешали действие директив proxy_ignore_headers и proxy_hide_header. Директива proxy_ignore_headers не уберет заголовок из ответа клиенту, а лишь предотвратит его влияние на кэшируемость ответа.

Если вы хотити чтобы заголовок не передавался клиенту, то необходимо использовать директиву proxy_hide_header.

Хороший туториал!
Тоже несколько лет назад приходилось настраивать кэширование на уровне nginx. Решили избавиться от генерации превьюшек при загрузке фото, т.к. очень часто они не нужны, а место занимают + когда требуется новый размер превью — либо городить костыли, либо генерирвать новый сет превьюшек из терабайтов фото…
Теперь актуальный набор превьюшек вмещается в ~60GB (ну экономия по приблизительным оценкам получилась минимум порядок), а то что отсутствует в кэше — уже проксируется на бэкенды и потом складывается в кэш на недельку.


Самое плохое что случалось — кэширование сессионных печенек, но это уже просто криворукость отдельного меня была :))


Ну и не хватает модуля для просмотра статистики кэширования (сколько ревалидаций, сколько промахов, сколько хитов...), пришлось самому писать, но использовали его только по началу, потом просто отпала необходимость в статистике, да и обнаруживались всякие странности в работе этого модуля. Может быть кому-нибудь пригодится для экспериментов: https://github.com/SakhCom/ngx_cache_status_module/

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.