Nginx 缓存
导航: 这里将Nginx的一些配置进行整合。根据导航比较容易找到对应的文档。资料来自于weixueyuan 5.Nginx 缓存 |
向用户提供内容服务是网站的核心目的,用户通过客户端从网站上获取内容的过程中,要经历很多复杂的过程,如路径的解析、数据的产生及返回等。通过使用缓存技术可加快用户对网站内容的获取,提升用户体验。
开发网站时可以在有可能影响数据传输速度的各个环节中使用缓存技术,如浏览器缓存、内容分发网络(Content Delivery Network,CDN)、反向代理缓存等。
Nginx 缓存的重要应用就是反向代理缓存服务,它不仅可以更高效地提升应用服务的性能,提高 Web 网站的可用性。当应用服务器繁忙或出现故障时,Nginx 缓存服务可以将错误返回的内容重新定向到早已准备好的静态缓存中,它不仅可以获得更好的用户体验,还能为其定位及排查故障提供充裕的时间。
1.Nginx Web缓存配置
Web 缓存可节约网络带宽,有效提高用户打开网站的速度。由于应用服务器被请求次数的降低,也相对使它的稳定性得到了提升。Web 缓存从数据内容传输的方向分为前向位置缓存和反向位置缓存两类。如下图所示。
图:Web 缓存位置图
前向位置缓存既可以是用户的客户端浏览器,也可以是位于用户 ISP 或内部局域网的服务器。反向位置缓存通常位于互联网端,如内容分发网络或网站的反向代理缓存等。
1.客户端缓存
当客户端访问某一网站时,通常会多次访问同一页面,如果每次都到网站服务器获取相同的内容,不仅会造成用户自身网络资源的浪费,也会加重网站服务器的负载。为了提高访问效率,客户端浏览器会将访问的内容在本地生成内容缓存。
由于网站的内容经常变化,为了保持缓存的内容与网站服务器的内容一致,客户端会通过内容缓存的有效期及 Web 服务器提供的访问请求校验机制,快速判断请求的内容是否已经更新。客户端缓存校验流程如下图所示。
图:客户端缓存校验
客户端通过内容缓存有效期的本地校验和由 Web 服务端提供的服务端校验两种方式共同校验内容缓存是否有效,这两种方式都是通过 HTTP 消息头中的相应字段进行判断或与服务端交互的。HTTP 消息头字段功能说明如下表所示。
消息头字段 | 示例 | 类型 | 功能 |
Cache-Control | Cache-Control: no-cache | 请求/响应 | HTTP/1.1 协议加入的缓存控制字段,用于服务端告知客户端是否缓存及缓存的有效期。也可用于客户端本地缓存检验流程的控制 |
Pragma | Pragma: no-cache | 请求/响应 | 一个在 HTTP/1.0 中规定的通用消息头字段,当字段值为 no-cache 时,功能与消息头 Cache-Control:no-cache 的设定一致 |
Date | Date: Tue, 15 Nov 2018 08:12:31 GMT | 响应 | 原始服务器消息发出的时间 |
Expires | Expires: Fri, 16 Aug 2019 19:43:31 GMT | 响应 | 告知客户端当前响应内容缓存的有效期,是个绝对时间,属于 HTTP/1.0 的协议约定,优先级低于 HTTP/1.1 协议的 max-age 设置 |
Last-Modified | Last-Modified: Fri, 16 Aug 2019 12:45:26 GMT | 响应 | 当前响应数据的最后修改时间 |
If-Modified-Since | If-Modified-Since: Fri, 16 Aug 2019 19:43:31 GMT | 请求 | 将当前请求本地内容缓存的最后修改时间发送给服务端进行校验,如果请求的内容在指定时间之后被修改了,将返回被修改的内容,否则返回响应状态码 304,客户端将使用本地缓存 |
If-Unmodified-Since | If-Unmodified-Since: Fri, 16 Aug 2019 19:43:31 GMT | 请求 | 将当前请求本地内容缓存的最后修改时间发送给服务端进行校验,如果请求的内容在指定时间之后未被修改,将继续传输内容,否则返回响应状态码 412,其常被用在 byte-range 请求的断点续传场景 |
ETag | ETag: "0a3ea38e4fd51:0" | 响应 | 当前响应数据的实体标签值 |
If-Match | If-Match: "0a3ea38e4fd51:0" | 请求 | 将当前内容缓存的 ETag 值发送给服务端进行校验,如果与服务端的 ETag 匹配一致就继续响应请求,否则返回响应状态码 412 |
If-None-Match | If-None-Match: "0a3ea38e4fd51:0" | 请求 | 将当前内容缓存的 ETag 值发送给服务端进行校验,如果与服务端的 ETag 值匹配不一致,则返回新的内容,否则返回响应状态码 304,客户端将使用本地缓存 |
1) 消息头字段 Cache-Control 由客户端发起缓存控制的相关字段值如下表所示。
消息头 | 功能分类 | 功能 |
Cache-Control: max-age= | 有效期 | 当 max-age=0 时,不进行内容缓存的有效期验证,直接向 Web 服务器发起请求,不影响缓存的服务端验证 |
Cache-Control: max-stale[=] | 有效期 | 如果内容缓存的过期时间不超过指定值,仍可被认为有效并被客户端使用。单位为秒 |
Cache-Control: min-fresh= | 有效期 | 内容缓存的更新时间不超过指定值,则认为有效。单位为秘 |
Cache-Control: no-cache | 可缓存性 | 不进行内容缓存的有效期验证,直接向 Web 服务器发起请求。常用在 Ctrl+F5 的场景,强制从服务端获取最新内容 |
Cache-Control: only-if-cached | 其他 | 只使用本地已经缓存的内容,不向 Web 服务器发送请求 |
当按下 F5 或者点击刷新时,客户端浏览器会添加请求消息头字段Cache-Control
:max-age=0
,该请求不进行内容缓存的本地验证,会直接向Web服务端发起请求,服务端将根据消息头字段进行服务端验证。
当按下 Ctrl+F5 时,客户端浏览器会添加请求消息头字段Cache-Control
:no-cache
和Pragma:no-cache
,并忽略所有服务端验证的消息头字段,该请求不进行内容缓存的本地验证,它会直接向 Web 服务端发起请求,因没有服务端验证的消息头字段,所以会直接返回请求内容。
2) 消息头字段 Cache-Control 由服务端发起缓存控制的相关字段值如下表所示。
消息头 | 类型 | 功能 |
Cache-Control: no-cache | 可缓存性 | 不对响应数据的内容缓存设置有效期,不需要进行本地有效期验证 |
Cache-Control: no-store | 可缓存性 | 响应数据不在本地保留内容缓存 |
Cache-Control: public | 可缓存性 | 表明当前数据可以被任何对象(客户端、缓存服务器等)缓存 |
Cache-Control: private | 可缓存性 | 当响应数据在经过缓存服务器(CDN 或反向代理缓存服务器)时,用于告知缓存服务器不能缓存该响应数据 |
Cache-Control: max-age= | 有效期 | 设置内容缓存的最大有效期,是个相对值,表示一个时间区间,单位为 s |
Cache-Control: s-maxage= | 有效期 | 当响应数据在经过缓存服务器(CDN 或反向代理缓存服务器)时,用于对缓存服务器中缓存的控制,该值优先级高于 max-age 的设定,与客户端浏览器无关 |
Cache-Control: must-revalidate | 服务端验证 | 当响应数据被设置有效期时,超过有效期的缓存请求必须进行服务端验证 |
Cache-Control: proxy-revalidate | 服务端验证 | 当响应数据在经过缓存服务器(CDN 或反向代理缓存服务器)时,用于缓存服务器缓存的控制,功能与 must-revalidate相同 |
Cache-Control: no-transform | 其他 | 当响应数据在经过缓存服务器(CDN 或反向代理缓存服务器)时,用于告知缓存服务器不得对消息头进行修改,与客户端浏览器无关 |
3) Last-Modified 与 if-modified-since 属于 HTTP/1.0,是用于服务端对响应数据修改时间进行校验的服务端校验方法。
Last-Modified 的值是由服务端生成后传递给客户端的,客户端发送请求时,它会将本地内容缓存中的 Last-Modified 的值由请求消息头的 if-modified-since 字段传递给服务端,如果服务端被请求的内容在 if-modified-since 字段值的时间之后被修改了,将返回被修改的内容,否则返回响应状态码 304,客户端将使用本地缓存。
4) ETag 与 If-None-Match 属于 HTTP/1.1,优先级高于 Last-Modified 的验证,是用于服务端对响应数据进行实体标签校验的服务端校验方法。
ETag 类似于身份指纹,是一个可以与 Web 资源关联的记号(token)。当客户端第一次发起请求时,ETag 的值在响应消息头中传递给客户端;当客户端再次发送请求时,如果验证本地内容缓存需要发起服务端验证,Etag 的值将由请求消息头的 If-None-Match 字段传递给服务端。
如果验证本地内容缓存与服务端的 ETag 的匹配不一致,则认为请求的内容已经更新,服务端将返回新的内容,否则返回响应状态码 304,客户端将使用本地缓存。
5) 客户端会通过 HTTP 消息头字段对本地内容缓存进行本地校验和服务端校验,内容缓存校验的流程如下图所示。
图:客户端内容缓存校验流程图
2.正向代理缓存
当客户端浏览器通过正向代理缓存服务器访问互联网 Web 服务器时,正向代理缓存服务器会先检查本地的缓存,如果本地已经有客户端访问网站的内容缓存,则会根据缓存策略将缓存内容返回客户端;如果本地没有相应的内容缓存,则会向网站 Web 服务器发起访问请求,在获得响应数据后,它会先将响应内容在本地缓存生成内容缓存,然后再转发给客户端。
正向代理缓存架构如下图所示。
图:正向代理缓存架构图
通常是多个客户端共享一台正向代理缓存服务器,当一台客户端访问某个网站后,其他客户端均会共享这个网站的缓存,无须再向网站服务器发起访问请求,提升内容响应速度。
通过共享正向代理缓存服务器,不仅减少了外网的访问次数,也降低了网络带宽的需求。通过正向代理缓存服务器的控制策略,可以有效地针对内网客户端及访问的目标进行过滤控制,提升内网安全。
正向代理缓存服务器并不严格限制其一定要在客户端的内网,因它是通过七层协议实现代理转发的,所以只要客户端通过 HTTP 或 HTTPS 协议可以连接到正向代理服务器即可。
3.内容分发网络
内容分发网络(CDN)是基于反向代理缓存技术实现的大规模网络应用,其将缓存服务器分布到用户访问相对集中的地区或网络中,当用户访问目标网站时,它会利用全局负载策略,将用户的访问分配到离用户最近的缓存服务器,并由被分配的缓存服务器处理用户的访问请求。
国内跨运营商的网络访问会很慢,通过 CDN 的分配策略,可有效地优化网络路径,并结合 CDN 缓存服务器节点的缓存,有效提高用户的访问速度,从而提升用户体验。内容分发网络架构如下图所示。
图:内容分发网络架构图
CDN 将被加速的网站内容缓存在离用户最近的缓存服务器中,通常被缓存的是更新较少的静态资源(如静态页面、CSS、JavaScript、图片、视频等),CDN 的各缓存服务器节点是通过 HTTP 响应头的 Cache-Control 来控制本地内容缓存有效期的。当客户端的请求被分配到 CDN 缓存服务器节点时,CDN 缓存服务器会先判断内容缓存是否过期,若内容缓存在有效期内,则直接返回客户端,否则将向源站点发出回源请求,并从源站点获取最新的数据,在更新本地缓存后将响应数据返回客户端。
CDN 的缓存有效期设置会影响内容缓存的回源率。如果缓存有效期设置的较长,回源率较低,则会使缓存服务器的缓存数据与源网站不同步,影响访问;如果缓存有效期设置的较短,回源率较高,则会增加源网站的负载,影响 CDN 缓存服务器的使用效率。
因此,CDN 服务商会根据被缓存资源的类型(如文件后缀)、路径等多个维度为使用者提供缓存有效期设置接口,并为用户提供更加细化的缓存时间管理。除了可以设置缓存时间外,也可以通过“缓存刷新”接口对 CDN 缓存服务器的缓存数据进行强制更新。
4.反向代理缓存
反向代理缓存是基于反向代理技术在用户请求转发到 Web 服务器前进行缓存加载的缓存方式。反向代理缓存服务器通常位于 Web 服务器之前,通过反向代理缓存服务器可以对被代理服务器的响应内容进行缓存,以加速用户请求响应的处理速度,降低被代理服务器的负载。反向代理缓存服务器架构如下图所示。
图:反向代理缓存服务器架构图
反向代理缓存提高了网站内容的加载速度,降低了被代理服务器的负载,并可以在被代理服务器发生故障时通过缓存的内容作为备份来提高网站的可用性。
提升网站性能。反向代理缓存以与静态内容相同的处理速度为所有类型的缓存内容提供用户响应处理,从而减少因被代理服务器动态计算产生的延迟,进一步提升网站的性能。
增加资源容量。因为减少了被代理服务器的请求,被代理服务器将有更多的计算资源处理动态响应,相对增加了应用服务器的资源容量。
提高可用性。通过反向代理缓存服务器的本地缓存,可以在被代理服务器出现故障或停机产生的故障等待时,让用户仍可访问网站(单向的浏览缓存中的内容),避免了用户因收到故障信息而产生的负面影响。
2.Nginx代理缓存配置
Nginx 的缓存功能是集成在代理模块中的,当启用缓存功能时,Nginx 将请求返回的响应数据持久化在服务器磁盘中,响应数据缓存的相关元数据、有效期及缓存内容等信息将被存储在定义的共享内存中。当收到客户端请求时,Nginx 会在共享内存中搜索缓存信息,并把查询到的缓存数据从磁盘中快速交换到操作系统的页面缓存(Page Cache)中,整个过程的速度非常快。
Nginx 缓存会缓存加载进程(Cache Loader Process)和库存管理(Cade Manger Process)进行管理。缓存加载进程只在 Nginx 启动时执行一次,将上一次 Nginx 运行时缓存有关数据的元数据加载到共享内存区域,加载结束后它将自动退出。
为了避免缓存因加载缓存降低 Nginx 的性能,缓存加载进程会采用周期性迭代式加载缓存数据,且迭代加载的时间间隔、每次最大消耗时间和每次迭代加载的数量可以由配置指令 proxy_cache_path 的指令值参数设置。缓存管理进程则周期性的检查缓存的状态,负责清除在一段时间内未被访问的缓存文件,并对超出缓存存储最大值的缓存对象进行删除,缓存管理进程的删除操作也是周期性迭代执行的,并由配置指令 proxy_cache_path 的指令值参数设置。
1.缓存处理流程及状态
当客户端发起请求到 Nginx 缓存服务器时,Nginx 会先检查本地是否已经有该请求的内容缓存,有的话会直接返回数据,缓存请求状态会被标记为 HIT,否则该缓存请求状态就会被标记为 MISS。
如果指令 proxy_cache_lock 未被启用,则会直接向源服务器发起访问请求,如果被启用,则会先确认当前请求是不是第一个发起的请求,若不是,则等待;若是,则向源服务器发起访问请求。服务器响应数据返回后会先被存储在本地缓存,然后再返回给客户端。缓存处理流程如下图所示。
图:Nginx 缓存处理流程图
Nginx 在处理缓存过程中,客户端请求的缓存请求状态会被记录在变量 $upstream_cache_status 中,缓存请求状态如下表所示。
缓存请求状态 | 状态说明 |
MISS | 缓存未命中,从源服务器获取响应数据 |
HIT | 缓存命中,从本地缓存获取数据 |
BYPASS | proxy_cache_bypass 生效,直接从源服务器获取响应数据 |
REVALIDATED | 启用 proxy_cache_revalidate 指令后,缓存将被源服务器服务端验证为有效状态,从本地缓存获取数据 |
EXPIRED | 缓存过期,从源服务器获取响应数据 |
UPDATING | 正在更新缓存,当前返回为旧缓存内容,在配置指令 proxy_cache_use_stale updating 时会存在该状态 |
STALE | 源服务器无法正常返回更新的内容,当前返回为旧缓存内容,在配置指令 proxy_cache_use_stale error timeout 时会存在该状态 |
SCARCE |
缓存节点被查询次数未达到配置指令 proxy_cache_min_uses 设定的值时,对此请求无法启用缓存机制,将从源服务器获取响应数据 |
2.缓存配置指令
Nginx 缓存配置指令如下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
proxy_store | on、off 或 string | off |
设置是否将被代理服务器的响应数据在本地按照请求的 URL 建立目录结构镜像。当指令值为 on 时,存储路径的设置为 root 或 alias, 响应数据先存储到临时文件后再复制或重命名保存 |
proxy_store_access | users:permissions... | user:rw | 设置创建本地镜像存储路径的文件夹权限 |
proxy_cache | zone 或 off | off | 设置一个用以做缓存管理的共享内存区域 |
proxy_cache_path | path 参数 | -- | 设置缓存文件存储路径及参数。缓存数据以 URL 的 MD5 值命名存储在缓存目录中 |
proxy_cache_key | string | $scheme $proxy_host $request_uri |
设置缓存的关键字 |
proxy_cache_lock | on 或 off | off |
是否启用缓存锁指令。当启用缓存锁机制时,每次只允许个向被代理服务器转发的请求,按照 proxy_cache_key 指令设置的标识增添新的缓存数据, 其他相同的请求则将等待缓存中出现响应数据或该缓存锁被释放,其等待时间由 proxy_cache_lock_timeout 指令设置 |
proxy_cache_lock_age | time | 5s |
缓存锁有效时间。当启用缓存锁机制时,如果一个请求在该指令的时间内没有完成响应数据缓存的添加,缓存锁将会被释放, 获取缓存锁的请求将被转发给被代理服务器由代理服务器负责生成缓存 |
proxy_cache_lock_timeout | time | 5s | 缓存锁等待超时时间。当启用缓存锁机制时,等待超过该时间的请求将直接从被代理服务器中读取响应,该请求响应不会被添加到缓存中 |
proxy_cache_max_range_offset | number | -- | 用以设置范围请求(byte-range)请求时的最大偏移量。超出该偏移量的请求将直接从被代理服务器中读取响应数据 |
proxy_cache_methods | GET 或 HEAD 或 POST... | GET HEAD | 指定可被缓存的请求方法 |
proxy_cache_convert_head | on 或 off | on | 开启或禁用将请求方法 HEAD 转换为 GET,如果该功能被禁用,配置指令 proxy_cache_key 的指令值应该添加变量 $request_method |
proxy_cache_min_uses | numberstring | 1 | 响应数据超过设置请求次数后将被缓存 |
proxy_no_cache | string... | -- | 设置不生成缓存数据的条件,指定字符串的值不为空或不等于 0,则不将当前请求返回的响应数据进行缓存 |
proxy_cache_bypass | string... | -- |
设置不使用缓存数据的条件,指令值中至少有一个值不为空或不等于 0 时,当前请求不使用缓存中的响应数据, 直接访问源应用服务器。它可以与 proxy_no_cache 指令一起使用 |
proxy_cache_revalidate | on 或 off | off |
启用该指令后,如果缓存过期,则通过在 HTTP 头中添加字段属性 If-Modified-Since 和 If-None-Match 的方式发送给源服务器, 从而进行缓存的服务端校验 |
proxy_cache_use_stale | error、timeout、 invalid_header、 updating、http_500、 http_503、http_403、 http_404、http_429、 off... |
off | 当出现指定的条件时,使用已经过期的缓存响应数据 |
proxy_cache_background_update | on 或 off | off | 允许使用过期的响应数据时,设置是否启用后台子请求更新过期缓存,同时向客户端返回过期的缓存响应数据 |
proxy_cache_valid | [code...] time | -- | 根据响应码设置缓存时间 |
proxy_cache_purge | string... | -- |
定义清除缓存请求条件,若指定的字符串不为空或 0,则将 proxy_cache_key 设置的标识的缓存进行清除。 清除成功则返回状态码 204,仅商业版有效 |
关于上表有以下几点需要说明。
- 该模块指令列表中指令的指令域范围都是 http、server、location;
- proxy_cache_path 指令只能编写在 http 指令域中;
- proxy_cache 与 proxy_store 指令不能在同一指令域中同时使用;
- proxy_cache_path 指令值参数如下表所示。
参数名 | 参数格式 | 默认值 | 参数说明 |
levels | levels | -- | 设置缓存目录的层级及命名方式 |
use_temp_path | on 或 off | on | 参数值为 on,则使用 proxy_temp_path 设置作为临时文件目录。参数值为 off 时,则使用缓存目录做临时文件目录 |
keys_zone | name:size | -- | 设置存储 cache_key 的共享内存 zone 及大小,1MB 可以存储 8000 个 key |
inactive | time | 10 分钟 | 设置时间内未被访问的缓存将被删除 |
max_size | size | -- | 缓存数据的最大值,超出这个最大值时,缓存管理进程将执行迭代更新,即删除最近最少使用的缓存 |
manager_files | number | 100 | 缓存管理进程执行一次迭代更新时,删除文件的最大数 |
manager_sleep | time | 50ms | 缓存管理进程每次更新缓存的迭代间隔时间 |
manager_threshold | time | 200ms | 缓存管理进程执行一次迭代更新时,最大执行的时间,单位为 ms |
loader_threshold | time | 200ms | 缓存加载进程每次迭代加载时,加载数据的最大执行时间 |
loader_files | number | 100 | 缓存加载进程每次迭代加载时,加载缓存目录中缓存数据的最大文件数 |
loader_sleep | time | 50ms | 缓存加载进程每次迭代的间隔时间 |
purger | on 或 off | off | 是否启用缓存清除功能。仅商业版有效 |
purger_files | number | 10 | 每次迭代清除时,清除缓存目录中缓存数据的最大文件数。仅商业版有效 |
purger_sleep | time | 50ms | 连续两次迭代清除间的最少间隔时间。仅商业版有效 |
purger_threshold | time | 50ms | 每次迭代清除时,最大执行的时间。仅商业版有效 |
3.HTTP 范围请求
范围请求允许服务器只发送请求的一部分响应数据给客户端,通常对大文件传输时,用以实现断点续传、多线程下载等功能。若服务端响应信息头中包含字段 Accept-Ranges:bytes,则表示服务端支持范围请求,且节点范围的单位为字节(bytes)。
在 Nginx 缓存默认配置下,Nginx 处理完一个大文件的初始请求后,后续的用户请求必须等待整个文件下载结束并存入缓存后才可以继续被处理,整个过程非常耗时。为解决这个问题,Nginx 提供了 ngx_http_slice_module 模块,用以缓存范围请求的支持。该模块将文件分成更小的切片(slices),客户端每个范围请求覆盖特定的切片,如果该范围没有缓存,则从源服务器请求后存入缓存,否则就从缓存中返回数据。
http_slice 模块配置指令如下表所示。
名称 | 切片指令 |
指令 | slice |
作用域 | http、server、location |
默认值 | 0 |
指令说明 | 设定范围请求切片的大小。默认为不启用该功能 |
配置样例如下:
location / { slice 1m; # 切片大小为1MB proxy_cache cache; # 缓存共享内存名称为cache proxy_cache_key $uri$is_args$args$slice_range; # 设置缓存key proxy_set_header Range $slice_range; # 添加头字段Range的字段值为 # $slice_range proxy_cache_valid 200 206 1h; # 响应状态码为200及206的内容缓存有效期为1h proxy_pass http://localhost:8000; }
3.Nginx Memcached缓存模块简述
Nginx 的 ngx_http_memcached_module 模块本身并没有提供缓存功能,它只是一个将用户请求转发到 Memcached 服务器的代理模块。
在以 Memcached 服务器为缓存应用的方案中,Memcached 作为内容缓存的存储服务器,用户通过 URL 为 Memcached 的 key 将 Web 请求数据缓存到 Memcached 服务器中,在客户端发起请求时,Nginx 通过一致的 URL 为 key,快速地从 Memcached 服务器中将缓存的内容作为用户的请求响应数据返回给客户端。
Memcached 是一个开源、高性能的内存对象缓存系统,使用 Memcached 服务器作为缓存存储服务器,充分利用了 Memcached 的高效缓存功能,减少了 Nginx 服务器磁盘 I/O 的操作,也可以通过 upstream 指令对多台 Memcached 做分布式集群负载,以便整体提升 Nginx 缓存服务器的性能。
Memcached 缓存模块配置指令如下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
memcached_bind | address[transparent]或 off | -- |
设置从指定的本地 IP 地址及端口与 Memcached 服务器建立连接,指令值可以是变量。指令值参数为 transparent 时,允许将客户端的真实 IP 透传给被代理服务器, 并以客户端真实 IP 为访问被代理服务器的源 IP,指令值为 off 时,则取消上一层指令域同名指令的配置 |
memcached_buffer_size | size | 4k 或 8k | 设置用于读取 Memcached 服务器,读取响应数据缓冲区的大小,当 Nginx 收到响应数据后,将同步传递给客户端 |
memcached_connect_timeout | time | 60s | Nginx 与 Memcached 服务器建立连接的超时时间,通常不应超过 75s |
memcached_force_ranges | on 或 off | off | 启用来自 Memcached 服务器的缓存和未缓存响应的 byte-range 请求支持,而不考虑这些响应头中的 Accept-Ranges 字段 |
memcached_gzip_flag | flag | -- |
启用对 Memcached 服务器缓存数据 fags 的测试,flags 为客户端写入缓存时的自定义标记,此处用以判断缓存数据是否被压缩存储,如果数据被压缩存储, 则将响应头字段 Content-Encoding 设置为 gzip |
memcached_next_upstream | error、timeout、 invalid_header、 not found 或 off... |
error timeout | 当出现指令值中指定的条件时,将未返回响应的客户请求传递给 upstream 中的下一个服务器 |
memcached_next_upstream_timeout | time | 0 | 设置将符合条件的客户端请求传递给 upstream 中下一个服务器的超时时间。0 为不做超时限制,遍历完所有上游服务器组中的服务器为止 |
memcached_next_upstream_tries | number | 0 | 设置符合条件的客户端请求传递给upstream中下一个服务器的尝试次数,包括第一次失败的次数。0为不做尝试次数限制,遍历完所有上游服务器组中的服务器为止 |
memcached_pass | address | -- | 设置 Memcached 服务器的地址及端口,地址可以是 IP、域名或 UNIX 套接字 |
memcached_read_timeout | time | 60s | 在连续两个从 Memcached 服务器接收数据的读操作之间的间隔时间超过设置的时间时,将关闭连接 |
memcached_send_timeout | time | 60s | 在连续两个发送到 Memcached 服务器的写操作之间的间隔时间超过设置的时间时,将关闭连接 |
memcached_socket_keepalive | on 或 off | off |
设置 Nginx 与 Memcached 服务器的 TCP keepalive 行为的心跳检测机制,默认使用操作系统的 socket 配置,若指令值为 on, 则开启 SO_KEEPALIVE 选项进行心跳检测 |
配置样例如下:
server { location / { set $memcached_key "$uri?$args"; # 设置Memcached缓存key memcached_pass 127.0.0.1:11211; # 设置被代理Memcached地址 error_page 404 502 504 = @fallback; # 返回状态码404、502、504时跳入内部请求 } location @fallback { proxy_pass http://backend; # 将请求转发给后端服务器 } }
Memcached 缓存应用
为了提高动态网站的响应速度,有时会采用将动态网站转换成静态化文件的方式进行优化,而相对于磁盘存储,使用 Memcached 进行静态文件的存储则可以进一步提升网站的响应速度。Memcached 是基于内存的高性能对象缓存系统,因为存储数据都是在内存中的,所以减少了系统的 I/O 操作,从而避免了因磁盘性能带来的影响。
使用 Memcached 作为缓存存储服务器,可以直接利用 Memcached 缓存的过期机制实现缓存的自动化过期管理,且利用 Nginx 的负载机制和 Memcached 分布式特性,可以非常方便地横向扩展,以提升处理性能。Memcached 缓存应用场景如下图所示。
图:Memcached 缓存应用
Web 服务器将动态文件以请求 URI 作为 Memcached 的 key 初始化到 Memcached 服务器中;Nginx 将用户请求转发到 Memcached 服务器中,并将以请求 URI 作为 Memcached key 的数据返回给用户;当 Memcached 的请求失败后,则将请求转发给后端 Web 服务器的接口动态生成对应的静态文件,返回响应数据并更新 Memcached。
Memcached 的安装非常简单,在 CentOS 7 系统下使用 yum 安装即可,安装方法如下:
yum -y install memcached cat /etc/sysconfig/memcached PORT="11211" # 端口 USER="memcached" MAXCONN="1024" # 最大连接数 CACHESIZE="64" # 使用内存大小为64M OPTIONS="" systemctl start memcached
Nginx 服务器配置样例如下:
upstream backend { server 192.168.2.145:8190; # 后端PHP服务器IP } upstream memcached { hash $host$request_uri consistent; # 一致性hash server 192.168.2.145:11211; # Memcached服务器IP server 192.168.2.109:11211; # Memcached服务器IP } server { listen 8181; access_log logs/mem_access.log; set $memcached_key $host$request_uri; # 设置Memcached的key location / { memcached_connect_timeout 5s; # 与Memcached建立连接超时时间为5s memcached_read_timeout 2s; # 连续两次读的超时时间为2s memcached_send_timeout 2s; # 连续两次写的超时时间为2s memcached_pass memcached; # 代理到Memcached集群 add_header X-Cache-Satus HIT; # 显示缓存命中状态 add_header Content-Type 'text/html; charset=utf-8'; # 强制响应数据格式为html } error_page 404 502 504 = @fallback; location @fallback { proxy_set_header X-Memcached-Key $memcached_key; # 将memecached key传递 # 给PHP服务器 proxy_pass http://backend; # PHP服务器 } }
为了方便演示 Memcached 的使用方法,在此处提供了一段简单的 PHP 测试代码。在测试代码中,使用了 PHP 模块 Memcached 与 Nginx 兼容的一致性哈希算法实现分布式 Memcached 集群的支持。
<?php // 测试数据 $html = file_get_contents('https://www.baidu.com'); if ($_SERVER['REQUEST_METHOD'] != 'GET' || !isset($_SERVER['HTTP_X_MEMCACHED_KEY']) || !$_SERVER['HTTP_X_MEMCACHED_KEY']) { echo $html; exit(); } $memcachedKey = $_SERVER['HTTP_X_MEMCACHED_KEY']; // 初始化Memcached $memcached = new Memcached(); // 配置分布式hash一致性算法,兼容Nginx的Ketama算法 $memcached->setOptions(array( Memcached::OPT_DISTRIBUTION=>Memcached::DISTRIBUTION_CONSISTENT, Memcached::OPT_LIBKETAMA_COMPATIBLE=>true, Memcached::OPT_REMOVE_FAILED_SERVERS=>true, Memcached::OPT_COMPRESSION=>false )); // 添加Memcached服务器 $memcached->addServers(array( array('192.168.2.145', 11211), array('192.168.2.109', 11211) )); // 存储到Memcached,缓存有效期1天 $memcached->set($memcachedKey, $html, 86400); //调试用 header('X-Cache-Status: MISS'); header('X-Cache-Key: ' . $memcachedKey); //输出静态文件 print $html; ?>
4.Nginx反向代理缓存服务器配置
Nginx 代理功能根据应用方式的不同分为正向代理和反向代理,Nginx 开源版本的正向代理功能并不完整,不支持 HTTP 的 CONNECT 方法,所以 HTTPS 的正向代理功能通常是使用第三方模块来实现的。
Nginx 的 HTTPS 正向代理使用最多的第三方模块是 ngx_http_proxy_connect_module,但其不支持缓存,所以开源版本 Nginx 无法在正向代理缓存的使用场景中应用。
Nginx 的重点缓存应用是在反向代理缓存的应用场景,官方也一直在不断地增强该功能。Nginx 反向代理缓存是目前网站架构中最常用的缓存方式,其不仅被网站架设者用以提高访问速度,降低应用服务器的负载,同时也被广泛应用于 CDN 的缓存服务器中。
Nginx的反向代理缓存有以下几个功能特点。
-
- 故障降级。如果源服务器因故障停机,即便缓存过期,也可以被返回给用户使用,这就避免了页面无法打开的故障信息传递,从而实现有效容错降级;
- 缓存负载。基于Nginx提供的比例分配赋值指令,可以将请求分配给由多个不同的硬盘组成的缓存池,以实现缓存存储负载,降低I/O瓶颈,提升磁盘效率;
- 缓存锁。使多个相同的请求只有一个可以访问被代理服务器,其他的请求则等待缓存生成后,从缓存中获取响应数据,从而有效地提升缓存利用率,降低被代理服务器的负载;
- 缓存验证支持。支持在Nginx本地缓存有效期过期后,通过服务器远端验证的方式确认缓存是否有效;
- 范围请求支持。通过切片指令设置,提升了范围请求的缓存效率,使其响应速度更快;
- 缓存控制。可对用户的请求是否使用缓存、响应数据是否被缓存、可被缓存的最低使用频率等方式实现缓存控制。
配置样例如下:
upstream backend_server { ip_hash; # session会话保持 server 192.168.2.145:8081; # 被代理服务器IP server 192.168.2.159:8081; # 被代理服务器IP } proxy_cache_path /usr/local/nginx/nginx-cache1 levels=1:2 keys_zone=cache_hdd1:100m max_size=10g use_temp_path=off inactive=60m; # 设置缓存存储路径1,缓存的共享内存名称和大小100MB, # 无效缓存的判断时间为1小时 proxy_cache_path /usr/local/nginx/nginx-cache2 levels=1:2 keys_zone=cache_hdd2:100m max_size=10g use_temp_path=off inactive=60m; # 设置缓存存储路径2,缓存的共享内存名称和大小100MB, # 无效缓存的判断时间为1小时 split_clients $request_uri $proxy_cache { 50% "cache_hdd1"; # 50%请求的缓存存储在第一个磁盘上 50% "cache_hdd2"; # 50%请求的缓存存储在第二个磁盘上 } server { listen 8080; root /opt/nginx-web/phpweb; index index.php; include proxy.conf; # 引入默认配置文件 location ~ \.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) { # 设置客户端静态资源文件缓存过期时间为12小时 expires 12h; } proxy_ignore_headers Cache-Control Set-Cookie; # 忽略被代理服务器返回响应头中指定字段的控制响应 location ~ / { root /opt/nginx-web/phpweb; proxy_cache $proxy_cache; # 启用proxy_cache_path设置的$proxy_cache的共享内存区域 proxy_cache_lock on; # 启用缓存锁 proxy_cache_lock_age 5s; # 缓存锁有效期为5s proxy_cache_lock_timeout 5s; # 等待缓存锁超时时间为5s proxy_cache_methods GET HEAD; # 默认对GET及HEAD方法的请求进行缓存 proxy_cache_min_uses 1; # 响应数据至少被请求1次,才将被缓存 proxy_cache_bypass $http_pragma; # 当客户端请求头包含字段pragma时,不适用缓存 proxy_cache_use_stale error timeout invalid_header updating http_500 http_503 http_403 http_404 http_429; # 当出现指定条件时,使用已经过期的缓存响应数据 proxy_cache_background_update on; # 允许使用过期的响应数据时,启用后台子请求用以更新过 # 期缓存,并将过期的缓存响应数据返回给客户端 proxy_cache_revalidate on; # 当缓存过期时,向后端服务器发起服务端校验 proxy_cache_valid 200 301 302 10h; # 200 301 302状态码的响应缓存10小时 proxy_cache_valid any 1m; # 其他状态码的响应缓存1分钟 add_header X-Cache-Status $upstream_cache_status; # 添加缓存请求状态标识 proxy_pass http://backend_server; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; }
在默认配置下,Nginx 会对被代理服务器返回响应数据信息头的缓存控制字段 Cache-Control 执行相关操作。当 Cache-Control 字段的值为 private、no-cache 或者有字段 Set-Cookie 时,它会对响应数据缓存产生影响,可以使用 proxy_ignore_headers 指令忽略这些字段的操作响应。
proxy_ignore_headers Cache-Control Set-Cookie;
Nginx 默认只对 GET 和 HEAD 方法的请求进行缓存,如果想对 POST 请求方法的数据进行缓存,则可以使用 proxy_cache_methods 指令进行设置。
proxy_cache_methods GET HEAD POST;
5.Nginx expires、etag、if_modified_since:客户端缓存控制
客户端的缓存有两种验证机制,一种是基于有效期的本地有效期验证;另一种是由服务端提供的服务端验证。Nginx 提供了 expires、etag、if_modified_since 指令可实现对客户端缓存的控制。
1.有效期验证
expires 指令可实现在响应状态码为 200、201、204、206、301、302、303、304、307 或 308 时,对响应头中的属性字段 Expires 和 Cache-Control 进行添加或编辑操作。该指令会同时设置 Expires 和 Cache-Control 两个字段,客户端根据这两个字段的值执行内容缓存的本地有效期设置。
1) 设置相对时间
响应头字段 Expires 的值为当前时间与指令值的时间之和,响应头字段 Cache-Control 的值为指令值的时间。
server { expires 24h; # 设置Expires为当前时间过后的24小时,Cache-Control的值为24 # 小时 expires modified +24h; # 编辑Expires增加24小时,Cache-Control的值增加24小时 expires $expires; # 根据变量$expires的内容设置缓存时间 }
2) 设置绝对时间
可以通过前缀 @ 指定一个绝对时间,表示在当天的指定时间失效。
server { expires @15h; # 设置Expires为当前日的15点,Cache-Control的值为到 # 当前时间到15点的时间差 }
3) 无有效期设置
时间为负值或为 epoch 时,响应头字段 Cache-Control 的值为 no-cache,表示当前响应数据的内容缓存无有效期。
server { expires -1; expires epoch; }
4) 最大值设置
指令值为 max 时,Expires 的值为 Thu,31 Dec 2037 23:55:55 GMT,Cache-Control 为 10 年。
server {
expires max;
}
Nginx 除了提供指令 expires 可以实现有效期控制外,还提供了指令 add_header,可以让用户自定义响应头实现客户端缓存的控制。
server { add_header Cache-Control no-cache; # 响应数据的内容缓存无有效期 }
2.服务端验证
1) Etag 实体标签
Nginx 作为 Web 服务器时,对静态资源会自动在响应头中添加响应头字段 Etag,字段值为静态资源文件的最后编辑时间(last_modified_time)和文件大小的十六进制组合。对于代理的响应内容则由被代理服务器进行控制,不会自动添加 Etag 字段,只有存在 Nginx 服务器由 Nginx 直接读取的文件时才会自动添加 Etag 字段,它可以通过添加 etag off 指令禁止自动生成 Etag。
2) 文件修改时间
Nginx 作为 Web 服务器时,会对静态资源自动添加响应头字段 Last-Modified,字段值为静态资源文件的最后编辑时间(last_modified_time)。
Nginx 提供了配置指令 if_modified_since,对文件修改时间的服务端校验提供了两种不同的比对方式。一种是指令值为 exact 时,Nginx 会将请求头中 if_modified_since 的时间与响应数据中的时间做精确匹配,即完全相等才认为客户端缓存有效,返回响应状态码 304;另一种是指令值为 before 时,则在请求头中 if_modified_since 的时间大于响应数据中的时间也认为客户端缓存有效,返回响应状态码 304。该指令功能控制处于数据流的出入口,对于任何形式产生的响应数据都有效,当指令值为 off 时,则关闭 Nginx 对客户端缓存文件修改时间的服务端校验功能。
任何与用户私人相关的数据都不应该被缓存,所以对于私人内容数据建议设置 HTTP 信息头 Cache-Control 字段值为 no-cache、no-store 或 private 控制客户端不进行缓存,根据数据内容的敏感性,正确设置这些头字段,可以在保持维护私人信息安全的前提下利用缓存的优势提升网站的响应速度。
指令说明