点赞
评论
收藏
分享
举报
Nginx 减轻缓存失效对上游服务压力 proxy_cahce_lock和proxy_cache_use_stale
发表于2021-02-08 09:44

浏览 1.3k

文章标签

合并回源请求场景


Nginx的缓存满足了绝大部分的应用场景,当我们的服务面对非常大的流量的时候,如果我们的缓存服务例如nginx出现了一些问题,比如新增加了或者一些nginx宕机了,缓存已经失效了,这些ngixn起来的时候会导致大量的请求穿透nginx,因为当前nginx缓存都是失效的,这样全部的请求打到了上游服务,特别是对一些热点的文件,很多用户访问的是同一个资源,但是因为这个资源突然失效了,这些并发的请求全部打到了上游服务,而导致上游服务一直起不来。Nginx对于这种场景有很多的处理方法。

Nginx是怎么样通过合并回源请求等等方式来减轻上游服务在高峰期并发访问压力的呢?

合并回源请求,减轻峰值流量下的压力 proxy_cache_lock


Syntax:proxy_cache_lock on | off;
Default:
proxy_cache_lock off;
Context:httpserverlocation

This directive appeared in version 1.1.12.

When enabled, only one request at a time will be allowed to populate a new cache element identified according to the proxy_cache_key directive by passing a request to a proxied server. Other requests of the same cache element will either wait for a response to appear in the cache or the cache lock for this element to be released, up to the time set by the proxy_cache_lock_timeout directive.

Syntax:proxy_cache_lock_age time;
Default:
proxy_cache_lock_age 5s;
Context:httpserverlocation

This directive appeared in version 1.7.8.

If the last request passed to the proxied server for populating a new cache element has not completed for the specified time, one more request may be passed to the proxied server.

 最近使用nginx做缓存,发现当大量客户端访问一个没有cache的文件时,回源的流量非常大,在站源上查看日志也看到确实有并发的请求。这个就是需要改成合并回源,当cache内没有数据的时候,只允许1个请求去站源请求数据,写到本地cache。nginx从1.1.12开始原生支持合并回源了。主要有2个配置项(proxy_cache_lock和proxy_cache_lock_timeout控制,开源nginx通过配置proxy_cache_lock指令,可以在一段时间内合并回源请求。但后续请求必须等第一个请求从上游获取完整响应并注入cache后,才会继续往下处理。). 

proxy_cache_lock被启用时,当多个客户端请求一个缓存中不存在的文件(或称之为一个MISS),只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用proxy_cache_lock,则所有在缓存中找不到文件的请求都会直接与服务器通信。

指令说明
proxy_cache_lock启用这个指令,当多个客户端请求一个缓存中不存在的文件(或称之为一个MISS),只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。
proxy_cache_lock_timeout设置proxy_cache_lock的超时时间。当time到期时,请求将被传递给代理的服务器,但是,响应不会被缓存。
  1. Syntax: proxy_cache_lock on | off;
  2. Default: proxy_cache_lock off;
  3. Context: http, server, location
  4. Syntax: proxy_cache_lock_timeout time;
  5. Default: proxy_cache_lock_timeout 5s;
  6. Context: http, server, location
  7. Syntax: proxy_cache_lock_age time;
  8. Default: proxy_cache_lock_age 5s;
  9. Context: http, server, location
  10. 是一个请求发挥响应超时时间,到达后再放行一个请求发往上游

合并回源请求:如果是正常的情况下,nginx对某个热点资源没有做缓存还有四个客户端同时访问的话,那么这四个请求全部都打到了上游服务,那么怎么样解决这个问题呢?

可以使用proxy_cahce_lock指令,这个指令默认是关闭的,当我们打开为on的时候,同一时间,仅第一个请求可以发到上游,其他请求要求等待第一个响应返回或者超时以后来使用缓存响应客户端。

如图:第一步,第一个客户端发来的请求到达nginx,第二步,第二个客户端也发来了请求,nginx让第二个客户端请求其在此等待,也不会向第二个客户端发送响应,也不会发送到上游服务。第三步,nginx将第一个请求向上游发送了,而这个时候第三个客户端发来请求nginx告诉其要求再次等待,第四个客户端发来请求也在此等待,第六步上游服务器终于发回来了响应,第七步,先向第一个客户端发送响应,同时由于已经有缓存了,所以会向第二个客户端,第三个客户端,第四个客户端根据缓存发送响应,这就大大的减轻了上游服务的压力。

为了控制这个流程还有两个指令,第一个指令是proxy_cache_lock_timeout,默认是5秒,表示等待第一个请求返回响应的最大时间,也就是说针对的是2,3,4客户端,当2,3,4客户端等待了5秒以后,第一个客户端请求还没有生成响应的缓存,那么2,3,4请求直接同时打向上游服务器。

第二个指令是proxy_cahce_lock_age,第一个请求返回响应的超时时间达到了达到了默认的5秒了,再放行第二个请求,第三个第四个依次等待,依次放行。

说了这么多举个简单的配置例子:

  1. location / {
  2. proxy_pass http://complicated.cn ;
  3. proxy_cache nginx_cache;
  4. proxy_cache_valid 200 1s;
  5. proxy_cache_bypass $http_x_purge_cache;
  6. #proxy_no_cache $http_x_purge_cache;
  7. #proxy_cache_use_stale updating;
  8. proxy_cache_lock on;
  9. proxy_cache_lock_timeout 50s;
  10. }
  11. proxy_cache_lock on; //同一时间只允许一个请求更新缓存,其他请求要么等待,要么超时后直接访问源文件。
  12. proxy_cache_lock_age 5s; // 如果一个请求在5秒内没完成缓存更新,那么其他后面的请求就直接访问源文件。

 

减少回源请求,使用stale陈旧缓存


陈旧总比没有强

这种方式是虽然我的缓存失效了,但是使用旧的缓存给客户,这样给用户的体验是比较好的。在这种场景下面宁愿使用旧的缓存。

NGINX内容缓存的一个非常强大的特性是:当无法从原始服务器获取最新的内容时,NGINX可以分发缓存中的陈旧(stale,编者注:即过期内容)内容。这种情况一般发生在关联缓存内容的原始服务器宕机或者繁忙时。比起对客户端传达错误信息,NGINX可发送在其内存中的陈旧的文件。NGINX的这种代理方式,为服务器提供额外级别的容错能力,并确保了在服务器故障或流量峰值的情况下的正常运行。为了开启该功能,只需要添加proxy_cache_use_stale命令即可:

  1. location / {
  2. ...
  3. proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
  4. }
  1. Syntax:
  2. proxy_cache_use_stale error | timeout | invalid_header |
  3. updating | http_500 | http_502 | http_503 | http_504 |
  4. http_403 | http_404 | http_429 | off ...;
  5. Default: proxy_cache_use_stale off;
  6. Context: http, server, location
  7. Syntax: proxy_cache_background_update on | off;
  8. Default: proxy_cache_background_update off;
  9. Context: http, server, location
  10. #当使用proxy_cache_use_stale允许使用过期响应时,将同步产生一个子请求,通过访问上游服务更新缓存
  11. Syntax: proxy_cache_revalidate on | off;
  12. Default: proxy_cache_revalidate off;
  13. Context: http, server, location
  14. #更新缓存时候,使用If-Modifiled-Since和If-None-Match作为请求头部,预期内容未发生变更时候通过304减少传输内容

当proxy_cache_use_stale引入updating的时候用原理下图表示:

第一步,第一个客户端发来请求,紧接着第二个客户端发来请求,实际上客户端发送的第一个请求之后nginx就准备将该请求向上游发送了,在第三步向上游发送请求要求重新更新缓存,这个时候第四步第三个客户端发来了请求,因为有旧缓存,因为配置了updating,所以在第五步和第六步分别向第二个或者第三个客户端发送我的旧缓存内容。

第七步上游服务终于发回来响应更新缓存了,此时第四个客户端发来的请求就可以使用新缓存了,最后第九步第十步都将新缓存的内容返回给客户端。

proxy_cache_revalidate指令:

该指可以减轻上游服务的负担,更新缓存时候使用if-mofified-since和if-none-match作为请求头部,预期内容未发生变更时通过304来减少传输内容(if-none-match后面跟着etag,if-modified-since后面跟着last-modified)

我希望上游服务和nginx之间发送响应的时候,不要总是发送200,如果缓存没有过期返回304就可以了,不需要返回完整的文件内容,这个和浏览器与nginx交互时候的流程是一模一样的。

如上图所示:proxy_cache_revalidate设置为on,访问的时候nginx与上游可能会发生200,设置为on了之后,会将etag,if-modified-since传入上游服务,上游服务返回304而不用返回200很大的body了。

上面是nginx在峰值情况下去减轻上游服务的压力,在生产环境面对大流量的服务,上面这些指令可以给我们提供很大的帮助,他可以在突发故障的时候保证我们的nginx不会对上游服务产生巨大的流量冲击。

已修改于2023-03-09 02:15
创作不易,留下一份鼓励
守望

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
守望
这家伙很懒还未留下介绍~
89
文章
0
问答
17
粉丝
相关文章
分布式系统提升可用性时,最有效的方案就是在空间维度上,将资源复制一份作为缓存,并把缓存放在离用户更近的地方。这样,通过缩短用户的访问路径,不只可以降低请求的时延,多份资源还能提升系统的健壮性。比如WEB服务中的CDN就是这样一个缓存系统。 Nginx由于具有下面3个特性,因此是最合适的缓存系统:l 首先,高并发、低延迟赋予了Nginx优秀的性能;l 其次,多进程架构让Nginx具备了很高的稳定性;l 最后,模块化的开源生态,以及从开放中诞生的Openresty、Kong等其他体系,这都让Nginx的功能丰富而强大。 所以,Nginx往往部署在企业最核心的边缘位置,在最外层的Nginx上部署共享缓存,能够给服务带来更大的收益,更短的访问路径带来了更佳的用户体验。然而,当整个系统的可用性极度依赖Nginx的缓存功能时,我们必须仔细地配置Nginx,还得使用到缓存的许多进阶功能。 比如,在超大流量下如果热点资源的缓存失效,那么在巨大的流量穿透Nginx缓存后,非常有可能把脆弱的上游服务打挂。此时合并回源请求功能,就是你的最佳应
点赞 12
浏览 2.4k
本文是我对2019年GOPS深圳站演讲的文字整理。这里我希望带给各位读者的是,如何站在整个互联网背景下系统化地理解Nginx,因为这样才能解决好大流量分布式网络所面临的高可用问题。标题里有“巧用”二字,何谓巧用?同一个问题会有很多种解决方案,但是,各自的约束性条件却大不相同。巧用就是找出最简单、最适合的方案,而做到这一点的前提就是必须系统化的理解Nginx!本文分四个部分讲清楚如何达到这一目的:首先要搞清楚我们面对的是什么问题。这里会谈下我对大规模分布式集群的理解;Nginx如何帮助集群实现可伸缩性;Nginx如何提高服务的性能;从Nginx的设计思路上学习如何用好它。1.大规模分布式集群的特点互联网是一个巨大的分布式网络,它有以下特点:多样化的客户端。网络中现存各种不同厂商、不同版本的浏览器,甚至有些用户还在使用非常古老的浏览器,而我们没有办法强制用户升级;多层代理。我们不知道用户发来的请求是不是通过代理翻墙过来的;多级缓存。请求链路上有很多级缓存,浏览器、正反向代理、CDN等都有缓存,怎么控制多级缓存?RFC规范中有明确的定义,但是有些Server并不完全遵守;不可控的流量风暴。
点赞 10
浏览 3k
介绍nginx网页配置工具QQ技术交流群1:1106758598QQ技术交流群2:560797506邮箱: cym1102@qq.com官网地址: http://www.nginxwebui.cn码云: https://gitee.com/cym1102/nginxWebUIgithub: https://github.com/cym1102/nginxWebUI功能特点nginxWebUI也可管理多个nginx服务器集群,随时一键切换到对应服务器上进行nginx配置,也可以一键将某台服务器配置同步到其他服务器,方便集群管理.部署此项目后,配置nginx再也不用上网各种搜索配置代码,再也不用手动申请和配置ssl证书,只需要在本项目中进行增删改查就可方便的配置和启动nginx。技术说明本项目是基于springBoot的web系统,数据库使用sqlite,因此服务器上不需要安装任何数据库项目启动时会释放一个.sqlite.db到系统用户文件夹中,注意进行备份本系统通过Let'sencrypt申请证书,使用acme.sh脚本
点赞 6
浏览 6.1k