什么是缓存?
Web缓存是可以自动保存常见文档副本的HTTP 设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地设备而不是服务器中提取这个文 档。
为什么使用缓存?
- 缓存减少了冗余的数据传输,节约了网络费用
- 缓存缓解了网络瓶颈的问题,对于带宽的要求
- 缓存降低了对原始服务器的要求,降低服务器压力
- 缓存加速了页面的展示
缓存的分类:
缓存分为服务端侧(比如 Nginx,redis,memcached)和客户端侧(比如 web browser)。
服务端缓存又分为 代理服务器缓存 和 反向代理服务器缓存(也叫网关缓存,比如 Nginx反向代理就可以设置缓存)
客户端侧缓存一般指的是浏览器缓存、app缓存等等,目的就是加速各种静态资源的访问,降低服务器压力。
简单看看浏览器的缓存规则,同时使用浏览器缓存跟nginx缓存:
第一次访问某个网站
第二次访问某个网站
HTTP 缓存控制头介绍
HTTP 中最基本的缓存机制,涉及到的 HTTP 头字段,包括 Cache-Control, Last-Modified, If-Modified-Since, Etag, If-None-Match 等
Last-Modified/If-Modified-Since
Last-Modified :标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since :当资源过期时(使用Cache-Control标识的max-age),发现资源具有 Last-Modified 声明,则再次向web服务器请求时带上头
If-Modified-Since ,表示请求时间。web服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源有被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应 HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的 cache 。
当我们按下f5刷新的时候,我们看看浏览器发送的请求头:
此处发送时有一个 If-Modified-Since 请求头,其值就是上次请求响应的 Last-Modified
响应状态码为304
Ctrl+f5强制刷新(如果你想强制从服务器获取最新的内容,不去对比,那么就可以强制刷新 )
Pragma行是为了兼容 HTTP1.0 ,作用与 Cache-Control: no-cache 是一样的
Etag/If-None-Match
Etag :web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定),如果给定URL中的资源修改,则一定要生成新的Etag值。
If-None-Match :当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头 If-None-Match (Etag的值)。web服务器收到请求后发现有头 If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
Etag 是啥:
Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间,如果某些文件会被定期生成,当有时内容并没有任何变化,但 Last-Modified 却改变了,导致文件没法使用缓存有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形 Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。 Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag ,一致的情况下,才会继续比对 Last-Modified ,最后才决定是否返回304。
如下所示:
浏览器第一次请求,无缓存状态
浏览器第二次请求
Nginx web缓存设置
nginx 提供了 expires、etag、if-modified-since 指令来进行浏览器缓存控制。
expires指令
语法: expires [modified] time;
默认值: expires off;
上下文: http, server, location, if in location
假设我们使用 nginx 作为静态资源服务器,此时可以使用 expires 进行缓存控制。
location /img {
alias /export/img/;
expires 10s;
}
expires 30s;#30秒
expires 30m;#30分钟
expires 2h;#2个小时
expires 30d;#30天
nginx代理缓存模块(ngx_http_proxy_module)
Proxy 模块,用于把请求后抛给服务器节点或 upstream 服务器池
常用配置,具体看手册
请求头传递
proxy_redirect off ;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 50m;
client_body_buffer_size 256k;
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 60;
proxy_buffer_size 256k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_max_temp_file_size 128m;
proxy_pass http://nginx.23673.com;
proxy_cache_path指令
语法:proxy_cache_path[levels=number] keys_zone=zone_name:zone_size[inactve=time] [max_size=size];
默认值:None
上下文:http
proxy_cache_path 设置缓存目录,目录里的文件名是cache_key的MD5值。
levels=1:2 默认所有缓存文件都放在同一个/path/to/cache下,但是会影响缓存的性能,因此通常会在/path/to/cache下面建立子目录用来分别存放不同的文件。假设levels=1:2。
key_zone 在共享内存中设置一块存储区域来存放缓存的key和metadata(类似使用次数),这样nginx可以快速判断一个request是否命中或者未命中缓存,1m可以存储8000个key,10m可以存储80000个key。
max_size 最大cache空间,如果不指定,会使用掉所有disk space,当达到配额后,会删除最少使用的cache文件。
inactive 未被访问文件在缓存中保留时间,本配置中如果60分钟未被访问则不论状态是否为expired,缓存控制程序会删掉文件。inactive默认是10分钟。需要注意的是,inactive和expired配置项的含义是不同的,expired只是缓存过期,但不会被删除,inactive是删除指定时间内未被访问的缓存文件。
use_temp_path 如果为off,则nginx会将缓存文件直接写入指定的cache文件中,而不是使用temp_path存储,official建议为off,避免文件在不同文件系统中不必要的拷贝。
proxy_cache 启用proxy cache,并指定key_zone。另外,如果proxy_cache off表示关闭掉缓存。
proxy_cache_key 定义cache_key,nginx对缓存的资源会设置一个key,NGINX生成的键的默认格式是类似于下面的NGINX变量的MD5哈希值:$scheme$proxy_host$request_uri,实际的算法有些复杂。 为了改变变量(或其他项)作为基础键,可以使用proxy_cache_key命令。
proxy_cache_valid 为不同的HTTP返回状态码的资源设置不同的缓存时长。
缓存细节
NGINX仅仅默认缓存GET和HEAD客户端请求,在响应头部中 Cache-Control 被配置为 Private,No-Cache,No-Store 或者 Set-Cookie , NGINX 不会进行缓存。
如果你不想源服务器控制是否缓存,也可以在 nginx 当中配置忽略利用 roxy_ignore_headers Cache-Control 指令实现下面的指令允许多种请求类型缓存
proxy_cache_methods GET HEAD POST ;
缓存设置优化
proxy_cache_min_uses 设置响应被缓存的最小请求次数。
当缓存不断被填满时,这项设置便十分有用,因为这确保了只有那些被经常访问的内容才会被添加到缓存中。该项默认值为1。
proxy_cache_lock 开启此功能时,对于相同的请求,同时只允许一个请求发往后端。
只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用 proxy_cache_lock ,则所有在缓存中找不到文件的请求都会直接与源服务器通信。
![](https://i-blog.csdnimg.cn/blog_migrate/3a8b0a403b0c176e7635be3fc595c4ee.png)
![](https://i-blog.csdnimg.cn/blog_migrate/de0f35891214e22dfd025e247323b491.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a3480be881b02b64bffb9d8b93ef28fe.png)
不缓存的条件
有时候,我们也不想所有的请求都被缓存,我们可以指定某些请求不被缓存,比如带有后台后缀的,可以通过一些条件判断决定是否缓存。
语法: proxy_cache_bypass string ...;
默认值: —
上下文: http, server, location
定义nginx不从缓存取响应的条件。如果至少一个字符串条件非空而且非“0”,nginx就不会从缓存中去取响应,而是请求源服务器
比如后台模块是不允许缓存的,就可以设置不缓存
清除缓存
某些时候我们如果不想等待缓存的过期,想要主动清除缓存,可以采用第三方的缓存清除模块清除缓存 nginx_ngx_cache_purge
第三方地址 https://www.nginx.com/resources/wiki/modules/
Purge 模块下载地址 http://labs.frickle.com/nginx_ngx_cache_purge/
可以利用平滑升级的方式安装
proxy_cache_purge
syntax: proxy_cache_purge zone_name key
default: none
context: location
注意:要在proxy_cache 指令 下方
proxy_cache_purge tmp-test $uri;
tmp-test:指定的key_zone
$uri:指定的生成key的参数
比如:匹配url当中包含了purge关键字的就清除
缓存 xxx.com/cache/shop/?a=1
清除 xxxx.com/purge/shop/?a=1
安装步骤:
1)下载 http://labs.frickle.com/nginx_ngx_cache_purge/,并上传到服务器上/root/ngx_cache_purge-2.3.tar.gz
2) 解压/root/ngx_cache_purge-2.3.tar.gz
tar -zxvf /root/ngx_cache_purge-2.3.tar.gz
3) 通过nginx -V查看原nginx信息,然后添加需要安装的第三方模块的路径
4)make && make install 安装
5)nginx -V再次查看是否安装成功
6)上传配置文件,测试缓存key值
7)测试清除缓存参数
8)最终测试