聊聊高并发系统之HTTP缓存(3)
对于静态资源会自动添加ETag,可以通过添加“etag off”指令禁止生成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_since exact”表示精确匹配,也可以使用“if_modified_sincebefore”表示只要文件的上次修改时间早于或等于浏览器短的If-Modified-Since时间,就返回304. nginx proxy expires使用nginx作为反向代理时,请求会先进入nginx,然后nginx将请求转发给后端应用.如下图所示: 首先配置upstream: upstream backend_tomcat { server 192.168.61.1:9080 max_fails=10 fail_timeout=10s weight=5; } 接着配置location: location = /cache { proxy_pass http://backend_tomcat/cache$is_args$args; } 接下来我们可以通过如http://192.168.61.129/cache?millis=1471349916709访问nginx,nginx会将请求转发给后端java应用.也就是说nginx只是做了相关的转发(负载均衡),并没有对请求和响应做什么处理. 假设对后端返回的过期时间需要调整,可以添加expires指令到location: location = /cache { proxy_pass http://backend_tomcat/cache$is_args$args; expires 5s; } 然后再请求相关的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匹配,则返回300状态码给浏览器,否则返回200状态码和最新的文档给浏览器. 即内容不需要动态(计算、渲染等)速度更快,内容越接近于用户速度越快.像apache traffic server、squid、varnish、nginx等技术都可以来进行内容缓存.还有CDN就是用来加速用户访问的: 即用户首先访问到全国各地的CDN节点(使用如ATS、Squid实现),如果CDN没命中,会回源到中央nginx集群,该集群如果没有命中缓存(该集群的缓存不是必须的,要根据实际命中情况等决定),最后回源到后端应用集群. 像我们商品详情页的一些服务就大量使用了nginx缓存减少回源到后端的请求量,从而提升访问速度.可以参考《构建需求响应式亿级商品详情页》、《京东商品详情页服务闭环实践》和《应用多级缓存模式支撑海量读服务》. nginx代理层缓存http模块配置: proxy_buffering?????????????? on; proxy_buffer_size???????????? 4k; proxy_buffers????????????????? 512 4k; proxy_busy_buffers_size????? 64k; proxy_cache_path???????????? /export/cache/proxy_cachelevels=1:2 keys_zone=cache:512m inactive=5m max_size=8g use_temp_path=off; #proxy timeout proxy_connect_timeout? 3s; proxy_read_timeout???? 5s; proxy_send_timeout???? 5s; 其中红色部分是proxy_cache_path指令相关配置: levels=1:2 :表示创建两级目录结构,比如/export/cache/proxy_cache/7/3c/,将所有文件放在一级目录结构中如果文件量很大会导致访问文件慢; keys_zone=cache:512m :设置存储所有缓存key和相关信息的共享内存区,1M大约能存储8000个key; inactive=5m :inactive指定被缓存的内容多久不被访问将从缓存中移除,以保证内容的新鲜;默认10分钟; max_size=8g :最大缓存阀值,“cachemanager”进程会监控最大缓存大小,当缓存达到该阀值,该进程将从缓存中移除最近最少使用的内容; use_temp_path:如果为on,则内容首先被写入临时文件(proxy_temp_path?),然后重命名到proxy_cache_path指定的目录;如果设置为off,则内容直接被写入到proxy_cache_path指定的目录,如果需要cache建议off,该特性是1.7.10提供的. location配置location = /cache { proxy_cache cache; proxy_cache_key $scheme$proxy_host$request_uri; proxy_cache_valid 200 5s; proxy_pass http://backend_tomcat/cache$is_args$args; add_header cache-status $upstream_cache_status; } 缓存相关配置: proxy_cache :指定使用哪个共享内存区域存储缓存键和相关信息; proxy_cache_key :设置缓存使用的key,默认为访问的完整URL,根据实际情况设置缓存key; proxy_cache_valid :为不同的响应状态码设置缓存时间;如果是proxy_cache_valid 5s 则200、301、302响应将被缓存; proxy_cache_validproxy_cache_valid不是唯一设置缓存时间的,还可以通过如下方式(优先级从上到下): 1、以秒为单位的“X-Accel-Expires”响应头来设置响应缓存时间; 2、如果没有“X-Accel-Expires”,可以根据“Cache-Control”、“Expires”来设置响应缓存时间; 3、否则使用proxy_cache_valid设置的缓存时间; 如果响应头包含Cache-Control:private/no-cache/no-store、Set-Cookie或者只有一个Vary响应头且其值为*,则响应内容将不会被缓存.可以使用proxy_ignore_headers来忽略这些响应头. add_headercache-status $upstream_cache_status在响应头中添加缓存命中的状态: HIT:缓存命中了,直接返回缓存中内容,不回源到后端; MISS:缓存没有命中,回源到后端获取最新的内容; EXPIRED:缓存命中但过期了,回源到后端获取最新的内容; UPDATING:缓存已过期但正在被别的nginx进程更新;配置了proxy_cache_use_staleupdating指令时会存在该状态; STALE:缓存已过期,但因后端服务出现了问题(比如后端服务挂了)返回过期的响应;配置了如proxy_cache_use_stale error?timeout指令后会存在该状态; REVALIDATED:启用proxy_cache_revalidate指令后,当缓存内容过期时nginx通过一次If-Modified-Since的请求头去验证缓存内容是否过期,此时会返回该状态; BYPASS:proxy_cache_bypass指令有效时强制回源到后端获取内容,即使已经缓存了; proxy_cache_min_uses用于控制请求多少次后响应才被缓存;默认“proxy_cache_min_uses 1;”,如果缓存热点比较集中、存储有限,可以考虑修改该参数以减少缓存数量和写磁盘次数; proxy_no_cache?用于控制什么情况下响应将不被缓存;比如配置“proxy_no_cache $args_nocache”,如果带的参数值至少有一个不为空或者0,则响应将不被缓存; proxy_cache_bypass类似于proxy_no_cache,但是其控制什么情况不从缓存中获取内容,而是直接到后端获取内容;如果命中则$upstream_cache_status为BYPASS; proxy_cache_use_stale(编辑:ASP站长网) |