在前端已经设置了缓存时间戳的情况下,后端数据库也已经更新,但是请求接口获取的数据仍然是老数据,排除了304重定向的问题,发现是服务器Varnish设置了缓存。
Varnish是一个http反向代理的缓存,高性能,轻量级,web应用程序加速器。
它通过缓存服务端的输出来减少你的网站/应用/API的加载时间,从而提高性能。
默认监听TCP80端口。
特点: 基础内存进行缓存,重启后数据消失;利用虚拟内存方式,性能好;支持设置0-60秒的精确缓存时间;VCL配置管理,比较灵活;状态机设计巧妙,结构清晰;后端服务器的负载均衡和健康检查 URL地址重写;优雅的处理后端服务器宕机的问题; 过程: varnish从客户端接收请求 然后尝试从缓存中获取数据来响应客户端的请求 ;如果varnish不能从缓存中获得数据来响应客户端;它将转发请求到后端,获取响应同时缓存到本地 最后交付给客户端;如果varnish已经缓存了某个响应,则请求直接从varnish的缓存中获取响应;比从后端服务器去获取数据快的多;
bereq.
由varnish发往服务器的http请求;
beresp.
由服务器响应给varnish的响应报文;
resp.
由varnish响应给client相关;
obj.
只读的,存储在缓存空间中的缓存对象的属性;
Management管理进程:编译VCL并应用新配置、监控varnish、初始化varnish并提供命令行接口CLI;Child/Cache线程: Acceptor:用于接收并连接请求; Worker:用于处理并响应用户请求; Object expiry:从缓存中清理过期的cache object; cache-main:此线程只有一个,用于启动cache; banluker:清理指定缓存; expire:清理过期缓存 epoll:线程池管理器;varnish定义其最大并发连接数是通过线程池模型实现的: thread_pools:线程池个数,默认为2; thread_pool_max:单线程池内允许启动的最大线程个数; thread_pool_min:单线程池内允许启动的最小线程个数; thread_pool_timeout:多于thread_pool_min的线程空闲此参数指定的时长后即被purge;Log file:varnish的日志,为保持其高性能,保持在一段共享内存空间中–Shared Memory Log,共享内存日志大小一般为90M,分为两部分:前一部分为计数器,后一部分为客户请求相关的数据,可以计算缓存命中率、分析请求首部、记录响应首部等;vcl:Varnish Configuration Language 缓存策略配置工具; 基于“域”的简单编程语言,意为其所有代码都是写在各“{}”中,且作用范围仅为对应的“{}”,这些“域”称为varnish的状态引擎;varnish定义其最大并发连接数:线程池模型: thread_pools:线程池个数;默认为2; thread_pool_max:单线程池内允许启动的最多线程个数; thread_pool_minthread_pool_timeout:多于thread_pool_min的线程空闲此参数指定的时长后即被purge; 实现负载均衡
1、varnish实现调度的方式:
round-robin:加权轮询,每个backend都有它的权重random:随机dns:基于DNS解析之后进行调度
2、使用varnish自动清理缓存
使用pruge 修剪缓存,能够让用户清理所指定的某个特定缓存对象,如果要移除多个缓存对象,对缓存某些内容基于正则方式进行清理的话,可以进行banning这种机制Banning通常可以移除指定的缓存对象或者进行匹配某些对象进行处理。
Varnish的缓存策略偏向保守型的可以通过配置修改),默认缓存get请求和Head请求,不会缓存cookie和认证信息的请求,也不会缓存带有Set-cookie和有变化的头信息的响应。
Varnish会检查和请求响应中的Cache-control头信息,头信息中的一些选项控制缓存行为,当头信息有max-age=n,varnish以此n设置缓存时间,否则,取缓存默认时间default_ttl:120s。
Varnish子程序 vcl_recv: 接收到客户端请求后执行。返回结果有: pass:直接去后端服务器请求资源,从后端拿到的数据不会被缓存; pipe:直接去后端服务器请求资源,也不会被缓存,并且处理的请求不会被记录日志; hash:进行hash计算检查缓存; purge:在缓存中查找缓存对象并清除; synth:合成http响应报文,通常是错误报文;vcl_pass: 当一个subroutine执行return pass时,跳转到vcl_pass处理,把请求设置为pass模式,返回以下结果: fetch:不会被缓存,直接响应给客户端; synth:进入vcl_synth合成响应报文; restart:从vcl_recv重新开始;vcl_miss: 根据缓存命中情况来执行 fetch:获取服务器响应结果,缓存到本地; pass:从后端获取到响应,但本地不缓存;vcl_hit: 缓存命中执行。 deliver:直接将缓存结果返回给客户端; pass:丢弃缓存,重新从后端获取数据;vcl_fetch: 从后端服务器获取数据之后执行,通过beresp对象访问响应的数据。 deliver:将数据返回给客户端; restart:重新开始这个请求;vcl_deliver:将响应结果返回给客户端,结束请求。
Varnish配置文件 # 1.定义一个健康监测vcl 4.0; #指定版本import directors; #加载后端的轮询模块probe backend_healthcheck { #设置名为backend_healthcheck的健康监测 .url = “/index.html”; .window = 5; #窗口 .threshold = 2; #门槛 .interval = 3s; .timeout = 1s;}# 后端服务器backend web1 { .host = “127.0.0.1”; .port = “80”; .probe = backend_healthcheck;}backend web2 { .host = “127.0.0.1”; .port = “80”; .probe = backend_healthcheck;}# 设置后端集群事件sub vcl_init { new img_cluster = directors.round_robin); img_cluster.add_backendweb1); img_cluster.add_backendweb2);} acl purgers { # 定义可访问来源IP,权限控制 “127.0.0.1”; “172.17.0.0”/16;}# 定义引擎sub vcl_recv { if req.method == “GET” && req.http.cookie) { returnhash); //处理完recv 引擎,给下一个hash引擎处理 } if req.method != “GET” && req.method != “HEAD” && req.method != “PUT” && req.method != “POST” && req.method != “TRACE” && req.method != “OPTIONS” && req.method != “PURGE” && req.method != “DELETE”) { return pipe); //除了上边的请求头部,通过通道直接扔后端的pass }# 定义index.php不经过缓存 直接后端请求 if req.url ~ “index.php”) { returnpass); }# 定义删除缓存的方法 if req.method == “PURGE”) { //PURGE请求的处理的头部,清缓存 if client.ip ~ purgers) { returnpurge); } }# 为发往后端主机的请求添加X-Forward-For首部 if req.http.X-Forward-For) { set req.http.X-Forward-For = req.http.X-Forward-For + “,” + client.ip; } else { set req.http.X-Forward-For = client.ip; } returnhash);}# 定义vcl_hashsub vcl_hash { hash_datareq.url);}# 自定义缓存文件的缓存时长,即TTL值sub vcl_backend_response { if bereq.url ~ “\.jpg|jpeg|gif|png)$”) { set beresp.ttl = 30d; } if bereq.url ~ “\.html|css|js)$”) { set beresp.ttl = 7d; } if beresp.http.Set-Cookie) { //定义带Set-Cookie首部的后端响应不缓存,直接返回给客户端 set beresp.grace = 30m; returndeliver); }} # 定义vcl_deliversub vcl_deliver { if obj.hits > 0) { //为响应添加X-Cache首部,显示缓存是否命中 set resp.http.X-Cache = “HIT from ” + server.ip; } else { set resp.http.X-Cache = “MISS”; } unset resp.http.X-Powered-By; //取消显示php框架版本的header头 unset resp.http.Via; //取消显示varnish的header头} node-varnish的使用 npm install node-varnishvar Varnish = require’node-varnish’);var client = new Varnish.VarnishClient’127.0.0.1′, MANAGEMENT_PORT[, secret]);client.on’ready’, function) { client.run_cmd’purge obj.http.X == test’, function){});});