缓存的目的就是减轻服务端的压力。尽量让请求集中在前端就能取到数据。
缓存类型:
根据缓存存放位置不同可以分为不同的缓存
如果存放在服务端则是 服务端缓存,例如:redis
,MongoDB
等。
如果是放在代理层则是 代理缓存,存放的内容是从服务端获取到数据,可直接给客户端使用,例如:Nginx
如果存放在客户端就是客户端缓存(浏览器请求服务器获取到的数据)。
我们看下Nginx
作为缓存服务器的流程
当客户端请求数据的时候先看代理缓存中是否存在,如果存在则返回。如果不存在,代理服务器向服务器请求数据并保留一份到缓存,然后返回给客户端。
proxy_cache
配置语法
配置proxy_cache
之前需要先配置proxy_cache_path
指定缓存文件路径
1 | 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]; |
之后进行proxy_cache
的配置
1 | Syntax: proxy_cache zone | off; |
其中的Zone
就是上面定义的path
。
配置语法–缓存过期周期:
1 | Syntax: proxy_cache_valid [code ...] time; |
其中的code
是指返回的HTTP状态码
配置语法–缓存的维度:
1 | Syntax: proxy_cache_key string; |
这个是指将什么样子的请求进行缓存(如上面是协议 主机 请求路径作为key进行缓存)
指令 | 含义 |
---|---|
proxy_cache_path | /data/nginx/tmp-test levels=1:2 keys_zone=tmp-test:100m inactive=7d max_size=1000g; |
proxy_cache_path | 缓存文件路径 |
levels | 设置缓存文件目录层次;levels=1:2 表示两级目录 默认所有缓存文件都放在同一个/path/to/cache下,从而影响缓存的性能,大部分场景推荐使用2级目录来存储缓存文件; |
keys_zone | 设置缓存名字和共享内存大小 在共享内存中设置一块存储区域来存放缓存的key和metadata(类似使用次数),这样nginx可以快速判断一个request是否命中或者未命中缓存,1m可以存储8000个key,10m可以存储80000个key; |
inactive | 在指定时间内没人访问则被删除 |
max_size | 最大cache空间,如果不指定,会使用掉所有disk space,当达到配额后,会删除最少使用的cache文件。 每一个proxy_cache_path对应一个ngx_http_file_cache_t结构体。 |
proxy_cache tmp-test | 使用名为tmp-test的缓存配置 |
proxy_cache_key $uri | 定义缓存唯一key,通过唯一key来进行hash存取 |
proxy_cache_methods | 设置缓存哪些HTTP方法 |
proxy_cache_min_uses | 指定请求至少被发送了多少次以上时才缓存,可以防止低频请求被缓存 |
proxy_cache_bypass | 如果指定的任何一个变量值不为空,或者不等于0,nginx就不会查找缓存,直接进行代理转发 |
proxy_cache_lock/proxy_cache_lock_timeout | 当多个客户端同时请求同一份内容时,如果开启proxy_cache_lock(默认off)则只有一个请求被发送至后端;其他请求将等待该内容返回;当第一个请求返回时,其他请求将从缓存中获取内容返回;当第一个请求超过了proxy_cache_lock_timeout超时时间(默认5s),则其他请求将同时请求到后端来获取响应,且响应不会被缓存;启用proxy_cache_lock可以应对雪崩效应。 |
inactive | 未被访问文件在缓存中保留时间,本配置中如果60分钟未被访问则不论状态是否为expired,缓存控制程序会删掉文件,默认为10分钟;“需要注意的是,inactive和expired配置项的含义是不同的,expired只是缓存过期,但不会被删除,inactive是删除指定时间内未被访问的缓存文件” |
use_temp_path | 临时存储区域。开启状态,会把一个写入缓存的文件,先放入一个临时存储区域,建议关闭,可以避免文件系统中不必要的数据拷贝 |
proxy_cache | 启用proxy cache,指定key_zone |
add_header | 在给客户端的返回中,增加名为X-Cache-Status的header,其值是缓存命中情况,比如MISS,HIT等等。 |
proxy_cache_key | 设置缓存文件中的key,硬盘中缓存文件的名字key值的MD5。譬如key是test.xnow.me/,则在硬盘上的md5值是c9d71dc81143d6d9a60165bdcb1b9c9f,计算方法: echo -n “test.xnow.me/“ |
proxy_cache_valid | 200 304 301 302 10d: 设置缓存的状态码,把返回状态是200和304的请求缓存起来。缓存时间是60分钟,过了缓存时间之后,设置缓存状态为EXPIRED,这是绝对时间,和上次更新时间相比。 10d代表缓存的时间,为10天 |
proxy_cache_use_stale | 返回码出错的时候,使用缓存数据。譬如出现超时,502和503等等情况 |
这个小节直接看老师的例子
1 | # 对于服务器进行负载均衡 |
如何清理指定缓存?
方式一:rm -rf
清除缓存目录内容
方式二:第三方扩展模块ngx_cache_purge
如何让部分页面不缓存?
1 | # 通过 proxy_no_cache 设置不缓存 |
配置项–proxy_cache_bypass
1 | Syntax: proxy_no_cache string ...; |
该指令用于定义满足条件的响应不会被保存到缓存中。在条件字符串中至少有一个条件不为空或者0,符合这样条件的响应才不会被缓存。举例如下:
1 | proxy_no_cache $cookie_nocache $arg_nocache$arg_comment; |
其中,cookie_nocache
、arg_nocache...
皆为变量,可以根据你访问的匹配策略来设置,其值只有2类,0和非0;
访问匹配策略例如:
1 | if ($request_uri ~ ^/(login|register|password\/reset)/) { |
如果在此链式配置中,只要有一个值不为0,则不会cache;例如:
1 | proxy_no_cache $cookie_nocache(0) $arg_nocache(1) $arg_comment(0) |
则不会被cache。
注:一般会配合proxy_cache_bypass共同使用;
配置项–proxy_cache_bypass
1 | Syntax: proxy_cache_bypass string ...; |
我们可以指定变量,当变量的值不为空或者不为0就不会缓存。
该指令用于定义哪些情况不从cache读取,直接从backend获取资源;配置方式同proxy_no_cache
。
缓存命中分析
方式一: 通过设置response
的头信息Nginx-Cache
add_header Nginx-Cache "$upstream_cache_status";
方式二:通过设置log_format
打印日志分析
将变量upstream_cache_status
配置到nginx的访问日志来查看是否命中缓存。
看下upstream_cache_status
的展示信息
状态 | 意义 |
---|---|
MISS | 未命中,请求被传送到后台处理 |
HIT | 缓存命中 |
EXPIRED | 缓存已经过期,请求被传送到后台处理 |
UPDATING | 正在更新缓存,将使用旧的应答 |
STALE | 后端得到过期的应答 |
1 | location / { |
我们在返回中新增了response头信息 Nginx-Cache
,可以在请求返回的头中查看该头信息的值来判断是否命中缓存,命中的话该值为HIT
。
如果我们想根据日志进行分析命中了 需要先将变量添加到log_format
中。
1 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' |
大文件分片请求
1 | Syntax: slice size; |
可以将大文件进行分片请求,即将一个大的文件请求分成多个小的切片。
在前端传过来一个大文件请求的时候,第一次会去请求文件大小,然后结合我们设置的切片大小进行分割成多个小的请求。多个小的请求到前端都是独立的文件。
优势:
每个子请求收到的数据都会形成一个独立文件,一个请求断了,其他请求不受影响。
缺点:
当文件很大或者slice
很小的时候,可能会导致文件描述符耗尽等情况。
一次请求就占有操作系统的一个句柄和建立一次连接