- Вопрос или проблема
- Ответ или решение
- Почему Nginx FastCGI не кеширует статические файлы?
- 1. Понимание FastCGI и статических файлов
- 2. Причины, по которым статические файлы не кешируются
- Параметры конфигурации
- Директивы expires и Cache-Control
- 3. Рекомендуемые нюансы для кеширования статических файлов
- 4. Дополнительные рекомендации
- Заключение
Вопрос или проблема
Я настраиваю fastCGI для кэширования с NginX. Он работает с .php файлами, но я не могу кэшировать статические файлы, такие как .jpg, .mp4…
Моя информация при проверке с cURL:
curl -I http://192.168.1.223/music.php
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 07 Dec 2015 20:21:48 GMT
Content-Type: text/html
Connection: keep-alive
X-Powered-By: PHP/5.3.3
X-Cache: HIT
curl -I http://192.168.1.223/b2.jpg
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 07 Dec 2015 20:24:51 GMT
Content-Type: image/jpeg
Content-Length: 18103
Last-Modified: Mon, 07 Dec 2015 20:06:27 GMT
Connection: keep-alive
ETag: "5665e6c3-46b7"
Expires: Fri, 05 Feb 2016 20:24:51 GMT
Cache-Control: max-age=5184000
Accept-Ranges: bytes
Моя конфигурация NginX:
user nginx nginx;
worker_processes 1;
lock_file /run/lock/nginx.lock;
events {
worker_connections 1024;
}
rtmp {
server {
listen 1935;
application pullfromwowza {
live on;
pull rtmp://192.168.1.222:1935/vod;
}
}
}
http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
keepalive_timeout 5;
#include /etc/nginx/mime.types;
default_type application/octet-stream;
#gzip on;
#gzip_static on;
#gzip_comp_level 2;
#gzip_disable "msie6";
#gzip_proxied any;
#gzip_types application/javascript application/json application/vnd.ms-fontobject application/x-font-ttf image/svg+xml #text/css text/plain text/xml;
#gzip_vary on;
fastcgi_cache_path /data/nginx/cache levels=1:2 keys_zone=fastcgicache:200m inactive=200m max_size=640m;
fastcgi_cache_key $scheme$request_method$host$request_uri;
# note: can also use HTTP headers to form the cache key, e.g.
#fastcgi_cache_key $scheme$request_method$host$request_uri$http_x_custom_header;
fastcgi_cache_lock on;
fastcgi_cache_use_stale error timeout invalid_header updating http_500;
fastcgi_cache_valid 5m;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
index index.php;
server {
listen 80;
server_name example.com;
root /usr/local/nginx/html;
#root /var/www/example.com;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# example FastCGI cache exception rules
set $fastcgi_skipcache 0;
if ($query_string) {
set $fastcgi_skipcache 1;
}
if ($http_x_custom_header) {
set $fastcgi_skipcache 0;
}
if ($uri ~ "/path/matches/") {
set $fastcgi_skipcache 1;
}
if ($http_cookie ~ "users_login_cookie") {
set $fastcgi_skipcache 1;
}
#include /etc/nginx/conf/phpfastcgicache;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ "\.php$" {
fastcgi_index index.php;
if (!-f $document_root$fastcgi_script_name)
{
return 404;
}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# note: adds a HTTP response header "X-Cache" returning HIT/MISS/BYPASS/EXPIRED for cache use status
add_header X-Cache $upstream_cache_status;
fastcgi_cache fastcgicache;
fastcgi_cache_bypass $fastcgi_skipcache;
fastcgi_no_cache $fastcgi_skipcache;
include /usr/local/nginx/conf/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
# fastcgi_pass unix:/var/run/php5-fpm.sock;
}
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
expires -1;
# access_log logs/static.log; # Я обычно не добавляю статический лог
}
# Feed
location ~* \.(?:rss|atom)$ {
expires 1h;
add_header Cache-Control "public";
}
# Media: images, icons, video, audio, HTC
location ~* \.(jpg|jpeg|gif|css|png|js|ico|gz) {
expires 60d;
# proxy_pass http://192.168.11.11:8888;
# proxy_redirect off;
#proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
fastcgi_cache fastcgicache;
# proxy_cache_key "$request_method|$host|$request_uri";
# proxy_cache_valid 1d;
}
# CSS и Javascript
location ~* \.(?:css|js)$ {
expires 1y;
access_log off;
add_header Cache-Control "public";
}
}
}
Спасибо !
Я хотел бы дополнить другие ответы.
Сказать, что файл уже закэширован, потому что он на диске, — это не удовлетворительный ответ. Например, Apache2 очень медленно обслуживает статические файлы, которые находятся на диске, поэтому прокси-кэш, такой как nginx или varnish, совершенно оправдан для сайта с высокой нагрузкой.
В случае с nginx он разработан так, чтобы эффективно обслуживать статическое содержимое.
Но вы должны убедиться, что у вас включено “sendfile on” (это так в вашей конфигурации).
Senfile() заменяет классическую пару read()/write() на уровне ядра и делает доступ к файлам очень быстрым.
Скорость достаточно высока, чтобы быть такой же производительной, как если бы содержимое было закэшировано.
Кстати, я рекомендую вам также включить tcp_nodelay. Он позволяет nginx отправлять короткий TCP-пакет немедленно, если не ожидаются другие данные.
Смотрите также:
- man sendfile(): http://man7.org/linux/man-pages/man2/sendfile.2.html
- директивы sendfile, tcp_nodelay и tcp_nopush: https://t37.net/nginx-optimization-understanding-sendfile-tcp_nodelay-and-tcp_nopush.html
Этот вопрос недооценен и недостаточно хорошо обсуждается в сообществе Nginx (или веб-серверов), потому что все копируют и вставляют уроки!
Комментарии к посту OP достаточно правдиво, но @Daneel дал отличный ответ, который затрагивает что-то более глубокое в стеке — за пределами Nginx, как операционная система и оборудование реагируют.
И действительно, это более актуально для обслуживания статических файлов. В конце концов, Nginx может «обслуживать» файлы на диске так быстро, как это позволяет ОС, ядро, виртуальная система и оборудование…
Что многие уроки забывают упомянуть, так это то, что оптимизация настроек Nginx недостаточна, для достижения максимальной производительности (особенно для VPS/VM/облачных серверов) вам также следует оптимизировать свое ядро. Если кому-то это интересно, вы можете проверить systctl.conf, который мы используем в SlickStack (скрипт LEMP для WordPress).
Также стоит отметить еще одну актуальную функцию: TMPFS
, которая является методом использования вашей оперативной памяти максимально эффективно, чтобы избежать диск I/O… если вы ищете экстремальную оптимизацию Nginx и статических файлов, тогда становится более важным найти качественный дата-центр с отличным оборудованием (виртуализация KVM, SSD-диски NVMe, хорошее управление ОС/пакетами), а затем получить машину с достаточным объемом оперативной памяти, чтобы ваша система могла помочь Nginx как можно лучше быстро доставлять файлы.
И если вы собираетесь использовать кеширование Nginx FastCGI вместе с TMPFS
(обслуживание файлов из RAM), тогда убедитесь, что у вас много доступной оперативной памяти и знайте о потенциальных рисках перед активацией, которые могут включать потерю данных в случае внезапных сбоев сервера или жестких перезапусков и т.д…
Вы не обслуживаете статические файлы из кеша, потому что вы не настроили никакого кеширования для статических файлов. Если только ваш PHP-скрипт не обслуживает b2.jpg
, в этом случае у вас есть более серьезные проблемы.
Вопрос OP на самом деле не был ответен никем.
Две вещи вызывают проблемы в конфигурации: (1) Сам по себе, директива expires
или заголовок кэширования не заставляет nginx кэшировать файл. Когда люди говорят вам сделать это для статического кэширования, они на самом деле имеют в виду кеш браузера. (2) В nginx директива fastcgi_cache
полезна только тогда, когда запрос действительно проходит через FastCGI. Чтобы закэшировать статический файл, вам нужна директива proxy_cache
. Используйте ее с proxy_pass
для передачи запроса на localhost, который вы можете настроить в отдельном server
.
На вопрос о том, где это может быть полезно, обычным сценарием использования является кэширование сжатых brotli css/js, запрашивание их один раз и последующее кеширование nginx.
Ответ или решение
Почему Nginx FastCGI не кеширует статические файлы?
На первый взгляд, выглядит, что ваше конфигурационное решение для Nginx хорошо настроено для кэширования динамического контента через FastCGI. Однако вы сталкиваетесь с проблемой: статические файлы, такие как изображения или видео, не кэшируются должным образом. Давайте рассмотрим, почему это происходит и как можно улучшить ваше решение.
1. Понимание FastCGI и статических файлов
FastCGI кеширует динамически сгенерированные страницы, которые обрабатываются через PHP, но для статических файлов, таких как .jpg
или .mp4
, ваш текущий подход с использованием fastcgi_cache
не будет работать. Это связано с тем, что статические файлы не проходят через быструю обработку FastCGI; они передаются Nginx напрямую. Поэтому вы не получите кеширование этих файлов без дополнительной настройки.
2. Причины, по которым статические файлы не кешируются
Параметры конфигурации
Вы вряд ли будете использовать fastcgi_cache
для статических файлов. Чтобы кешировать статический контент, вам нужно использовать директивы proxy_cache
, а не fastcgi_cache
. Если вы хотите, чтобы Nginx обслуживал статические файлы более эффективно, вам потребуется настроить совершенно другой подход.
Директивы expires
и Cache-Control
Ваши директивы expires
и Cache-Control
на самом деле работают на уровне кэширования браузеров, а не на уровне Nginx. Они помогают сократить сетевой трафик при повторных запросах со стороны клиента, но не кэшируют файлы на уровне сервера.
3. Рекомендуемые нюансы для кеширования статических файлов
-
Используйте директивы
proxy_cache
:
Для кэширования статических файлов вам нужно добавить блокlocation
, который будет использоватьproxy_cache
. Например:location ~* \.(jpg|jpeg|gif|css|png|js|ico)$ { proxy_cache my_static_cache; proxy_pass http://localhost; # или ваш сервер proxy_cache_valid 200 1h; expires 1M; add_header Cache-Control "public"; }
-
Добавьте блок
location
для кеша:
Если требуется кеширование, вам следует добавить новый серверный блок или доработать существующий серверный блок для статических файлов, чтобы гарантировать, что они кешируются должным образом. -
Настройка сервера для статических файлов:
Убедитесь, что у вас есть правильная настройка на уровне сервера, чтобы обеспечить быструю доставку статического контента. Воспользуйтесьsendfile
, чтобы улучшить производительность. Вы уже включилиsendfile
, что хорошо, и также рассмотрите использованиеtcp_nodelay
.
4. Дополнительные рекомендации
- Использование Redis или Memcached: Если ваш поток данных достаточно велик, рассмотрите возможность использования Redis или Memcached для более эффективного кэширования динамического контента.
- Настройка системы и Apache или Varnish: Для высокопроизводительных веб-сайтов, особенно если вы используете Apache, подумайте о применении прокси-сервера, такого как Varnish, который может эффективно кешировать как статический, так и динамический контент.
- Оптимизация вашего сервера: Настройки ядра и системы могут сыграть важную роль. Убедитесь, что у вас оптимизированы параметры TCP/IP и сетевого стека для ваших нужд.
Заключение
Чтобы обеспечить кеширование статических файлов на уровне Nginx, переключите на использование proxy_cache
и соответствующим образом настройте директивы конфигурации. Это поможет вам избежать задержек и значительно улучшить время загрузки вашего контента. Не забывайте, что кэширование — это не единственный аспект оптимизации: правильная настройка вашего сервера и сети также критически важна для высокой производительности и эффективного обслуживания клиентов.