服务端缓存
proxy cache属于服务端缓存,主要实现 nginx 服务器对客户端数据请求的快速响应。nginx 服务器在接收到被代理服务器的响应数据之后,一方面将数据传递给客户端,另一方面根据proxy cache的配置将这些数据缓存到本地硬盘上。当客户端再次访问相同的数据时,nginx服务器直接从硬盘检索到相应的数据返回给用户,从而减少与被代理服务器交互的时间。
开启nginx缓存
反向代理nginx配置
首先需要指定proxy_cache_path,可以指定多条:
proxy_cache_path /tmp/nginx/cache levels=1:2 inactive=60s keys_zone=mycache:10m max_size=10g;
- /tmp/nginx/cache:缓存文件存放的路径。
- levels : 默认所有缓存文件都放在同一个目录下时,会影响缓存的性能,大部分场景推荐使用2级目录来存储缓存文件,1和2表示用1位和2位16进制来命名目录名称。第一级目录用1位16进制命名,如b;第二级目录用2位16进制命名,如2b。所以一级目录有16个,二级目录有16*16=256个,总目录数为16*256=4096个。
- key_zone : 在共享内存中设置一块存储区域来存放缓存的key字符串,这样nginx可以快速判断一个request是否命中或者未命中缓存,1m可以存储8000个key,10m可以存储80000个key;
- max_size(可选) : 最大cache空间,如果不指定,会使用掉所有磁盘空间。当达到配额后,会删除最少使用的cache文件。
- inactive(可选) : 未被访问文件在缓存中保留时间,本配置中如果60秒未被访问则不论状态是否为expired,缓存控制程序会删掉文件,默认为10分钟。
然后在http,server或者location上下文中通过proxy_cache引用前面定义的proxy_cache_path:
user nginx; events { } http { proxy_cache_path /tmp/nginx/cache levels=1:2 inactive=60s keys_zone=mycache:10m max_size=10g; server { listen 80; location /cache { proxy_pass http://192.168.1.135:8080; #proxy_cache_valid 200 302 80s; #代理服务器本身设置对200 302响应缓存80s proxy_cache mycache; #引用前面定义的proxy_cache_path add_header cache $upstream_cache_status; #这个不是必须的,只是方便我们测试的时候查看是否命中缓存 } } }
被代理服务器配置
被代理服务器上需要通知代理服务器缓存内容的时间,否则代理服务器不会对内容进行缓存,通过X-Accel-Expires,expires,Cache-Control "max-age="其中一个参数指定时间。如果代理服务器上配置了proxy_cache_valid的时间,那么被代理服务器可以不指定缓存内容的时间。
events { } http { server { listen 8080; location /cache { add_header X-Accel-Expires 100; #通知代理服务器缓存100s #expires 50; #通知代理服务器缓存50s #add_header Cache-Control "max-age=50"; #通知代理服务器缓存50s alias /www/html/docs/ ; } } }
验证缓存
客户端连续两次去访问代理服务器,可以看到第一次请求未命中缓存,第二次请求命中缓存。
❯ curl http://192.168.1.134/cache/ -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Sat, 09 Jan 2021 16:09:38 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Sat, 09 Jan 2021 16:10:27 GMT Cache-Control: max-age=50 cache: MISS #第一次请求未命中缓存 Accept-Ranges: bytes ❯ curl http://192.168.1.134/cache/ -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Sat, 09 Jan 2021 16:09:39 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Sat, 09 Jan 2021 16:10:27 GMT Cache-Control: max-age=50 cache: HIT #第二次请求命中缓存 Accept-Ranges: bytes
并且在代理服务器上我们之前指定的缓存文件路径下可以看到该文件。
[root@nginx-plus1 e2]# pwd /tmp/nginx/cache/9/e2 [root@nginx-plus1 e2]# ls b5ba0009996f20ce25cbca96ac976e29
缓存配置综合例子
user nginx; events{ worker_connections 1024; } http { #设置缓存路径和相关参数(必选) proxy_cache_path /tmp/nginx/cache levels=1:2 keys_zone=mycache:10m max_size=10g; server { listen 80; location /cache { proxy_pass http://192.168.1.135:8080; #引用缓存配置(必选) proxy_cache mycache; #对响应状态码为200 302的响应缓存100s proxy_cache_valid 200 302 100s; #对响应状态码为404的响应缓存200 proxy_cache_valid 404 200s; #请求参数带有nocache或者comment时不使用缓存 proxy_cache_bypass $arg_nocache $arg_comment; #忽略被代理服务器设置的"Cache-Control"头信息 proxy_ignore_headers "Cache-Control"; #对GET HEAD POST方法进行缓存 proxy_cache_methods GET HEAD POST; #当缓存过期时,当构造上游请求时,添加If-Modified-Since和If-None-Match头部,值为过期缓存中的Last-Modified值和Etag值。 proxy_cache_revalidate on; #当被代理服务器返回403时,nginx可以使用历史缓存来响应客户端,该功能在一定程度上能能够为客户端提供不间断访问 proxy_cache_use_stale http_403; #默认开启,开启代理缓冲区(内存) proxy_buffering on; #设置响应头的缓冲区设为8k proxy_buffer_size 8k; #设置网页内容缓冲区个数为8,单个大小为8k proxy_buffers 8 8k; #设置当nginx还在读取被代理服务器的数据响应的同时间一次性向客户端响应的数据的最大为16k proxy_busy_buffers_size 16k; #临时文件最大为1024m proxy_max_temp_file_size 1024m; #设置一次往临时文件的大小最大为16k proxy_temp_file_write_size 16k; #设置临时文件存放目录 proxy_temp_path /tmp/proxy_temp; #设置和被代理服务器连接的超时时间为60s proxy_connect_timeout 60; #设置向被代理服务器发送请求的超时时间为60s proxy_send_timeout 60; #设置从被代理服务器读取响应的超时时间为60s proxy_read_timeout 60; #添加缓存状态参数,方便测试是否命中缓存 add_header cache $upstream_cache_status; } } }
缓存状态
$upstream_cache_status
中包含以下几个状态:
- MISS:未命中缓存,请求被传送到后端服务器。
- HIT: 命中缓存,使用缓存响应客户端。
- EXPIRED: 缓存已经过期,请求被传送到后端。
- UPDATING: 正在更新缓存,nginx使用过期缓存的响应客户端。
- STALE: 当后端服务器出错时,nginx用缓存响应客户端。
- BYPASS: 缓存被绕过了,请求被传送到后端服务器。
- REVALIDATED: nginx通过过期缓存中的Etag和Last-Modified字段的值向被代理服务器发起验证请求。
缓存多久
参数(优先级从高到低) | 位置 |
inactive | 代理服务器 |
X-Accel-Expires | 被代理服务器 |
Cache-Control | 被代理服务器 |
expires | 被代理服务器 |
proxy_cache_valid | 代理服务器 |
通过nginx变量限制是否使用缓存
proxy_cache_bypass
该参数设定,什么情况下的请求不读取cache而是直接从后端的服务器上获取资源。这里的string通常为nginx的的一些内置变量或者自己定义的变量。
Syntax: proxy_cache_bypass string ...; Default: — Context: http, server, location
例如:
proxy_cache_bypass $arg_nocache $arg_comment;
当客户端访问请求中带有nocache或者comment参数时,不使用缓存数据。
❯ curl http://192.168.1.134/cache/?nocache=1 -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Sun, 10 Jan 2021 05:38:25 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Cache-Control: max-age=10 cache: BYPASS Accept-Ranges: bytes ❯ curl http://192.168.1.134/cache/?comment=3 -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Sun, 10 Jan 2021 05:38:29 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Cache-Control: max-age=10 cache: BYPASS Accept-Ranges: bytes
proxy_no_cache
该参数和proxy_cache_bypass类似,用来设定什么情况下不缓存。
Syntax: proxy_no_cache string ...; Default: — Context: http, server, location
例如:
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
定义缓存与请求间匹配的关键字
proxy_cache_key
设置nginx服务器在共享内存中为缓存数据建立索引时使用的关键字。
Syntax: proxy_cache_key string; Default: proxy_cache_key $scheme$proxy_host$request_uri; Context: http, server, location
例如:
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
影响缓存的HTTP method
proxy_cache_methods
设置可以缓存的HTTP请求方法。
Syntax: proxy_cache_methods GET | HEAD | POST ...; Default: proxy_cache_methods GET HEAD; Context: http, server, location This directive appeared in version 0.7.59.
proxy_cache_convert_head
当客户端一次使用HEAD方法请求时,nginx会通过GET方法向上游请求完整的header和body,只返回header给客户端。当客户端下次使用GET方法请求时,nginx会把缓存好的body返回给客户端,就不用去请求上游了。
Syntax: proxy_cache_convert_head on | off; Default: proxy_cache_convert_head on; Context: http, server, location This directive appeared in version 1.9.7.
影响缓存的HTTP header
proxy_ignore_headers
当被代理服务器的响应存在以下头部时,nginx不会缓存:
- Set-Cookie
- Cache-Control中存在以下项之一:
- private
- no-cache
- no-store
可以设置忽略被代理服务器的响应头。
Syntax: proxy_ignore_headers field ...; Default: — Context: http, server, location
例如:
proxy_ignore_headers Set-Cookie Cache-Control;
影响缓存的HTTP 响应
proxy_cache_valid
通过该参数,可以配置相应的http code类型的请求,生成的缓存的过期时间,可以配置多条。
Syntax: proxy_cache_valid [code ...] time; Default: — Context: http, server, location
例如:
proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m;
缓存请求次数
proxy_cache_min_uses
当客户端请求发送的次数达到设置次数后才会缓存该请求的响应数据,如果不想缓存低频请求可以设置此项。
Syntax: proxy_cache_min_uses number; Default: proxy_cache_min_uses 1; Context: http, server, location
缓冲区大小
proxy_buffering
默认是开启状态,当关闭时,nginx将不会对任何响应做缓存。
Syntax: proxy_buffering on | off; Default: proxy_buffering on; Context: http, server, location
proxy_buffers
在内存中设置缓冲区存储被代理服务器响应的body所占用的buffer个数和每个buffer大小,默认情况下buffer size等于一个memory page,32为操作系统为4k,64位为8k。当buffer大小(内存)无法容纳被代理服务器响应数据时,会将响应数据存放在proxy_temp_path中定义的临时目录(硬盘)中。
Syntax: proxy_buffers number size; Default: proxy_buffers 8 4k|8k; Context: http, server, location
proxy_buffer_size
proxy_buffer_size 用来接受被代理服务器响应头,如果响应头超过了这个长度,nginx会报upstream sent too big header错误,然后client收到的是502。
Syntax: proxy_buffer_size size; Default: proxy_buffer_size 4k|8k; Context: http, server, location
proxy_busy_buffers_size
nginx将会尽可能的读取被代理服务器的数据到buffer,直到proxy_buffers设置的所有buffer被写满或者数据被读取完,此时nginx开始向客户端传输数据。如果数据很大的话,nginx会接收并把他们写入到temp_file里去,大小由proxy_max_temp_file_size 控制。当数据没有完全读完的时候,nginx同时向客户端传送的buffer大小不能超过 proxy_busy_buffers_size。
Syntax: proxy_busy_buffers_size size; Default: proxy_busy_buffers_size 8k|16k; Context: http, server, location
proxy_temp_path
定义proxy的临时文件存在目录以及目录的层级。
Syntax: proxy_temp_path path [level1 [level2 [level3]]]; Default: proxy_temp_path proxy_temp; Context: http, server, location
例如:
proxy_temp_path /spool/nginx/proxy_temp 1 2; 那么临时文件将会类似: /spool/nginx/proxy_temp/7/45/00000123457
proxy_temp_file_write_size
设置一次写入临时文件的数据的最大的大小。
Syntax: proxy_temp_file_write_size size; Default: proxy_temp_file_write_size 8k|16k; Context: http, server, location
proxy_max_temp_file_size
设置临时文件的最大的大小。
Syntax: proxy_max_temp_file_size size; Default: proxy_max_temp_file_size 1024m; Context: http, server, location
超时时间
proxy_connect_timeout
设置和被代理服务器建立连接超时时间。
Syntax: proxy_connect_timeout time; Default: proxy_connect_timeout 60s; Context: http, server, location
proxy_read_timeout
设置从被代理服务器读取响应的时间。
Syntax: proxy_read_timeout time; Default: proxy_read_timeout 60s; Context: http, server, location
proxy_send_timeout
设置发送请求给被代理服务器的超时时间。
Syntax: proxy_send_timeout time; Default: proxy_send_timeout 60s; Context: http, server, location
并发回源请求
proxy_cache_lock
针对同一个key,仅允许一个请求回源去更新缓存,用于锁住并发回源请求。
Syntax: proxy_cache_lock on | off; Default: proxy_cache_lock off; Context: http, server, location This directive appeared in version 1.1.12.
proxy_cache_lock_timeout
锁住请求的最长等待时间,超时后直接回源,但不会以此响应更新缓存。
Syntax: proxy_cache_lock_timeout time; Default: proxy_cache_lock_timeout 5s; Context: http, server, location This directive appeared in version 1.1.12.
proxy_cache_lock_age
更新缓存的回源请求最大超时时间,超时后放行其他请求更新缓存。
Syntax: proxy_cache_lock_age time; Default: proxy_cache_lock_age 5s; Context: http, server, location This directive appeared in version 1.7.8.
历史缓存
proxy_cache_use_stale
如果nginx在访问被代理服务器过程中出现被代理服务器无法访问或者访问出错等现象时,nginx服务器可以使用历史缓存响应客户端的请求,这些数据不一定和被代理服务器上最新的数据相一致,但对于更新频率不高的后端服务器来说,nginx服务器的该功能在一定程度上能够为客户端提供不间断访问。该指令用来设置一些状态,当被代理服务器处于这些状态时,nginx服务器启用该功能。
Syntax: proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...; Default: proxy_cache_use_stale off; Context: http, server, location
例如:配置当被代理服务器返回404 HTTP响应码时,nginx可以使用历史缓存来响应客户端。
proxy_cache_use_stale http_404;
客户端访问测试:
❯ curl http://192.168.1.134/cache/index.html -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Mon, 11 Jan 2021 06:00:58 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Mon, 11 Jan 2021 06:01:07 GMT Cache-Control: max-age=10 cache: MISS #第一次请求没有缓存 Accept-Ranges: bytes ❯ curl http://192.168.1.134/cache/index.html -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Mon, 11 Jan 2021 06:01:01 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Mon, 11 Jan 2021 06:01:07 GMT Cache-Control: max-age=10 cache: HIT #第二次请求nginx使用缓存响应 Accept-Ranges: bytes ❯ curl http://192.168.1.134/cache/index.html -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Mon, 11 Jan 2021 06:01:29 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Mon, 11 Jan 2021 06:01:07 GMT Cache-Control: max-age=10 cache: STALE #第三次请求之前先将被代理服务器上的index.html文件删除,nginx使用历史缓存响应 Accept-Ranges: bytes
过期缓存
proxy_cache_revalidate
当缓存过期时,当nginx构造上游请求时,添加If-Modified-Since和If-None-Match头部,值为过期缓存中的Last-Modified值和Etag值。
Syntax: proxy_cache_revalidate on | off; Default: proxy_cache_revalidate off; Context: http, server, location This directive appeared in version 1.5.7.
当接收到被代理服务器的304响应时,且打开了proxy_cache_revalidate功能,则用缓存来响应客户端,并且更新缓存状态。
❯ curl http://192.168.1.134/cache/ -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Sun, 10 Jan 2021 08:11:37 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Sun, 10 Jan 2021 08:11:36 GMT Cache-Control: max-age=10 cache: REVALIDATED #表示nginx通过过期缓存中的Etag和Last-Modified字段的值向被代理服务器发起验证请求,并且被代理服务器返回了304 Accept-Ranges: bytes ❯ curl http://192.168.1.134/cache/ -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Sun, 10 Jan 2021 08:11:38 GMT Content-Type: text/html Content-Length: 26065 Connection: keep-alive Last-Modified: Wed, 21 Oct 2020 14:17:08 GMT ETag: "5f9042e4-65d1" Expires: Sun, 10 Jan 2021 08:11:36 GMT Cache-Control: max-age=10 cache: HIT Accept-Ranges: bytes