varnish的大体架构,有守护进程varnishd组成
而大体上,varnish可以分为两类进程,
1.管理进程 manager process
2.缓存进程 cacher pricess 有很多线程来提供服务,
比如管理存储的storage 线程
管理日志和统计数据的log/stats
真正去处理运行的 worker threads
对于varnish而言,加载的配置分为两大类
1配置整个进程自己的工作特性
2配置缓存工作策略(VCL配置) 被vcc process(用vcl配置转成C语言代码,用c-compiler转换成共享对象而后供各cacher process所加载使用,
varnishi守护进程运行当中,日志和统计数据会放在共享日志区域(shared memory log),想要查看日志就需要专门的日志查看工具 varnishlog varnishstat
vagent2是用来实现支持vac的varnish访问控制台,客户端工具是varnishadm **
对于varnish来讲,所谓的缓存策略,是靠vcl来实现,vcl说白了就是能够在一个请求到达以后,来去处理位置上去精选一些位置对请求做出相关处理的一些钩子(类似iptables)状态引擎
fetch在4.0以后被单独独立出来,新增了几个引擎
先看3。0中的workflow工作流
一个请求到达时无非有三种情形,
1.不可查缓存 (直接交给vcl pass,然后交给VCL_fetch,取内容之后要不要缓存,依然可以定义,经过deliver,取到数据
2.允许缓存 (是否可以命中缓存,命中就直接投递,没命中到服务器取,取完之后才投递)
3.识别不了请求 (直接到后端服务器,去response
4.0以后与服务端打交道的引擎又新增了两个
**
vcl_backend_error 响应失败该如何
vcl_backend_response 判断如何缓存,
配置语句
这些都是vcl语言,对此类配置来讲,可以对他们,做一个总结
无非几个要点
4.0的配置文件必须又一个固定的行来指明整个vcl兼容性的
所以3到4的配置跨度非常大,区别也很大
1.4.0的配置文件必须又一个固定的行来指明整个vcl兼容性的
2.//单行注释,#单行注释,/ /多上注释,表明无效配置
3.所有的子进程关于状态引擎相关的配置,叫做subroutines,必须经由sub关键字来进行申明
4.对vcl而言,不支持循环,noloops,只支持状态引擎相关的内建变量
5.每个状态引擎都必须使用return来结束,以决定下一次该跳到哪个引擎上,
6.所有配置只应用一个域
整个vcl引擎是一个有限状态机
1.每一个请求会单独处理
2.每一个请求在任何时刻都与其他请求都是彼此隔离的,互相不干扰
3.状态是有关联的,但是彼此是隔离的
4.退出一个状态代表varnish会进入下一个状态
5.内建的vcl代码默认为一直生效,你所自定义的配置是附加在这些内建之上的
对vcl来讲主要有三种语法
return指明从哪个引擎跳转到哪个引擎
vcl还有一些内建的函数和变量
regsub 正则表达式查找替换(正则表达式默认在一行中出现两次,只替换一次,要想都替换需要用G)
regsuball(这边一行匹配到几次,就全部替换)
hash_data对数据如何做哈希运算
客户端的状态引擎,
后端的状态引擎有vcl_backend_fetch,到后端取,取到以后,能否进行缓存在vcl_backend_resoponse定义,
如果取不到就在vcl_backend_error合成一个错误应答,如502
面向客户端,收到请求后判断该往哪里去,比如vcl_pass不能查缓存的,
可以查缓存,命中了 vcl_hit,未命中vcl_miss
不是正常web服务请求 vcl_pipe
如果缓存项过期 或者需要过期,人工清理 vcl_purge
缓存修剪 vcl_synth
deliver 直接向客户端发送响应报文
4.0的两个特殊引擎
lnit 初始化(类似awk 的begin)在任何请求之前执行整个vcl初始化操作,比如加载一些varnish模块
finl (类似awk end),在所有请求都结束,在vcl配置被丢弃时调用,主要清理varnish模块
现在尝试去写一段代码
obj的变量
obj.hits 此对象从缓存中命中的次数,(可以判断整个变量是几,可以给用户发送一个相关的首部)
resp响应报文,http协议首部,设定整个首部叫x-cache,把这个首部的值定义为这个字段(把一个字符串拼接成另外一个字符串)
我们之前设置的返回值是不会有任何结果的
为了效果,修改配置
这段配置只能用在把结果要发送回客户的时候,因此要在vcl中deliver中添加
先连接到varnish控制台
用load手动加载配置+配置名+配置文件名
如果有语法错误是会报错的
这个是先定义
然后再是用use来使用
现在是没命中
再访问一次试试,就命中了
这就是自己添加一个报文首部,哪个命中哪个没命中
obj.hits是一个内建变量,用于保存某缓存项的命中的次数
操作符,~模式匹配
逻辑操作,与,或,非
req. 表示由客户端发来的请求报文相关的很多属性值
代理服务器做的事情有两边,所以要面对4种通信,
1.客户端发来的请求
2.自己发请求个后端服务器
3.后端服务器响应给代理服务器
4.自己响应给客户端的报文
能改变的只有两个,自己发送给服务器的请求。自己发给客户端的响应报文*
引用客户端首部类型只要加req.http.+值
user-agent,就是保存了客户端的浏览器类型
referer,可以判断你的referer能否请求的,referer为空或者来自于自己的网站都可以请求,但是来自于别人的就不行
对应varnish而言模式匹配有点诡异(?!表示不匹配不区分)?是一个引导的标记位,并放在一个小括号里,来判定对于模式匹配时要不要区分大小写
如果期望用户的浏览器类型不能看到命令,curl的这种字符串,就可以去判定req.http.user_agent是什么,万一符合条件的话,就可以拒绝掉,让它不能查缓存也可以
第二类叫bereq,由代理服务器自己发给后端服务器的请求报文,可以自己加首部
bereq.http.额外set一个首部
berseq,后端服务器发送的响应报文,这个由后端服务器响应给varnish的响应报文
也可以引用任何首部
beresp.http.*
resp是varnish自己响应给客户端的
resp.http.*
缓存中的项的信息
请求类的包含客户端发来的请求,以及代理服务器发送的请求
这边写在一块了 be去掉就变成req了
bereq.request:请求方法 客户端 发来时 请求方法
bereq.url:请求的url
bereq.proto : 请求的协议版本
bereq.backend 指明要调用 后端主机
响应部分也是一样的
obj开头的有两个
这些变量和应用位置是有规定的,各类变量有使用位置
req开头的是请求相关的,基本在每个状态引擎中都可以使用(R/W表示能读能修改)
bereq开头 varnishi发送给后端服务器的,因此fetch pass,miss,pipe可以用,其他不行
beresp 后端发送的响应 报文,发送给fetch
resp,是服务器发送给客户端的,因此只能在deliver上使用
obj obj。hit就只能读,不能随便修改,因为是自己计数的
但是obj.ttl值就可以修改,缓存两小时,或者两年,响应时长都是可以修改的
域限制变量,受制于被限制的域当中的报文走到哪个阶段,跟阶段有关系
假如有些内容就不希望查缓存
到pass,就直接去后端服务器上去取,不会查,缓存
在后端主机上先创建一个目录
现在去访问,第一次访问不会命中,第二次以进HIT了
现在不要查询缓存如何应用
在这两个环节做
如果能匹配到就不去查询缓存
(?i)不区分大小写
来重新尝试编译一下
现在调用
现在访问主页,就可以命中缓存
如果你的请求方法是PRI(http2.0专有的方法,回复405,不支持该方法)
synth是内建函数,合成一个错误响应报文
现在想对curl命令不做回应时
再来定义一次vcl
现在就告诉客户端405了
也可以改成403
重新装载一次
再去访问,就是403
**域链接了很多条件
如果你的请求方法不是GET,HEAD,PUT等
就非标准方法,不能清楚是否要查缓存
,就只能交给pipe了
**
不是get和head就返回给pass,就是只对get和head方法进行查询缓存
即便是你用的get和head方法也不能去查询缓存
如果请求报文中,有 authrization ,请输入用户名密码之类的
就不查询缓存
如果后端服务器发来的cache-control的值不匹配 s-maxage(maxage是控制公共缓存时长)如果没有这一项,
而且用户请求的内容是图片类型或者css类型,意思这些非私有信息,么有落实maxage
强制如果给客户端设cookie值的话,就取消
并强制这个资源set beresp.ttl为3600s,缓存一小时
现在可以尝试访问了
现在还检查不出来效果
对于特定类型的资源,公开的的图片等,可以取消私有标识,来定义缓存时间的
对于后端服务器来讲,始终希望收到真正的客户端地址(nginx是加x-forward-to)
varnishi,也有类似,如果这个请求不是被重启的(restart=0,代表新情求,而不是重启的,或者因为各种设置而重启的),加这个因为避免x-forward,改很多次
如果请求报文req.http-xfowarded-for(数值型)非0为真,0为假
如果对应的这个变量有值,自己原来的值,或者加上,隔开,用真正客户端的地址
如果没有值,就直接=客户端ip
这段信息应该放在req
设置后端服务器的值应该是bereq
如果有值就在值后面加客户端地址
有错误
在backend_fetch是不能使用client up
那就只能放在receive当中
为了能看出效果,来改一下日志格式
刷新一下
没有生成传不过来
使用curl访问一下
记录两次,说明请求被重启,所以要加个判断,不要让请求重启
再次访问
现在看一下默认配置有哪些
当请求到达hash的时候,hash中有一个默认配置,把请求的rul
做哈希计算,如果请求报文首部有host(哈希值就把主机哈希进来)
否则就哈希server.ip
return hash
如果host是否存在,就把它的值也当做哈希中的内容
很显然就是用户请求如果主机相同,才能命中同一个键,如果不一样 ,就不能命中,出现多个ip指向一个域名的就有问题了host的值,可以让不同主机的值里面交叉命中
否则hash serverip=varnish自己的ip地址
缓存中的缓存项的ttl值是大于0的,直接把拿缓存响应就可以了
否则缓存就没命中(虽然键有,但是缓存没命中)
如果obj的ttl缓存时长+可以grace容忍的时间(缓存宽限的时间,就算是现在已经小于0秒但还没有超过一分钟)大于0秒
如果在宽限期内也是可以命中缓存的
把命中不了的缓存项命中了,把去掉的变成没去掉
把一些可缓存的,把私有信息删除
手动修剪缓存项,要加入指令才可以