Nginx 如何善用缓存提升系统的健壮性?(上)

Nginx 如何善用缓存提升系统的健壮性?(上)


分布式系统提升可用性时,最有效的方案就是在空间维度上,将资源复制一份作为缓存,并把缓存放在离用户更近的地方。这样,通过缩短用户的访问路径,不只可以降低请求的时延,多份资源还能提升系统的健壮性。比如WEB服务中的CDN就是这样一个缓存系统。

 

Nginx由于具有下面3个特性,因此是最合适的缓存系统:

l  首先,高并发、低延迟赋予了Nginx优秀的性能;

l  其次,多进程架构让Nginx具备了很高的稳定性;

l  最后,模块化的开源生态,以及从开放中诞生的Openresty、Kong等其他体系,这都让Nginx的功能丰富而强大。

 

所以,Nginx往往部署在企业最核心的边缘位置,在最外层的Nginx上部署共享缓存,能够给服务带来更大的收益,更短的访问路径带来了更佳的用户体验。然而,当整个系统的可用性极度依赖Nginx的缓存功能时,我们必须仔细地配置Nginx,还得使用到缓存的许多进阶功能。

 

比如,在超大流量下如果热点资源的缓存失效,那么在巨大的流量穿透Nginx缓存后,非常有可能把脆弱的上游服务打挂。此时合并回源请求功能,就是你的最佳应对手段!再比如,在源服务器暂时不可用时,使用失效过期的缓存,为用户提供有限的服务,可以通过降级体验来提升系统的健壮性,这要比给用户返回“系统暂时不可用”要好得多。再比如,Nginx重启后,需要为磁盘上大量的缓存文件,在共享内存中建立起索引,这一过程可能很漫长,我们必须防止它对正常的服务产生过大的影响,降低用户体验。

 

 如果你不清楚Nginx缓存的这些用法,就无法在超大流量场景中,用Nginx缓存保障服务的高可用性。当然,你可能觉得加机器扩容简单粗暴又有效,可是,一旦Nginx缓存正常工作后,这些新增的机器利用率又变得极低,这提升了公司的IT成本。因此,Nginx缓存的这些进阶用法,是你必须掌握的知识点!

 

这篇文章将分为上、下两个部分,先带着你回顾下Nginx缓存的基本用法,再来看如何使用缓存的进阶功能。

 

缓存的基本工作流程


时间局部性原理,决定了缓存的有效性。比如,当客户端首次获取到/url1对应的资源时,它可以用key/value的形式,将请求与响应同时缓存到磁盘上,其中,key就是/url1,而value就是响应中的资源。只要服务器没有更改/url1对应的资源内容,那么在时间维度上,后续访问/url1的请求,就一直可以使用磁盘上的缓存代替网络访问来提升性能,如下图所示: 

Nginx 如何善用缓存提升系统的健壮性?(上)

通过缓存,请求的时延得到极大的下降,因为访问磁盘不过几十毫秒,但经过以秒级计量的网络再到达源服务器,并由源服务器再读取磁盘,速度就慢了很多,尤其在网络是不稳定、不可控的时候。

 

然而,服务器上的资源一旦发生了更新,客户端的缓存就失效了,使用这样的缓存有可能导致业务逻辑出错,怎么解决这一问题呢?通常,由于服务器最清楚资源的变更频率,这样,在服务器发送的响应中,设置一个预估缓存失效时间的HTTP头部,就可以解决这一问题。就像Cache-Control: max-age头部,或者Expires头部,等等。

 

客户端基于服务器告知的失效时间设立定时器,当定时器归零触发时,再将缓存设置为失效即可。注意,失效的缓存仍然有多方面的价值

 

首先,客户端的失效定时器,毕竟来源于服务器的预估时间,时间过期后服务器上的资源也可能并未发生变化。这样,如果我们给每份资源生成唯一的ID(也就是缓存摘要,RFC规范用etag头部表示摘要),而客户端在判定缓存失效后,能够携带着摘要访问服务器,这就允许服务器通过304 Not Modified空包体回复客户端。如果资源是一个数百MB的视频文件,这一下就省去了数百MB字节的网络传输,如下图所示:

Nginx 如何善用缓存提升系统的健壮性?(上)

 

Etag摘要究竟是怎样生成的呢?Nginx会将文件大小和最近修改时间,拼接为一个字符串作为文件摘要,虽然区分度稍差,但优点是生成速度非常快。

 

其次,在某些场景下,给用户提供不那么及时的过期页面,要比返回500 服务器内部错误好得多。Nginx的proxy_cache_use_stale指令就可以完成这一功能,我们下一篇再细说。

 

缓存可以存放在任何位置!其中,仅存放于终端、只为一个用户服务的缓存,叫做私有缓存(Private Cache),而存放于服务器上,可以被多个用户共享使用的缓存,叫做共享缓存(Public Cache)。比如下图的REST架构中,浏览器User Agent中的$符号($表示现金cash,与cache发音很接近,故常用来表示缓存)表示私有缓存,而Proxy正向代理、Gateway反向代理中的$符号表示共享缓存:

Nginx 如何善用缓存提升系统的健壮性?(上)

Nginx上的缓存就是共享缓存,接下来我们看看如何配置共享缓存。