Nginx 缓存与压缩配置
1. Nginx中的缓存介绍
由于 Nginx 是在网站的所有其他后台服务的最前线,它接收的请求和流量是后台服务的数倍甚至数十倍之多。因此,用好 Nginx 的缓存功能对于大型网站而言至关重要。Nginx 中的缓存功能优势如下:
提升所有客户端体验
有效降低上游服务器的负载
减少上游服务器之间的流量消耗
Nginx 的 Web 缓存服务主要由 proxy_cache 相关指令集和 fastcgi_cache 相关指令集构成,前者用于反向代理时,对后端内容源服务器进行缓存,后者主要用于对 FastCGI 的动态程序进行缓存。两者的功能基本上一样。强大的缓存功能也成为了 Nginx 吸引众多用户的重要因素之一。
2. Nginx中缓存指令
2.1 expires指令
Nginx 中的 expires 指令通过控制 HTTP 相应中的 Expires 和 Cache-Control的头部值,达到控制浏览器缓存时间的效果。指令格式如下:
Syntax: expires [modified] time; expires epoch | max | off; Default: expires off; Context: http, server, location, if in location
Nginx 中的时间单位有s(秒), m(分), h(小), d(天)。指令参数说明:
epoch: 指定Expires的值为1, 即 January,1970,00:00:01 GMT;
max: 指定Expires的值为31 December2037 23:59:59GMT, Cache-Control的值为10年;
-1:指定Expires的值为当前服务器时间-1s,即永远过期;
off:不修改Expires和Cache-Control的值time中出现@表示具体的时间,比如@18h30m表示的是下午6点半;
官方的示例如下:
expires 24h; # 24小时过期 expires modified +24h; expires @24h; expires 0; # 不缓存,立即过期 expires -1; # 用不过期 expires epoch; expires $expires;
2.2 proxy 模块中的 cache 相关指令
Nginx 的 proxy 模块中定义了许多和 cache 相关的模块,这是配置 http 请求代理的缓存功能。
通常情况下,我们使用 proxy_cache 指令开启 Nginx 缓存功能,用 proxy_cache_path 指令来设置缓存的路径和其他配置。两个指令的用法如下:
Syntax: proxy_cache zone | off; Default: proxy_cache off; Context: http, server, location Syntax: proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time]; Default: — Context: http
proxy_cache_path 指令中有较多的参数,部分重要参数说明如下:
path: 定义缓存存放的位置;
levels: 定义缓存路径的目录等级,最多3级
use_temp_path:
on: 使用proxy_temp_path定义的目录
off:
keys_zone:
name: 共享内存名
size: 共享内存大小
max_size: 设置最大的缓存文件大小
其余的重要的缓存指令有:
proxy_cache_key: 配置缓存的关键字,格式如下:
Syntax: proxy_cache_key string; Default: proxy_cache_key $scheme$proxy_host$request_uri; Context: http, server, location
示例:
proxy_cache_key $host$request_uri $cookie_user;
proxy_cache_valid: 配置缓存什么样的响应,缓存多长时间。注意,如果只设置了缓存时间,只缓存只针对相应码200, 301和302的请求 。格式如下:
Syntax: proxy_cache_valid [code ...] time; Default: — Context: http, server, location
示例:
proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; # 只设置了缓存时间,只对200,301和302有效 proxy_cache_valid 5m; proxy_cache_valid 200 302 10m; proxy_cache_valid 301 1h; # any表示所有相应码 proxy_cache_valid any 1m;
proxy_cache_methods: 对哪种 method 的请求使用缓存返回响应。
Syntax: proxy_cache_methods GET | HEAD | POST ...; Default: proxy_cache_methods GET HEAD; Context: http, server, location
3. Nginx中的压缩配置
Nginx 的压缩配置主要是用在与浏览交互中,对网页、css、js等静态资源进行压缩,通过消耗 cpu 的计算资源来节约大量的带宽,提高传输效率,给用户良好的体验。Nginx 中的 ngx_http_gzip_module 就是专门处理这里压缩功能的模块。其中部分重要指如下:
gzip: 是否打开 gzip 压缩功能;
Syntax: gzip on | off; Default: gzip off; Context: http, server, location, if in location
gzip_buffers: 设置压缩所需要的缓冲区大小;
Syntax: gzip_buffers number size; Default: gzip_buffers 32 4k|16 8k; Context: http, server, location
gzip_comp_level: 设置压缩级别,从1-9;越大压缩率越高,同时消耗cpu资源也越多;
Syntax: gzip_comp_level level; Default: gzip_comp_level 1; Context: http, server, location
gzip_types:需要压缩的文件格式 text/html默认会压缩,不用添加;
Syntax: gzip_types mime-type ...; Default: gzip_types text/html; Context: http, server, location
gzip_min_length: 压缩文件最小大小;
Syntax: gzip_min_length length; Default: gzip_min_length 20; Context: http, server, location
一个常见的压缩配置如下:
# 开启gzip压缩 gzip on; # http的协议版本 gzip_http_version 1.0; # IE版本1-6不支持gzip压缩,关闭 gzip_disable 'MSIE[1-6].'; #需要压缩的文件格式 gzip_types text/css text/javascript application/javascript image/jpeg image/png image/gif; #设置为4个8K内存作为压缩结果流缓存 gzip_buffers 4 8k; #压缩文件最小大小 gzip_min_length 1k; #压缩级别1-9 gzip_comp_level 9; #给响应头加个vary,告知客户端能否缓存 gzip_vary on; #反向代理时使用 gzip_proxied off;
注意: gzip 的开启需适应特定的场景,比如大文件和图片的传输就不是和开启 gzip 功能,压缩效果不明显的同时还白白耗费系统的资源,所以使用时需要慎重考虑。
4. 案例实战
4.1 expires 指令用法
首先准备 nginx.conf,中间简单配置几条 expires 指令用作测试:
... http{ server { listen 8000; location / { default_type text/plain; expires 10m; #expires -1h; return 200 '8000, server\n'; } } } ...
下面观察请求结果:
# 使用 expires 10m 配置,可以看到Expires值正好为10分钟后 [shen@shen ~]$ curl http://180.76.152.113:8000 -I HTTP/1.1 200 OK Server: nginx/1.17.6 Date: Thu, 06 Feb 2020 11:37:17 GMT Content-Type: text/plain Content-Length: 13 Connection: keep-alive Expires: Thu, 06 Feb 2020 11:47:17 GMT Cache-Control: max-age=600 # 使用 expires -1h 配置, -1h表示环境一个小时前过期了,所以返回Cache-Control的值为no-cache [shen@shen ~]$ curl http://180.76.152.113:8000 -I HTTP/1.1 200 OK Server: nginx/1.17.6 Date: Thu, 06 Feb 2020 11:37:32 GMT Content-Type: text/plain Content-Length: 13 Connection: keep-alive Expires: Thu, 06 Feb 2020 10:37:32 GMT Cache-Control: no-cache
4.2 proxy_cache 缓存实验
准备好 proxy_cache 缓存相关的配置,如下:
... http { server { listen 8000; location / { default_type text/plain; return 200 '8000, server\n'; } } server { listen 8001; location / { default_type text/plain; return 200 '8001, server\n'; } } server { listen 8002; location / { default_type text/plain; return 200 '8002, server\n'; } } # 定义上游服务器 upstream backends { server 127.0.0.1:8000; server 127.0.0.1:8001; server 127.0.0.1:8002; } # proxy_cache_path 指令 proxy_cache_path /root/test/cache levels=1:2 keys_zone=nginx_cache:10m max_size=10g inactive=60m use_temp_path=off; server { listen 80; location / { proxy_pass http://backends; proxy_cache nginx_cache; # 状态码为200和301的缓存1分钟 proxy_cache_valid 200 301 1m; # 其余的缓存10分钟 proxy_cache_valid any 10m; # response响应的头信息中定义缓存的状态(有没有命中) proxy_cache_key $host$uri$is_args$args; expires 1d; proxy_no_cache $cookie_nocache $arg_nocache $arg_comment; proxy_no_cache $http_pragma $http_authorization; # add_header 响应添加缓冲命中结果 add_header Nginx-Cache $upstream_cache_status; } } ...
我们通过 curl 命令向 Nginx 所在主机的 80端 请求,第一次请求转发到8000端口,结果被缓存; 第2-3次请求时由缓存返回结果,所以仍然是8000端口的返回;等待超过1分钟后,缓存失效,请求被转发到8001端口进行处理,返回相应结果;最后再次请求80端口,依旧由缓存命中,返回8001端口的响应结果。参看日志记录的 http 请求。
# 第一次请求,转到8000端口响应,然后缓存 [shen@shen ~]$ curl http://180.76.152.113 8000, server # 接下来请求全部由缓存命中 [shen@shen ~]$ curl http://180.76.152.113 8000, server [shen@shen ~]$ curl http://180.76.152.113 8000, server [shen@shen ~]$ curl http://180.76.152.113 8000, server # 缓存失效,转发到8001端口相应,并缓存结果 [shen@shen ~]$ curl http://180.76.152.113 8001, server # 继续命中缓存 [shen@shen ~]$ curl http://180.76.152.113 8001, server
查看请求的响应结果:
[root@server sbin]# tail -f ../logs/access.log 127.0.0.1 - - [06/Feb/2020:20:14:15 +0800] GET / HTTP/1.0 200 13 - curl/7.29.0 -- 103.46.244.69 - - [06/Feb/2020:20:14:15 +0800] GET / HTTP/1.1 200 13 - curl/7.29.0 -MISS 103.46.244.69 - - [06/Feb/2020:20:14:23 +0800] GET / HTTP/1.1 200 13 - curl/7.29.0 -HIT 103.46.244.69 - - [06/Feb/2020:20:14:26 +0800] GET / HTTP/1.1 200 13 - curl/7.29.0 -HIT 127.0.0.1 - - [06/Feb/2020:20:16:10 +0800] GET / HTTP/1.0 200 13 - curl/7.29.0 -- 103.46.244.69 - - [06/Feb/2020:20:16:10 +0800] GET / HTTP/1.1 200 13 - curl/7.29.0 -EXPIRED 103.46.244.69 - - [06/Feb/2020:20:16:22 +0800] GET / HTTP/1.1 200 13 - curl/7.29.0 -HIT
5. 小结
本节内容主要是介绍 Nginx 中的缓存功能。一个是针对浏览器的缓存控制,另一个是针对上游服务器对 http 请求进行缓存,以减轻上游服务器的负载,这在高流量场景下是非常必要的。接下来,我们完成两个实验,测试前面讲到的缓存指令,并实际观察缓存效果。