Как очистить (удалить/обнулить/сбросить) cache в nginx?

Если вы активно используете встроенные в nginx функции кеширования, то рано или поздно может возникнуть ситуация, когда вам будет необходимо очистить текущий кеш, например, после обновления стилей css или рекламных блоков, чтобы ваши посетители сразу же увидели изменения, а не дожидались, когда кеш обновится из-за истечения срока его действия.
Удаление всего кеша с диска
Для очистки кеша в nginx достаточно просто удалить все файлы кеша, которые создал nginx в процессе своей работы. В зависимости от типа используемого прокси, файлы могут лежать в разных директориях.
При использовании proxy_cache
Местоположение каталога, в котором будут хранится закешированные ресурсы, определяется параметром proxy_cache_path в конфигурационном файле, обычно, если не менять конфигурацию, все расположено в директории: /var/cache/nginx Чтобы удалить все закешированные страницы и файлы, необходимо проделать следующее:
sudo find /var/cache/nginx -type f -delete
После этого, все страницы и ресурсы на сайте, для которых включено кеширование, должны будут обновить свой кеш по мере поступления к ним запросов.
При использовании fastcgi_cache
Местоположение каталога, в котором будут хранится закешированные ресурсы, определяется параметром fastcgi_cache_path в конфигурационном файле. Для примера, если в конфиге есть такая строка:
fastcgi_cache_path /var/run/nginx-fastcgi-cache levels=1:2 keys_zone=FASTCGICACHE:150m inactive=60m;
То отсюда видно, что кеш хранится в директории /var/run/nginx-fastcgi-cache
Чтобы удалить все закешированные страницы и файлы, необходимо проделать следующее:
sudo find /var/run/nginx-fastcgi-cache -type f -delete
После этого, все страницы и ресурсы на сайте, для которых включено кеширование, должны будут обновить свой кеш по мере поступления к ним запросов.
Кэширование ответа от backend с помощью NGINX

Обновлено: 02.08.2023 Опубликовано: 27.01.2020
NGINX позволяет значительно ускорить процесс загрузки страницы, не обращаясь к бэкэнду, а выдавая готовый html из кэша. Для работы данной функции необходимо, чтобы веб-сервер был версии 0.7.44 и выше (проверить можно командой nginx -v). Для FastCGI кэш задается с помощью опций fastcgi_cache_*. Для запросов к бэкэнду с помощью proxy_pass — proxy_cache_*.
Рекомендации и противопоказания
Кэш — это данные не первой свежести. Это важно учитывать, если мы хотим настроить эффективное кэширование средствами nginx. Мы можем столкнуться с различными проблемами, например, неспособность сервера продлить сессию авторизованного пользователя или отображение старой информации на портале с динамично меняющимся контентом. Чтобы избежать данных проблем, настройка nginx должна быть тесно сопряжена с разработкой сайта. Идеальная работа кэша возможна только при полном понимании внутренних механизмах работы портала, такие как, отправка запросов на авторизацию, продление сессии, обновлении контента — программист может написать для этого запрос по определенным URL, для которого администратор NGINX может отключить кэширование. Кэширование динамики будет полезно для сайтов с высокой посещаемостью, из-за которой создается высокая нагрузка на сервер и он не может успеть выполнить обработку запросов. Также оно будет полезно для отдельных страниц, содержимое которых меняется очень редко, но отработка скриптов выполняется долго. Из всего этого можно сделать вывод, что кэширование на стороне сервера NGINX стоит применять только в случае высоких нагрузок и медленной работы сайта из-за долгой работы backend’а.
Настройка кэширования для proxy_pass
Как было сказано выше, для разных методов обращения к серверу, который обрабатывает запрос, нужно использовать разные методы кэширования.
Включение кэширования
Открываем конфигурационный файл nginx:
vi /etc/nginx/nginx.conf
В секцию http добавляем:
http <
.
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=all:64m inactive=2h max_size=2g;
.
>
- /var/cache/nginx — путь хранения кэша.
- levels — уровень вложенности каталогов. В данном примере мы задаем настройку, при которой в каталог с кэшем будет создан каталог, а в ней — еще один каталог.
- keys_zone — имя зоны в разделяемой памяти, где будет храниться кэш, а также ее размер.
- inactive — задает время, после которого кэш будет автоматически чиститься.
- max_size — максимальный размер данных под кэш. Когда место заканчивается, nginx сам удаляет устаревшие данные.
Создаем каталог для хранения кэша и задаем владельца:
chown nginx:nginx /var/cache/nginx
Настройка хостов
Чтобы определенный сайт или отдельная страница кешировала запрос, открываем конфигурационный файл с настройками виртуального домена или хоста, например:
. и добавим к proxy_pass кэширование — мы получим что-то на подобие:
location / if ($http_cookie ~* «.+» ) set $cookie_cache_bypass 1;
>
proxy_cache_bypass $cookie_cache_bypass;
proxy_pass http://localhost:3000;
.
proxy_cache all;
proxy_cache_methods GET POST HEAD;
proxy_cache_valid 404 502 503 5m;
proxy_cache_valid any 1h;
proxy_cache_use_stale error timeout invalid_header updating;
>
- set $cookie_cache_bypass 1 — задаем значения переменной $cookie_cache_bypass, если передаются куки. Необходимо для предотвращения отдачи устаревших данных.
- proxy_cache_bypass — не отдавать данные из кэша. В нашем случае, применяется при куках.
- proxy_pass — передает запросы на бэкэнд.
- proxy_cache_methods — по умолчанию, закэшированными будут только запросы GET и HEAD. Если нам нужны другие методы, то добавляем их. В нашем примере добавлен POST.
- proxy_cache — включаем кэширование.
- proxy_cache_valid — задает время кеширования. В нашем примере первый параметр задает кэширование страниц с кодами ответов 404, 502, 503 на 5 минут, второй — для всего остального на 1 час.
- proxy_cache_use_stale — указывает, в каких случаях можно отдать устаревший кэш.
Применение настроек
NGINX настроен. Проверим корректность настроек и применяем их, если нет ошибок:
nginx -t && nginx -s reload
Теперь заходим на сайт и смотрим в каталог с кэшем — в нем должны появиться каталоги и файлы:
Мы должны увидеть что-то на подобие:
drwx——. 3 nginx nginx 4096 Jan 25 16:09 0
drwx——. 5 nginx nginx 4096 Jan 25 16:09 2
drwx——. 5 nginx nginx 4096 Jan 25 16:15 3
drwx——. 3 nginx nginx 4096 Jan 25 16:09 4
drwx——. 4 nginx nginx 4096 Jan 26 05:08 5
drwx——. 3 nginx nginx 4096 Jan 25 16:09 6
drwx——. 3 nginx nginx 4096 Jan 26 04:18 7
drwx——. 3 nginx nginx 4096 Jan 25 16:10 8
drwx——. 5 nginx nginx 4096 Jan 25 16:15 a
drwx——. 3 nginx nginx 4096 Jan 25 16:09 b
drwx——. 5 nginx nginx 4096 Jan 26 04:19 e
drwx——. 3 nginx nginx 4096 Jan 25 19:55 f
Настройка кэширования для fastcgi_pass
Настройка fastcgi_cache аналогична proxy_cache и настройки можно сделать по подобию последнего, заменив proxy_ на fastcgi_. Мы разберем основные настройки без подробностей и комментариев.
Открываем конфиг nginx:
Добавляем в секцию http:
http .
fastcgi_cache_path /var/cache/fastcgi levels=1:2 keys_zone=fastcgi:64m inactive=2h max_size=2g;
.
>
* обратите внимание, что мы задали другой каталог и keys_zone.
Создаем каталог для кэша:
chown nginx:nginx /var/cache/fastcgi
location / if ($http_cookie ~* «.+» ) set $cookie_cache_bypass 1;
>
fastcgi_cache_bypass $cookie_cache_bypass;
fastcgi_pass http://localhost:9000;
.
fastcgi_cache all;
fastcgi_cache_methods GET POST HEAD;
fastcgi_cache_valid 404 502 503 5m;
fastcgi_cache_valid any 1h;
fastcgi_cache_use_stale error timeout invalid_header updating;
>
* опции fastcgi_ аналогичны опциям proxy_.
Проверяем настройки и применяем их:
nginx -t && nginx -s reload
Кэширование статики
Кэширование статики не имеет никакого отношения к кэшированию ответа от бэкэнда, однако, это тоже позволяет разгрузить сервер. Суть в том, что nginx сам умеет отдавать статические файлы + задавать инструкцию для браузера по ее кэшированию.
Настройка выполняется для каждого виртуального хоста (секция server):
server .
location ~* ^.+\.(css|js)$ root /var/www/site
expires modified +1w;
>
location ~* ^.+\.(jpg|jpeg|gif|png)$ root /var/www/site
expires max;
>
>
* в данном примере мы задаем для файлов изображений (jpg, jpeg, gif, png) кэш до 31 декабря 2037 23:55:55 (max), для файлов css и js — 1 неделя с момента их модификации. Данные настройки мы задаем при помощи параметра expires, который, в свою очередь, задает заголовок cache-control. NGINX будет искать статические файлы в корневом каталоге /var/www/site.
После применяем настройки:
systemctl restart nginx
Отключение кэширования
Как говорилось выше, в некоторых случаях, кэширование может навредить и на некоторых страницах его стоит отключить. В настройках виртуального хоста, мы можем создать отдельный location, для которого отключиться кэш, например:
location /proxy_nocache proxy_pass http://localhost:3000;
.
proxy_cache off;
>
location /fastcgi_nocache fastcgi_pass http://localhost:9000;
.
fastcgi_cache off;
>
* обратите внимание, что в данном примере мы отключаем кэширование как для запросов proxy_pass, так и fastcgi_pass.
При отключении кэширования для статики используем следующую конфигурацию:
server .
location ~* ^.+\.(jpg|jpeg|gif|png|css|js)$ root /var/www/site
expires epoch;
>
>
* expires epoch задаст заголовок сache-control с временем окончания кэша «1 января 1970 00:00:01».
Сброс кэша
Удалить кэш на стороне сервера nginx мы можем только для бэкэнда. Для статики нужно удалять кэш в самом браузере (например, в настройках или с помощью дополнений).
Для сброса кэша мы просто должны удалить содержимое каталога, который прописан в опции proxy_cache_path или fastcgi_cache_path — в нашем случае, это /var/cache/nginx и /var/cache/fastcgi соответственно.
а) для proxy_cache_path:
б) для fastcgi_cache_path:
Хранение кэша в оперативной памяти
Мы можем значительно ускорить процесс записи и чтения информации, если будем хранить кэш в оперативной памяти.
Создаем обычный каталог, в который будем монтировать часть оперативной памяти:
. и дадим на него полные права:
chmod 777 /var/ramdisk
Монтируем часть оперативной памяти как обычный каталог:
mount -t tmpfs -o size=2G ramdisk /var/ramdisk
* в данном примере мы монтируем 2 Гб оперативной памяти как папку /var/ramdisk. Возможно, правильнее будет заранее убедиться в наличие свободной памяти командой free.
Для автоматического монтирования открываем на редактирование fstab:
ramdisk /var/ramdisk tmpfs nodev,nosuid,noexec,nodiratime,size=2G 0 0
Теперь, когда у нас есть каталог, данные которого хранятся в оперативной памяти, редактируем параметр proxy_cache_path или fastcgi_cache_path в NGINX:
proxy_cache_path /var/ramdisk levels=1:2 keys_zone=all:64m inactive=2h max_size=2g;
fastcgi_cache_path /var/ramdisk levels=1:2 keys_zone=fastcgi:64m inactive=2h max_size=2g;
systemctl restart nginx
How to clear the cache of nginx?
I use nginx to as the front server, I have modified the CSS files, but nginx is still serving the old ones. I have tried to restart nginx, to no success and I have Googled, but not found a valid way to clear it. Some articles say we can just delete the cache directory: var/cache/nginx , but there is no such directory on my server. What should I do now?
1,343 1 1 gold badge 9 9 silver badges 29 29 bronze badges
asked Jun 4, 2011 at 10:04
194k 158 158 gold badges 433 433 silver badges 711 711 bronze badges
More details on your Nginx configuration would be of much help. Are you using proxy_cache ?
Jun 4, 2011 at 12:13
No, I just used the default configuration, and I searched about string cache , not found it in the config files
Jun 4, 2011 at 15:16
Nginx does not cache by default.
Jun 4, 2011 at 17:12
Are you running in a virtualbox/vargant vm? If so, try turning off sendfile, as they don’t play well together.
Jun 6, 2011 at 14:22
are you sure the caching is on the nginx side, then? Have you verified the behavior with a tool like curl? Often times, an issue like this is just client-side caching not requesting an updated resource because it’s been told that the old resource will be valid for a long time by expires max; or something similar.
Jul 5, 2011 at 14:31
25 Answers 25
I had the exact same problem — I was running my nginx in Virtualbox. I did not have caching turned on. But looks like sendfile was set to on in nginx.conf and that was causing the problem. @kolbyjack mentioned it above in the comments.
When I turned off sendfile — it worked fine.
Sendfile is used to ‘copy data between one file descriptor and another‘ and apparently has some real trouble when run in a virtual machine environment, or at least when run through Virtualbox. Turning this config off in nginx causes the static file to be served via a different method and your changes will be reflected immediately and without question
30.6k 51 51 gold badges 180 180 silver badges 292 292 bronze badges
answered Oct 29, 2012 at 6:21
Deepan Chakravarthy Deepan Chakravarthy
4,164 7 7 gold badges 25 25 silver badges 21 21 bronze badges
Refer to this link
Jan 20, 2014 at 6:49
In my case, the alternative workaround is to turn on gzip for these file types. Either way the problem is solved.
Mar 23, 2014 at 0:28
I used following ‘sudo vim /etc/nginx/nginx.conf’ and change ‘ sendfile on’ to ‘sendfile off’
Jul 8, 2015 at 21:08
This is the only solution I can find anywhere, but I actually need to use sendfile so can’t disable it 🙁
Mar 2, 2016 at 20:51
I turned off sendfile. No luck.
May 21, 2016 at 6:29
You can also bypass/re-cache on a file by file basis using
proxy_cache_bypass $http_secret_header;
and as a bonus you can return this header to see if you got it from the cache (will return ‘HIT’) or from the content server (will return ‘BYPASS’).
add_header X-Cache-Status $upstream_cache_status;
to expire/refresh the cached file, use curl or any rest client to make a request to the cached page.
curl http://abcdomain.com/mypage.html -s -I -H "secret-header:true"
this will return a fresh copy of the item and it will also replace what’s in cache.
answered May 21, 2014 at 4:58
Jason Wiener Jason Wiener
1,851 1 1 gold badge 13 13 silver badges 13 13 bronze badges
Why can I only upvote this one time? I want to do a gazillion 🙂
Oct 28, 2015 at 7:42
This can only update cached pages when the new page is cacheable as well. If you have removed a page (404 or other errors are now served by the backend), the page now sends a Set-Cookie or a «Content-Control: private» header, the cached content will not be «invalidated».
Feb 2, 2016 at 10:17
This «add_header X-Cache-Status $upstream_cache_status;» is such a cool feature!
Apr 24, 2017 at 5:19
thanks a lot. nice tip for cache invalidation, there is so little tutorials about nginx
Jun 5, 2017 at 5:48
Has this changed since you posted? I can successfully get a fresh copy with the «secret-header» but as soon as I remove the header, I get the cached version again.
Aug 10, 2017 at 19:30
Unless you configured a cache zone via proxy_cache_path and then used it (for example in a location block), via: proxy_cache nothing will get cached.
If you did, however, then according to the author of nginx, simply removing all files from the cache directory is enough.
Simplest way: find /path/to/your/cache -type f -delete
answered Aug 1, 2011 at 10:07
3,166 1 1 gold badge 17 17 silver badges 15 15 bronze badges
i’m getting this in my error log after deleting the files: [crit] 1640#0: unlink() «/path/to/cache/85/1cc5328db278b328f2c200c65179ad85» failed (2: No such file or directory)
Jun 30, 2013 at 20:23
Repeatedly, or just once? It shouldn’t be an actual problem. It probably just means that the cache manager tried to delete a file that you already deleted. Maybe reloading nginx (nginx -s reload) might help if you get the message repeatedly. (Not sure if that reinitializes the cache manager, too.)
Jul 2, 2013 at 17:50
yeah, I automatically clear the cache for my website by a script whenever I deploy a change, and reloading nginx doesn’t fix it either.
Jul 2, 2013 at 21:13
That sounds rather vague. Could you elaborate on that? Doesn’t seem like it’s related to the topic at hand here.
Sep 2, 2013 at 9:14
Search nginx conf files for proxy_cache_path to find the path to your cache like grep -r proxy_cache_path /etc/nginx/ Mine was set in /etc/nginx/conf.d/proxy_cache.conf as /var/lib/nginx/proxy
Nov 12, 2013 at 2:32
You can delete cache directory of nginx or You can search specific file:
grep -lr 'http://mydomain.pl/css/myedited.css' /var/nginx/cache/*
And delete only one file to nginx refresh them.
194k 158 158 gold badges 433 433 silver badges 711 711 bronze badges
answered Jul 14, 2011 at 10:23
Łukasz Sokolik Łukasz Sokolik
251 2 2 silver badges 3 3 bronze badges
To get the exact hit, you can append $ to the search term. Like grep -lr ‘http://mydomain.pl/css/myedited.css$’ /var/nginx/cache/*
Oct 17, 2014 at 11:39
Unfortunately I got the following output grep: /var/nginx/cache/*: No such file or directory I’m using Ubuntu 14.04.3 LTS and nginx/1.8.1. Any idea?
Feb 6, 2016 at 14:46
Try the following to grep files under /var/nginx/cache: sudo find /var/nginx/cache -type f -exec grep -l ‘/css/myedited.css’ <> \;
Oct 9, 2017 at 20:56
I believe it’s /var/cache/nginx/* ( dir cache before nginx in path)
Mar 30, 2020 at 12:10
I run a very simple bash script which takes all of 10 seconds to do the job and sends me a mail when done.
#!/bin/bash sudo service nginx stop sudo rm -rf /var/cache/nginx/* sudo service nginx start | mail -s "Nginx Purged" [email protected] exit 0
answered Mar 24, 2017 at 13:21
2,392 1 1 gold badge 16 16 silver badges 25 25 bronze badges
I had this problem also.
- Could not find any nginx/cache folder
- sendfile was off
My domain uses cloudflare.com for DNS (great service!). Aha! There it was:
cloudflare.com -> caching -> Purge Cache (I purged everything) That solved my problem!
answered Jan 19, 2017 at 9:39
767 2 2 gold badges 8 8 silver badges 23 23 bronze badges
This purges Cloudflare’s edge caches. It doesn’t clear the Nginx cache on your own server.
Jun 28, 2017 at 11:24
As an advice, I think is a valid answer .
Aug 20, 2017 at 19:44
This was excellent answer. I was digging hours why some files are still being cached and couldn’t guess it was CloudFlare ‘fault’. Thanks!
Jun 1, 2018 at 2:35
There’s two answers in this question.
- One for nginx as reverse cache
- Another for cleaning the browser cache by header input (this one)
expires modified +90d;
location ~* ^.+\.(css|js|jpg|gif|png|txt|ico|swf|xml)$ < access_log off; root /path/to/htdocs; expires modified +90d; >
6,233 1 1 gold badge 21 21 silver badges 22 22 bronze badges
answered Dec 6, 2012 at 18:11
647 6 6 silver badges 9 9 bronze badges
I tried this implementation because i’m having similar issue. However, after I made the change — it shows the default Nginx page. I’m using Niginx as LB with proxy, do I need to change root maybe?
Sep 20, 2015 at 8:41
I found this useful
grep -lr 'jquery.js' /path/to/nginx/cache/folder/* | xargs rm
Search, and if found then delete.
answered Oct 19, 2013 at 22:35
111 1 1 silver badge 2 2 bronze badges
We have a very large nginx cache (gigabytes) that we occasionally need to wipe. I’ve worked out a script that instantly clears the cache (as far as Nginx is concerned) and then removes the cache directory without starving the main application for disk I/O.
- Move the cache folder to a new location (on the same filesystem!) (this doesn’t disrupt any open file descriptors)
- Recreate the original cache folder, empty
- Reload Nginx (graceful reload, where nginx lets old workers finish in-progress requests)
- Remove old cached data
Here’s the script, tailored to Ubuntu 16.04 LTS, with the cache located at /mnt/nginx-cache :
#!/bin/bash set -e TMPCACHE=`mktemp --directory --tmpdir=/mnt nginx-cache-XXXXXXXXXX` TMPTEMP=`mktemp --directory --tmpdir=/mnt nginx-temp-XXXXXXXXXX` # Move the old cache folders out of the way mv /mnt/nginx-cache $TMPCACHE mkdir -p /mnt/nginx-cache chmod -R 775 /mnt/nginx-cache chown www-data:www-data /mnt/nginx-cache mv /mnt/nginx-temp $TMPTEMP mkdir -p /mnt/nginx-temp chmod -R 775 /mnt/nginx-temp chown www-data:www-data /mnt/nginx-temp # Tell Nginx about the new folders. service nginx reload # Create an empty folder. rm -rf /mnt/empty mkdir -p /mnt/empty # Remove the old cache and old temp folders w/o thrashing the disk. # See http://serverfault.com/questions/546177/how-to-keep-subtree-removal-rm-rf-from-starving-other-processes-for-disk-i # Note: the `ionice` and `nice` may not actually do much, but why not? ionice -c 3 nice -19 rsync -a --delete /mnt/empty/ $TMPCACHE ionice -c 3 nice -19 rsync -a --delete /mnt/empty/ $TMPTEMP rm -rf $TMPCACHE rm -rf $TMPTEMP rm -rf /mnt/empty
And in case it’s helpful, here’s the Nginx config we use:
upstream myapp < server localhost:1337 fail_timeout=0; >proxy_cache_path /mnt/nginx-cache/app levels=2:2:2 keys_zone=app_cache:100m inactive=1y max_size=10g; proxy_temp_path /mnt/nginx-temp/app; server < listen 4316 default; server_name myapp.com; location / < proxy_pass http://appserv; proxy_cache app_cache; proxy_cache_valid 200 1y; proxy_cache_valid 404 1m; >>
Nginx cache: всё новое — хорошо забытое старое
В жизни каждого проекта настает время, когда сервер перестает отвечать требованиям SLA и буквально начинает захлебываться количеством пришедшего трафика. После чего начинается долгий процесс поиска узких мест, тяжелых запросов, неправильно созданных индексов, не кэшированных данных, либо наоборот, слишком часто обновляемых данных в кэше и других темных сторон проекта.
Но что делать, когда ваш код “идеален”, все тяжелые запросы вынесены в фон, все, что можно, было закэшировано, а сервер все так же не дотягивает до нужных нам показателей SLA? Если есть возможность, то конечно можно докупить новых машин, распределить часть трафика и забыть о проблеме еще на некоторое время.
Но если вас не покидает чувство, что ваш сервер способен на большее, или есть магический параметр, ускоряющий работу сайта в 100 раз, то можно вспомнить о встроенной возможности nginx, позволяющей кэшировать ответы от бэкенда. Давайте разберем по порядку, что это, и как это может помочь увеличить количество обрабатываемых запросов сервером.
Что такое Nginx cache и как он работает?
Nginx кэш позволяет значительно сократить количество запросов на бэкенд. Это достигается путем сохранения HTTP ответа, на определенное время, а при повторном обращении к ресурсу, отдачи его из кэша без проксирования запроса на бекенд. Кэширование, даже на непродолжительный период, даст значительный прирост к количеству обрабатываемых запросов сервером.
Перед тем как приступить к конфигурации nginx, необходимо убедиться, что он собран с модулем “ngx_http_proxy_module”, так как с помощью этого модуля мы и будем производить настройку.
Для удобства можно вынести конфигурацию в отдельный файл, например “/etc/nginx/conf.d/cache.conf”. Давайте рассмотрим директиву “proxy_cache_path”, которая позволяет настроить параметры хранения кэша.
proxy_cache_path /var/lib/nginx/proxy_cache levels=1:2 keys_zone=proxy_cache:15m max_size=1G;
“/var/lib/nginx/proxy_cache” указывает путь хранения кэша на сервере. Именно в эту директорию nginx будет сохранять те самые файлы с ответом от бэкенда. При этом nginx не будет самостоятельно создавать директорию под кэш, об этом необходимо позаботиться самому.
“levels=1:2” — задает уровень вложенности директорий с кэшем. Уровни вложенности указываются через “:”, в данном случае будет созданы 2 директории, всего допустимо 3 уровня вложенности. Для каждого уровня вложенности доступны значения от 1 до 2, указывающие, как формировать имя директории.
Важным моментом является то, что имя директории выбирается не рандомно, а создается на основе имени файла. Имя файла в свою очередь является результатом функции md5 от ключа кэша, ключ кэша мы рассмотрим чуть позже.
Давайте посмотрим на практике, как строится путь до файла кэша:
/var/lib/nginx/proxy_cache/2/49/07edcfe6974569ab4da6634ad4e5d492
“keys_zone=proxy_cache:15m” параметр задает имя зоны в разделяемой памяти, где хранятся все активные ключи и информация по ним. Через “:” указывается размер выделяемой памяти в Мб. Как заявляет nginx, 1 Мб достаточно для хранения 8 тыс. ключей.
“max_size=1G” определяет максимальный размер кэша для всех страниц, при превышении которого nginx сам позаботится об удалении менее востребованных данных.
Также есть возможность управлять временем жизни данных в кэше, для этого достаточно определить параметр “inactive” директивы “proxy_cache_path”, который по умолчанию равен 10 минутам. Если в течение заданного в параметре “inactive” времени к данным кэша не было обращений, то эти данные удаляются, даже если кэш еще не “скис”.
Что же из себя представляет этот кэш? На самом деле это обычный файл на сервере, в содержимое которого записывается:
• ключ кэша;
• заголовки кэша;
• содержимое ответ от бэкенда.
Если с заголовками и ответом от бэкенда все понятно, то к “ключу кэша” есть ряд вопросов. Как он строится и как им можно управлять?
Для описания шаблона построения ключа кэша в nginx существует директива “proxy_cache_key”, в которой в качестве параметра указывается строка. Строка может состоять из любых переменных, доступных в nginx.
proxy_cache_key $request_method$host$orig_uri:$cookie_some_cookie:$arg_some_arg;
Символ “:” между параметром куки и get-параметром используется для предотвращения коллизий между ключами кэша, вы можете выбрать любой другой символ на ваше усмотрение. По умолчанию nginx использует следующую строку для формирования ключа:
proxy_cache_key $scheme$proxy_host$request_uri;
Следует отметить следующие директивы, которые помогут более гибко управлять кэшированием:
proxy_cache_valid — Задает время кэширования ответа. Возможно указать конкретный статус ответа, например 200, 302, 404 и т.д., либо указать сразу все, с помощью конструкции “any”. В случае указания только времени кэширования, nginx по дефолту будет кэшировать только 200, 301 и 302 статусы.
proxy_cache_valid 15m; proxy_cache_valid 404 15s;
В этом примере мы установили время жизни кэша в 15 минут, для статусов 200, 301, 302 (их nginx использует по умолчанию, так как мы не указали конкретный статус). Следующей строчкой установили время кэширования в 15 секунд, только для ответов со статусом 404.
proxy_cache_lock — Эта директива поможет избежать сразу нескольких проходов на бэкенд за набором кэша, достаточно установить значение в положении “on”. Все остальные запросы будут ожидать появления ответа в кэше, либо таймаут блокировки запроса к странице. Соответственно, все таймауты возможно настроить.
proxy_cache_lock_age — Позволяет установить лимит времени ожидания ответа от сервера, после чего на него будет отправлен следующий запрос за набором кэша. По умолчанию равен 5 секундам.
proxy_cache_lock_timeout — Задает время ожидания блокировки, после чего запрос будет передан на бэкенд, но ответ не будет закэширован. По умолчанию равен 5 секундам.
proxy_cache_use_stale — Еще одна полезная директива, позволяющая настроить, при каких случаях возможно использовать устаревший кэш.
proxy_cache_use_stale error timeout updating;
В данном случае будет использовать устаревший кэш в случае ошибки подключения, передачи запроса, чтения ответа с сервера, превышения лимита ожидания отправки запроса, чтения ответа от сервера, либо если в момент запроса происходит обновление данных в кэше.
proxy_cache_bypass — Задает условия, при которых nginx не станет брать ответ из кэша, а сразу перенаправит запрос на бэкенд. Если хотя бы один из параметров не пустой и не равен “0”. Пример:
proxy_cache_bypass $cookie_nocache $arg_nocache;
proxy_no_cache — Задает условие при котором nginx не станет сохранять ответ от бэкенда в кэш. Принцип работы такой же как у директивы “proxy_cache_bypass”.
Возможные проблемы при кэшировании страниц
Как уже упоминалось выше, вместе с кешированием HTTP ответа nginx сохраняет полученные от бэкенда заголовки. Если на вашем сайте используется сессия, то сессионная кука также будет закэширована. Все пользователи, зашедшие на страницу, которую вам посчастливилось закэшировать, получат ваши персональные данные, хранящиеся в сессии.
Следующая задача, с которой придется столкнуться — это управление кэшированием. Конечно можно установить незначительное время кэша в 2-5 минут и этого будет достаточно в большинстве случаев. Но не во всех ситуациях такое применимо, поэтому будем изобретать свой велосипед. Теперь обо всем по порядку.
Управление сохранением cookie
Кэширование на стороне nginx накладывает некоторые ограничения на разработку. Например, мы не можем использовать сессии на закэшированных страницах, так как пользователь не доходит до бэкенда, еще одним ограничением будет отдача cookies бэкендом. Так как nginx кэширует все заголовки, то чтобы избежать сохранения чужой сессии в кэше, нам нужно запретить отдачу cookies для кэшируемых страниц. В этом нам поможет директива “proxy_ignore_headers”. В качестве аргумента перечисляются заголовки, которые должны быть игнорированы от бэкенда.
proxy_ignore_headers "Set-Cookie";
Этой строкой мы игнорируем установку cookies с проксируемого сервера, то есть пользователь получит ответ без заголовка “Set-Cookies”. Соответственно все, что бэкенд попытался записать в cookie, будет проигнорировано на стороне клиента, так как он даже не узнает, что ему что-то предназначалось. Это ограничение в установке cookie следует учесть при разработке приложения. Например для запроса авторизации можно отключить игнорирование заголовка, чтобы пользователь получил сессионную куку.
Также следует учитывать время жизни сессии, его можно посмотреть в параметре “session.gc_maxlifetime” конфига php.ini. Представим, что пользователь авторизовался на сайте и приступил к просмотру новостной ленты, все данные при этом уже есть в nginx кэше. Через некоторое время пользователь замечает, что его авторизация пропала и ему снова нужно проходить процесс авторизации, хотя все это время он находился на сайте, просматривая новости. Это произошло потому, что на все его запросы nginx отдавал результат из кэша, не передавая запрос на бэкенд. Поэтому бэкенд решил, что пользователь неактивен и спустя время указанное в “session.gc_maxlifetime” удалил файл сессии.
Чтобы этого не происходило, мы можем эмулировать запросы на бэкенд. Например через ajax посылать запрос, который будет гарантированно проходить на бэкенд. Чтобы пройти на бэкенд мимо nginx кэша, достаточно отправить POST запрос, также можно использовать правило из директивы “proxy_cache_bypass”, либо просто отключить кэш для этой страницы. Запрос не обязательно должен что-то отдавать, это может быть файл с единственной строкой, стартующей сессию. Цель такого запроса — продлить время жизни сессии, пока пользователь находится на сайте, и на всего его запросы nginx добросовестно отдает закэшированные данные.
Управление сбросом кэша
Вначале необходимо определиться с требованиями, какую цель мы пытаемся достигнуть. Допустим, на нашем сайте есть раздел с текстовой трансляцией популярных спортивных событий. При загрузке страница отдается из кэша, дальше все новые сообщения приходят по сокетам. Для того, чтобы при первой загрузке пользователь видел актуальные сообщения на текущее время, а не 15 минутной давности, нам необходимо иметь возможность самостоятельно сбрасывать кэш nginx в любой момент времени. При этом nginx может быть расположен не на той же машине, что и приложение. Также одним из требований к сбросу будет возможность удаления кэша, сразу по нескольким страницам за раз.
Перед тем как начать писать свое решение, посмотрим, что предлагает nginx из “коробки”. Для сброса кэша в nginx предусмотрена специальная директива “proxy_cache_purge”, в которой записывается условие сброса кэша. Условие на самом деле является обычной строкой, которая при непустом и не “0” значении удалит кэш по переданному ключу. Рассмотрим небольшой пример.
proxy_cache_path /data/nginx/cache keys_zone=cache_zone:10m; map $request_method $purge_method < PURGE 1; default 0; >server < . location / < proxy_pass http://backend; proxy_cache cache_zone; proxy_cache_key $uri; proxy_cache_purge $purge_method; >>
Пример взят с официального сайта nginx.
За сброс кэша отвечает переменная $purge_method, которая является условием для директивы “proxy_cache_purge” и по дефолту установлена в “0”. Это означает, что nginx работает в “обычном” режиме (сохраняет ответы от бэкенда). Но если изменить метод запроса на “PURGE”, то вместо проксирования запроса на бэкенд с сохранением ответа будет произведено удаление записи в кэше по соответствующему ключу кэширования. Также возможно указать маску удаления, указывая знак “*” на конце ключа кэширования. Тем самым нам не нужно знать расположения кэша на диске и принцип формирования ключа, nginx берет на себя эти обязанности. Но есть и минусы этого подхода.
- Директива “proxy_cache_purge” доступна как часть коммерческой подписки
- Возможно только точечное удаление кэша, либо по маске вида “*”
Мы знаем, что nginx кэш — это обычный файл на сервере. Директорию для хранения файлов кэша мы самостоятельно указали в директиве “proxy_cache_path”, даже логику формирования пути до файла от этой директории мы указали с помощью “levels”. Единственное, чего нам не хватает, это правильного формирования ключа кэширования. Но и его мы можем подсмотреть в директиве “proxy_cache_key”. Теперь все что нам остается сделать это:
- сформировать полный путь до страницы, в точности как это указано в директиве “proxy_cache_key”;
- закодировать полученную строку в md5;
- сформировать вложенные директории пользуясь правилом из параметра “levels”.
- И вот у нас уже есть полный путь до файла кэша не сервере. Теперь все, что нам остается, это удалить этот самый файл. Из вводной части мы знаем, что nginx может быть расположен не на машине приложения, поэтому необходимо заложить возможность удалять сразу несколько адресов. Снова опишем алгоритм:
- Сформированные пути к файлам кэша мы будем записывать в файл;
- Напишем простой сценарий на bash, который поместим на машину с приложением. Его задачей будет подключиться по ssh к серверу, где у нас находится кэширующий nginx и удалить все файлы кэша, указанные в сформированном файле из шага 1;
Шаг 1. Формирование файла с путями до кэша.
$urls = [ 'httpGETdomain.ru/news/111/1:2', 'httpGETdomain.ru/news/112/3:4', ]; function to_nginx_cache_path(url) < $nginxHash = md5($url); $firstDir = substr($nginxHash, -1, 1); $secondDir = substr($nginxHash, -3, 2); return "/var/lib/nginx/proxy_cache/$firstDir/$secondDir/$nginxHash"; >// Создаем файл с уникальным именем в директории tmp $filePath = tempnam('tmp', 'nginx_cache_'); // Открываем созданный файл на запись $fileStream = fopen($filePath, 'a'); foreach ($urls as $url) < // Собираем путь до файла кэша $cachePath = to_nginx_cache_path($url); // Построчно записываем путь до файла кэша fwrite($fileStream, $cachePath . PHP_EOL); >// Закрываем открытый дескриптор файла fclose($fileStream); // Вызываем bash скрипт с файлом в качестве аргумента exec("/usr/local/bin/cache_remover $filePath");
Обратите внимание, что в переменной “$urls” содержатся url закэшированных страниц, уже в формате “proxy_cache_key”, указанном в конфиге nginx. Url выступает неким тегом для выводимых сущностей на странице. Например, можно создать обычную таблицу в бд, где каждый сущности будет сопоставлена конкретная страница, на которой она выводится. Тогда при изменении каких-либо данных мы можем сделать выборку по таблице и удалить кэш всех необходимых нам страниц.
Шаг 2. Подключение на кэширующий сервер и удаление файлов кэша.
# Объединяем содержимое файла в одну строку, с пробелом в качестве разделителя FILE_LIST=`cat $1 | tr "\n" " "` # путь до ssh команды SSH=`which ssh` USER="root" # Логин под кем будем заходить на машину с nginx HOST="10.10.1.0" # Хост подключения KEY="/var/keys/id_rsa" # SSH ключ, так как мы будем использовать авторизацию не по паролю $SSH -i $ $@$ "rm -f $" # Подключение на сервер и выполнение команды rm -rf rm -f $1 # Удаление файла
Приведенные примеры несут ознакомительный характер, не стоит использовать их в production. В примерах опущены проверки входных параметров и ограничения команд. Одна из проблем с которой можно столкнутся — это ограничение длины аргумента команды “rm”. При тестировании в dev окружении на небольших объемах это можно легко упустить, а в production получить ошибку “rm: Argument list too long”.
Кэширование персонализированных блоков
Давайте подведем итог, что нам удалось сделать:
- снизили нагрузку на бэкенд;
- научились управлять кэшированием;
- научились сбрасывать кэш в любой момент времени.
Нужно рассмотреть альтернативную подгрузку таких частей страницы. Как всегда это можно сделать множеством способов, например после загрузки страницы отправлять ajax запрос, а на месте персонального контента отображать лоадер. Другим способом, который мы как раз сегодня и рассмотрим, будет использование ssi тегов. Давайте вначале разберемся что из себя представляет SSI, а затем, как мы можем его использовать в связке с nginx кэшем.
Что такое SSI и как он работает
SSI (Server-Side Includes, включения на стороне сервера) — это некий набор команд, встраиваемых в html страницу, указывающие серверу, что нужно сделать.
Вот некоторый перечень таких команд (директив):
• if/elif/else/endif — Оператор ветвления;
• echo — Выводит значения переменных;
• include — Позволяет вставлять содержимое другого файла в документ.
Как раз о последней директиве и пойдет речь. Директива include имеет два параметра:
• file — Указывает путь к файлу на сервере. Относительно текущей директории;
• virtual — Указывает виртуальный путь к документу на сервере.
Нас интересует параметр “virtual”, так как указывать полный путь до файла на сервере не всегда удобно, либо в случае распределенной архитектуры файла на сервере попросту нет. Пример директивы:
Для того, чтобы nginx начал обрабатывать ssi вставки, необходимо модифицировать location следующим образом:
location /
Теперь все запросы, обрабатываемые location “/”, будут иметь возможность выполнять ssi вставки.
Как же во всей этой схеме будет проходить наш запрос?
- клиент запрашивает страницу;
- Nginx проксирует запрос на бэкенд;
- бэкенд отдает страницу с ssi вставками;
- результат сохраняется в кэш;
- Nginx “дозапрашивает” недостающие блоки;
- итоговая страница отправляется клиенту.
Избавляемся от постоянных запросов к бэкенду через ssi
Для решения этой задачи нам поможет модуль nginx “ngx_http_memcached_module”. Модуль позволяет получать значения от сервера memcached. Записать через модуль не получится, об этом должен позаботиться сервер приложения. Рассмотрим небольшой пример настройки nginx в связке с модулем:
server < location /page < set $memcached_key "$uri"; memcached_pass 127.0.0.1:11211; error_page 404 502 504 = @fallback; >location @fallback < proxy_pass http://backend; >>
В переменной $memcache_key мы указали ключ, по которому nginx попробует получить данные из memcache. Параметры подключения к серверу memcache задаются в директиве “memcached_pass”. Подключение можно указать несколькими способами:
memcached_pass cache.domain.ru;
• IP адрес и порт;
memcached_pass localhost:11211;
memcached_pass unix:/tmp/memcached.socket;
upstream cachestream < hash $request_uri consistent; server 10.10.1.1:11211; server 10.10.1.2:11211; >location /
Если nginx удалось получить ответ от сервера кэша, то он отдает его клиенту. В случае когда данных в кэше нет, запрос будет передан на бэкенд через “@fallback”. Эта небольшая настройка memcached модуля под nginx поможет нам сократить количество проходящих запросов на бэкенд от ssi вставок.
Надеемся, эта статья была полезна и нам удалось показать один из способов оптимизации нагрузки на сервер, рассмотреть базовые принципы настройки nginx кэширования и закрыть возникающие проблемы при его использовании.