当前位置: 首页 > 科技观察

张凯涛:NginxHTTP缓存设置

时间:2023-03-16 13:52:35 科技观察

Nginx提供了expires、etag、if-modified-since指令来实现浏览器缓存控制。1.expires如果我们使用Nginx作为静态资源服务器,我们可以使用expires来进行缓存控制。location/img{alias/export/img/;expires1d;}当我们访问静态资源时,比如http://192.168.61.129/img/1.jpg,我们会得到类似如下的响应头。对于静态资源,会自动添加ETag,可以通过添加etagoff命令来禁止ETag的生成。如果是静态文件,Last-Modified值为文件的最后修改时间。Expires是根据当前服务器系统时间计算的。以上Nginx配置的计算逻辑(实际计算逻辑不止于此,具体请参考官方文档)。if(expires==NGX_HTTP_EXPIRES_ACCESS||r->headers_out.last_modified_time==-1){max_age=expires_time;expires_time+=now;}二、if-modified-since这个指令用来指定Nginx如何取Last-Modified和对比浏览器端的if-modified-since时间。默认的“if_modified_sinceexact”表示完全匹配。也可以用"if_modified_since_before"表示只要文件的最后修改时间早于或等于浏览器端的if-modified-since时间,就返回304。3.当nginxproxy_pass使用Nginx时作为反向代理,请求会先进入Nginx,然后Nginx将请求转发给后端应用,如下图所示。首先配置上游。upstreambackend_tomcat{server192.168.61.1:9080max_fails=10fail_timeout=10sweight=5;}然后配置位置。location=/cache{proxy_passhttp://backend_tomcat/cache$is_args$args;}接下来我们可以通过http://192.168.61.129/cache?millis=1471349916709访问Nginx,Nginx会将请求转发给后端Java应用.也就是说,Nginx只做相关的转发(负载均衡),对请求和响应不做任何事情。假设需要调整后端返回的过期时间,可以在location中添加Expires命令。location=/cache{proxy_passhttp://backend_tomcat/cache$is_args$args;expires5s;}然后请求相关的URL,你会得到如下响应。Expires指令改变了与过期时间相关的响应头,但last-modified不变。即使我们更改了缓存过期头,Nginx本身也不会在代理层缓存这些内容,每个请求仍然需要在后端进行验证。假设在过期时间内,这些校验都可以在Nginx层校验,不需要在后端校验,这样可以减轻后端的压力。即,整体流程如下。1、浏览器发起请求,先向Nginx,Nginx根据URL在Nginx本地搜索,看是否有本地代理层缓存。2、Nginx没有找到本地缓存,然后访问后端获取***文档,放入Nginx本地缓存,返回一个200状态码和***文档给浏览器。3、Nginx找到本地缓存,首先验证文档是否过期(Cache-Control:max-age=5),如果过期,访问后端获取***文档,放入Nginx本地缓存,并向浏览器返回200状态码和***文档;如果文档没有过期,即if-modified-since与缓存文档的last-modified匹配,则向浏览器返回304状态码。内容不需要访问后端,即不需要后端动态计算/渲染等,Nginx代理层直接返回内容,速度更快,内容离用户更近,它越快。ApacheTrafficServer、Squid、Varnish和Nginx等技术都可以用于内容缓存。还有就是用来加速用户访问的CDN技术。即用户首先访问全国CDN节点(使用ATS、Squid等)。如果没有安装CDN,会回到中心Nginx集群。该集群用作二级缓存。集群的缓存不是必须的,要根据实际安装情况等来确定),然后安装返回到后端应用集群。一些服务,比如我们的产品详情页面,大量使用了Nginx缓存,减少了返回后端的请求量,从而提高了访问速度。可参考《打造需求响应的亿级商品详情页》和《京东商品详情页服务闭环实践》。四、Nginx代理层存储1.Nginx代理层缓存配置HTTP模块配置proxy_bufferingon;proxy_buffer_size4k;proxy_buffers5124k;proxy_busy_buffers_size64k;proxy_cache_path/export/cache/proxy_cachelevels=1:2keys_zone=cache:512minactive=5mmax_size=8guse_temp_path=off;#proxytimeoutproxy_connect_timeout3s;proxy_read_timeout5s;proxy_send_timeout5s;proxy_cache_pathcommandconfiguration:levels=1:2:表示建立二级目录结构,缓存目录一级目录为1个字符,二级目录为2个字符,如/export/cache/proxy_cache/7/3c/,如果所有的文件都放在一级目录下,文件体积会很大,会导致文件访问变慢。keys_zone=cache:512m:设置共享内存区域,用于存放所有缓存的key及相关信息,1M可以存放8000个key左右。inactive=5m:inactive指定缓存的内容在没有被访问的情况下会在多长时间内从缓存中移除,以保证内容的新鲜度。默认值为10分钟。max_size=8g:最大缓存阈值,“缓存管理器”进程将监控最大缓存大小,当缓存达到此阈值时,该进程将从缓存中删除最近最少访问的内容。use_temp_path:如果开启,内容会先写入临时文件(proxy_temp_path),然后重命名到proxy_cache_path指定的目录;如果设置为off,内容将直接写入proxy_cache_path指定的目录。如果需要缓存,建议关闭。那么这个功能是1.7.10提供的。2.location配置location=/cache{proxy_cachecache;proxy_cache_key$scheme$proxy_host$request_uri;proxy_cache_valid2005s;proxy_passhttp://backend_tomcat/cache$is_args$args;add_headercache-status$upstream_cache_status;}3.缓存相关配置proxy_cache:指定哪个一个使用共享内存区域存储缓存信息。proxy_cache_key:设置缓存使用的key,默认为完整的访问url,根据实际情况设置缓存key。proxy_cache_valid:为不同的响应状态码设置缓存时间。如果是proxy_cache_valid5s,200、301、302响应都会被缓存。4.proxy_cache_valid不是唯一设置缓存时间的,也可以通过以下方式设置(优先级从上到下)。“X-Accel-Expires”响应标头以秒为单位设置响应缓存时间。如果没有“X-Accel-Expires”,可以根据“Cache-Control”和“Expires”设置响应缓存时间。否则,使用proxy_cache_valid设置缓存时间。如果响应头中包含Cache-Control:private/no-cache/no-store,Set-Cookie或者只有一个值为*的Vary响应头,则不会缓存响应内容。可以使用proxy_ignore_headers忽略这些标头。add_headercache-status$upstream_cache_status在响应头中添加缓存***的状态。HIT:Cache***,直接返回缓存中的内容,不向后端返回源。MISS:缓存未安装,返回源给后端获取安装的内容。EXPIRED:缓存***但过期,返回后台获取***内容。更新:缓存已过期但正在被其他Nginx工作进程更新。配置proxy_cache_use_stale更新指令时存在此状态。STALE:缓存已过期,但由于后端服务出现问题(例如后端服务宕机)而返回过期的响应。配置proxy_cache_use_staleerrortimeout等命令后会出现该状态。REVALIDATED:启用proxy_cache_revalidate命令后,当缓存内容过期时,Nginx会通过一个if-modified-since请求头来验证缓存内容是否过期,此时会返回这个状态。BYPASS:proxy_cache_bypass命令有效时,强制返回后端获取内容,即使已经缓存。5.proxy_cache_min_uses用于控制在缓存响应之前发出多少请求。默认值为“proxy_cache_min_uses1;”。如果缓存热点比较集中,存储空间有限,可以修改该参数,减少缓存的数量和写磁盘的次数。6.proxy_no_cache用于控制在什么情况下不缓存响应。例如配置“proxy_no_cache$args_nocache”,如果至少有一个nocache参数值不为空或0,则不会缓存响应。7、proxy_cache_bypass和proxy_no_cache类似,但是控制什么时候不使用缓存的内容,而是直接到后台获取***内容。如果***,则$upstream_cache_status为BYPASS。8.proxy_cache_use_stale对缓存内容的过期时间不敏感,或者后端服务出现问题时,即使缓存内容不新鲜,也比向用户返回错误要好(类似bottoming),此时可以配置该参数,如“proxy_cache_use_staleerrortimeouthttp_500http_502http_503http_504”,即如果出现超时,后端连接错误,500、502、503等错误,即使缓存内容过期,优先返回给用户。此时,$upstream_cache_status是STALE。还有updating表示缓存已经过期但是正在被其他NginxWorker进程更新,但是先返回过期的内容,此时$upstream_cache_status为UPDATING。9.proxy_cache_revalidate当缓存过期时,如果启用proxy_cache_revalidate,会发出if-modified-since或if-none-match条件请求。如果后端返回304,那么此时$upstream_cache_status被REVALIDATED,我们会得到两个好处,节省带宽和减少磁盘写入次数。10.proxy_cache_lock当多个客户端同时请求相同的内容时,如果启用proxy_cache_lock(默认关闭),则只会向后端发送一个请求。其他请求会等待这个请求返回。当第一个请求返回时,其他相同的请求会从缓存中获取内容并返回。当第一个请求超过proxy_cache_lock_timeout超时时间(默认5s),其他请求会同时向后端请求获得响应,响应不会被缓存(1.7.8版本之前有缓存)。开启proxy_cache_lock可以应对Dog-pileeffect(当某个缓存失效时,有大量相同的请求没有同时缓存,同时请求到后端,导致太多后端有压力。此时,限制一个请求获取即可)。proxy_cache_lock_age是1.7.8新增的。如果上一次发送给后端的请求在proxy_cache_lock_age指定的时间内(默认为5s)还没有完成,则下一次请求会发送给后端来构建缓存(因为1.7.8版本之后,proxy_cache_lock_timeout超时后返回的内容不缓存,下次请求需要建立响应缓存)。5.清理缓存。有时缓存的内容不对,需要手动清理。Nginx企业版提供purger功能。对于社区版的Nginx,可以考虑使用ngx_cache_purge(https://github.com/FRiCKLE/ngx_cache_purge)模块来清理缓存。location~/purge(/.*){allow127.0.0.1;denyall;proxy_cache_purgecache$1$is_args$args;}这个方法应该限制它的访问,比如只允许内网访问或者需要密码访问。代理层缓存的介绍到此结束。很多问题都可以通过代理层缓存来解决。可以参考《京东商品详情页服务闭环实践》。【本文为专栏作者张凯涛原创文章,作者微信公众号:凯涛博客(kaitao-1234567)】点此阅读更多本作者好文