web缓存varnish(第36天)
pass
web缓存
程序具有局部性:
时间局部性
空间局部性
程序的局部性才让缓存发挥威力
缓存一般是key-value:
key: 访问路径,URL, hash
value:web content
一般缓存热点数据,经济效益高。
缓存的命中率:hit/(hit+miss)
文档命中率:从文档个数进行衡量;
字节命中率:从内容大小进行衡量;
注意:
缓存对象:生命周期;定期清理;
缓存空间耗尽:LRU(最近最少使用的缓存清理掉,腾出空间)
可缓存,不可缓存(用户私有数据)
缓存处理的步骤:
接收请求 --> 解析请求 (提取请求的URL及各种首部)--> 查询缓存 --> 新鲜度检测 --> 创建响应报文 --> 发送响应 --> 记录日志
缓存的新鲜度检测机制有如下:
1:过期日期:
HTTP/1.0 Expires
Expires:Thu, 04 Jun 2015 23:38:18 GMT
HTTP/1.1 Cache-Control: max-age 缓存网页最大的存活时间600秒
Cache-Control:max-age=600
2:服务器的原始内容的有效性再验正:revalidate
如果服务器的原始内容未改变,则仅响应首部(不附带body部分),响应码304 (Not Modified)
如果服务器的原始内容发生改变,则正常响应,响应码200;
如果服务器的原始内容消失,则响应404,此时缓存中的cache object也应该被删除;
3:条件式请求首部:
If-Modified-Since: 基于请求内容的时间戳作验正;
If-Unmodified-Since 自从某个时间之后是否有修改
If-Match: 是否匹配,每个页面生成Etag,如果Etag改变,则内容修改过
If-None-Match: 是否未匹配
Etag: faiy89345
条件是请求首部最常用的 If-Modified-Since和If-None-Match。
Age首部:当代理服务器用自己缓存的实体取响应请求时候,用该头部表明该实体从产生到现在经过多长时间了
Cache-Control = "Cache-Control" ":" 1#cache-directive
cache-directive = cache-request-directive
| cache-response-directive
cache-request-directive = 请求
"no-cache" 不要用缓存响应我,去web服务器 取数据
| "no-store" (backup)
| "max-age" "=" delta-seconds 只接受age值小于max-age值,且没有过期的对象
| "max-stale" [ "=" delta-seconds ] 告诉服务器可以接受过期缓存,但是过期时间必须小于max-stale
| "min-fresh" "=" delta-seconds
| "no-transform"
| "only-if-cached"
| cache-extension
cache-response-directive = 响应
"public" 可以响应给任何用户
| "private" [ "=" <"> 1#field-name <"> ] 只能用该缓存响应先前请求该内容的那个用户
| "no-cache" [ "=" <"> 1#field-name <"> ] 这表示告诉客户端可以缓存,但是必须跟服务器验证了其有效后,才能返回给客户端
| "no-store" 告诉客户端不要缓存
| "no-transform"
| "must-revalidate"
| "proxy-revalidate"
| "max-age" "=" delta-seconds
| "s-maxage" "=" delta-seconds
| cache-extension
常见的缓存服务开源解决方案:
varnish, squid (类似nginx --> apache)
nginx和apache也有缓存功能
varnish, squid都有反向代理功能,但是主要功能是缓存
站点: https://www.varnish-cache.org
varnish引用DSL语言,也就是vcl(varnish configuration language),C语言风格。
varnish架构:
如图所示:
varnish的管理进程:编译VCL并应用新配置;监控vanish;初始化varnish;CLI接口;
varnish的Child/cache提供的功能如下:
Acceptor:接收新的连接请求;
worker threads:处理用户请求;
Expiry:清理缓存中的过期对象;
varnish的日志:Shared Memory Log,共享内存日志大小默认一般为90MB,分为两部分,前一部分为计数器,后一部分请求相关的数据;
vcl: Varnish Configuration Language
缓存策略配置接口;
基于“域”的简单编程语言;
varnish的安装:
yum install varnish =y
内存分配和回收:
malloc(), free() 性能不高,varnish使用jmalloc
yum info jmalloc
varnish如何存储缓存对象:
file: 单个文件;不支持持久机制;重启就失效
malloc: 内存;内存4K,4M,缓存对象缓存在内存中
persistent:基于文件的持久存储;
硬件直接上PCI-e接口固态
varnish监听6081端口和6082端口,6081端口提供服务(可改为80端口),6082端口是管理接口
配置varnish的三种应用:
1、varnishd应用程序的命令行参数;
监听的socket, 使用的存储类型等等;额外的配置参数;
-p param=value 设定参数=值
-r param,param,... : 设定只读参数列表;
/etc/varnish/varnish.params
2、-p选项指明的参数,也就是运行时参数,配置Child/Cache进程:
也可在程序运行中,通过其CLI进行配置;varnishadm 登录后设置
3、vcl:配置缓存系统的缓存机制;
通过vcl配置文件进行配置;/etc/varnish/default.vcl
先编译,后应用;依赖于c编译器;
varnish命令行工具:
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 管理命令varnishadm
Log:日志工具命令有如下2个
varnishlog
varnishncsa
Statistics 查看varnish状态
varnishstat
Top:排序
varnishtop
vcl:
vcl内部有多个state engine:各引擎之间存一定程度上的相关性;前一个engine如果可以有多种下游engine,则上游engine需要用return指明要转移的下游engine;
vcl_recv
vcl_hash
vcl_hit
vcl_miss
vcl_fetch
vcl_deliver
vcl_pipe
vcl_pass
vcl_error
vcl编程语言语法:
(1) //, #, /* */ 用于注释;会被编译器忽略;
(2) sub $name: 用于定义子例程;
sub vcl_recv {
}
(3) 不支持循环;
(4) 有众多内置的变量,变量的可调用位置与state engine有密切相关性;
(5) 支持终止语句,return(action) 表示到action中去 ,没有返回值;
(6) "域"专用;
(7) 操作符:=, ==, ~, !, &&, ||
条件判断语句:
if (CONDTION) {
} else {
}
变量赋值:
set name=value 设置变量
unset name 取消变量
req.http.HEADER:调用request报文中http协议的指定的HEADER首部;例子如下:
req.http.X-Forwarded-For
req.http.Auhtorization
req.http.cookie
req.request 表示请求方法,也就是get,post,head,put,delete等
client.ip 表示客户端IP;
vcl_recv引擎的工作原理如下:
vcl_hash原理:
vcl_fetch引擎原理:
state engine workflow(v3)有如下几种情况:
vcl_recv --> vcl_hash --> vcl_hit --> vcl_deliver
vcl_recv --> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver
vcl_recv --> vcl_pass --> vcl_fetch --> vcl_deliver
vcl_recv --> vcl_pipe
state engine workflow(v4)
vcl_recv
vcl_pass
vcl_pipe
vcl_hash
vcl_hit
vcl_miss
vcl_backend_fetch
vcl_backend_response
vcl_backend_error
vcl_purge
vcl_synth
sub vcl_recv {
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
定义在.vcl文件中的sub vcl_deliver中,向响应给客户端的报文添加一个自定义首部X-Cache;
if (obj.hits>0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cahce = "MISS";
}
varnish中的内置变量:
变量种类:
client 客户端
server varnish自身
req 客户端请求
resp
bereq varnish向后端发送的请求
beresp 后端发送的响应
obj
storage
bereq
bereq.http.HEADERS: 由varnish发往backend server的请求报文的指定首部;
bereq.request:请求方法;
bereq.url:
bereq.proto:
bereq.backend:指明要调用的后端主机;
beresp (backend server response)
beresp.proto
beresp.status:后端服务器的响应的状态码
beresp.reason:原因短语;
beresp.backend.ip
beresp.backend.name
beresp.http.HEADER: 从backend server响应的报文的首部;
beresp.ttl:后端服务器响应的内容的余下的生存时长;
obj
obj.ttl: 对象的ttl值;
obj.hits:此对象从缓存中被命中的次数;
server
server.ip
server.hostname
官方文档:https://www.varnish-cache.org/docs/
使varnish支持虚拟主机:
if (req.http.host == "www.magedu.com") {
}
强制对某资源的请求,不检查缓存;
/admin
/login
if (req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {
return(pass);
} //表示/admin和/login目录下的资源的访问不缓存
对特定类型的资源取消其私有的cookie标识,并强行设定其可以varnish缓存的时长:
vcl_backend_response
if (beresp.http.cache-control !~ "s-maxage") {
if (bereq.url ~ "(?i)\.jpg$") { //没有设置公共缓存s-maxage,并且为jpg资源
set beresp.ttl = 3600s; //设置公共缓存时长
unset beresp.http.Set-Cookie;
}
if (bereq.url ~ "(?i)\.css$") {
set beresp.ttl = 600s;
unset beresp.http.Set-Cookie;
}
}
官方配置示例:https://www.varnish-cache.org/trac/wiki/VCLExamples
backend server的定义:
backend name {
.attribute = "value";
}
.host: BE主机(后端主机)的IP;
.port:BE主机监听的PORT;
.probe: 对BE做健康状态检测;
.max_connections:并连接最大数量;
后端主机的健康状态检测方式:
probe name {
.attribute = "value";
}
.url: 判定BE健康与否要请求的url;
.expected_response:期望响应状态码;默认为200;
示例1:
backend websrv1 {
.host = "172.16.100.68";
.port = "80";
.probe = {
.url = "/test1.html";
}
}
backend websrv2 {
.host = "172.16.100.69";
.port = "80";
.probe = {
.url = "/test1.html";
}
}
sub vcl_recv {
if (req.url ~ "(?i)\.(jpg|png|gif)$") {
set req.backend_hint = websrv1;
} else {
set req.backend_hint = websrv2;
}
}
示例2:负载均衡
import directors;
sub vcl_init {
new mycluster = directors.round_robin();
mycluster.add_backend(websrv1);
mycluster.add_backend(websrv2);
}
sub vcl_recv {
set req.backend_hint = mycluster.backend();
}
负载均衡算法:
fallback, random, round_robin, hash
掌握:varnishlog, varnishncsa, varnishtop, varnishstat的用法
web缓存
程序具有局部性:
时间局部性
空间局部性
程序的局部性才让缓存发挥威力
缓存一般是key-value:
key: 访问路径,URL, hash
value:web content
一般缓存热点数据,经济效益高。
缓存的命中率:hit/(hit+miss)
文档命中率:从文档个数进行衡量;
字节命中率:从内容大小进行衡量;
注意:
缓存对象:生命周期;定期清理;
缓存空间耗尽:LRU(最近最少使用的缓存清理掉,腾出空间)
可缓存,不可缓存(用户私有数据)
缓存处理的步骤:
接收请求 --> 解析请求 (提取请求的URL及各种首部)--> 查询缓存 --> 新鲜度检测 --> 创建响应报文 --> 发送响应 --> 记录日志
缓存的新鲜度检测机制有如下:
1:过期日期:
HTTP/1.0 Expires
Expires:Thu, 04 Jun 2015 23:38:18 GMT
HTTP/1.1 Cache-Control: max-age 缓存网页最大的存活时间600秒
Cache-Control:max-age=600
2:服务器的原始内容的有效性再验正:revalidate
如果服务器的原始内容未改变,则仅响应首部(不附带body部分),响应码304 (Not Modified)
如果服务器的原始内容发生改变,则正常响应,响应码200;
如果服务器的原始内容消失,则响应404,此时缓存中的cache object也应该被删除;
3:条件式请求首部:
If-Modified-Since: 基于请求内容的时间戳作验正;
If-Unmodified-Since 自从某个时间之后是否有修改
If-Match: 是否匹配,每个页面生成Etag,如果Etag改变,则内容修改过
If-None-Match: 是否未匹配
Etag: faiy89345
条件是请求首部最常用的 If-Modified-Since和If-None-Match。
Age首部:当代理服务器用自己缓存的实体取响应请求时候,用该头部表明该实体从产生到现在经过多长时间了
Cache-Control = "Cache-Control" ":" 1#cache-directive
cache-directive = cache-request-directive
| cache-response-directive
cache-request-directive = 请求
"no-cache" 不要用缓存响应我,去web服务器 取数据
| "no-store" (backup)
| "max-age" "=" delta-seconds 只接受age值小于max-age值,且没有过期的对象
| "max-stale" [ "=" delta-seconds ] 告诉服务器可以接受过期缓存,但是过期时间必须小于max-stale
| "min-fresh" "=" delta-seconds
| "no-transform"
| "only-if-cached"
| cache-extension
cache-response-directive = 响应
"public" 可以响应给任何用户
| "private" [ "=" <"> 1#field-name <"> ] 只能用该缓存响应先前请求该内容的那个用户
| "no-cache" [ "=" <"> 1#field-name <"> ] 这表示告诉客户端可以缓存,但是必须跟服务器验证了其有效后,才能返回给客户端
| "no-store" 告诉客户端不要缓存
| "no-transform"
| "must-revalidate"
| "proxy-revalidate"
| "max-age" "=" delta-seconds
| "s-maxage" "=" delta-seconds
| cache-extension
常见的缓存服务开源解决方案:
varnish, squid (类似nginx --> apache)
nginx和apache也有缓存功能
varnish, squid都有反向代理功能,但是主要功能是缓存
站点: https://www.varnish-cache.org
varnish引用DSL语言,也就是vcl(varnish configuration language),C语言风格。
varnish架构:
如图所示:
varnish的管理进程:编译VCL并应用新配置;监控vanish;初始化varnish;CLI接口;
varnish的Child/cache提供的功能如下:
Acceptor:接收新的连接请求;
worker threads:处理用户请求;
Expiry:清理缓存中的过期对象;
varnish的日志:Shared Memory Log,共享内存日志大小默认一般为90MB,分为两部分,前一部分为计数器,后一部分请求相关的数据;
vcl: Varnish Configuration Language
缓存策略配置接口;
基于“域”的简单编程语言;
varnish的安装:
yum install varnish =y
内存分配和回收:
malloc(), free() 性能不高,varnish使用jmalloc
yum info jmalloc
varnish如何存储缓存对象:
file: 单个文件;不支持持久机制;重启就失效
malloc: 内存;内存4K,4M,缓存对象缓存在内存中
persistent:基于文件的持久存储;
硬件直接上PCI-e接口固态
varnish监听6081端口和6082端口,6081端口提供服务(可改为80端口),6082端口是管理接口
配置varnish的三种应用:
1、varnishd应用程序的命令行参数;
监听的socket, 使用的存储类型等等;额外的配置参数;
-p param=value 设定参数=值
-r param,param,... : 设定只读参数列表;
/etc/varnish/varnish.params
2、-p选项指明的参数,也就是运行时参数,配置Child/Cache进程:
也可在程序运行中,通过其CLI进行配置;varnishadm 登录后设置
3、vcl:配置缓存系统的缓存机制;
通过vcl配置文件进行配置;/etc/varnish/default.vcl
先编译,后应用;依赖于c编译器;
varnish命令行工具:
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 管理命令varnishadm
Log:日志工具命令有如下2个
varnishlog
varnishncsa
Statistics 查看varnish状态
varnishstat
Top:排序
varnishtop
vcl:
vcl内部有多个state engine:各引擎之间存一定程度上的相关性;前一个engine如果可以有多种下游engine,则上游engine需要用return指明要转移的下游engine;
vcl_recv
vcl_hash
vcl_hit
vcl_miss
vcl_fetch
vcl_deliver
vcl_pipe
vcl_pass
vcl_error
vcl编程语言语法:
(1) //, #, /* */ 用于注释;会被编译器忽略;
(2) sub $name: 用于定义子例程;
sub vcl_recv {
}
(3) 不支持循环;
(4) 有众多内置的变量,变量的可调用位置与state engine有密切相关性;
(5) 支持终止语句,return(action) 表示到action中去 ,没有返回值;
(6) "域"专用;
(7) 操作符:=, ==, ~, !, &&, ||
条件判断语句:
if (CONDTION) {
} else {
}
变量赋值:
set name=value 设置变量
unset name 取消变量
req.http.HEADER:调用request报文中http协议的指定的HEADER首部;例子如下:
req.http.X-Forwarded-For
req.http.Auhtorization
req.http.cookie
req.request 表示请求方法,也就是get,post,head,put,delete等
client.ip 表示客户端IP;
vcl_recv引擎的工作原理如下:
vcl_hash原理:
vcl_fetch引擎原理:
state engine workflow(v3)有如下几种情况:
vcl_recv --> vcl_hash --> vcl_hit --> vcl_deliver
vcl_recv --> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver
vcl_recv --> vcl_pass --> vcl_fetch --> vcl_deliver
vcl_recv --> vcl_pipe
state engine workflow(v4)
vcl_recv
vcl_pass
vcl_pipe
vcl_hash
vcl_hit
vcl_miss
vcl_backend_fetch
vcl_backend_response
vcl_backend_error
vcl_purge
vcl_synth
sub vcl_recv {
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
定义在.vcl文件中的sub vcl_deliver中,向响应给客户端的报文添加一个自定义首部X-Cache;
if (obj.hits>0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cahce = "MISS";
}
varnish中的内置变量:
变量种类:
client 客户端
server varnish自身
req 客户端请求
resp
bereq varnish向后端发送的请求
beresp 后端发送的响应
obj
storage
bereq
bereq.http.HEADERS: 由varnish发往backend server的请求报文的指定首部;
bereq.request:请求方法;
bereq.url:
bereq.proto:
bereq.backend:指明要调用的后端主机;
beresp (backend server response)
beresp.proto
beresp.status:后端服务器的响应的状态码
beresp.reason:原因短语;
beresp.backend.ip
beresp.backend.name
beresp.http.HEADER: 从backend server响应的报文的首部;
beresp.ttl:后端服务器响应的内容的余下的生存时长;
obj
obj.ttl: 对象的ttl值;
obj.hits:此对象从缓存中被命中的次数;
server
server.ip
server.hostname
官方文档:https://www.varnish-cache.org/docs/
使varnish支持虚拟主机:
if (req.http.host == "www.magedu.com") {
}
强制对某资源的请求,不检查缓存;
/admin
/login
if (req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {
return(pass);
} //表示/admin和/login目录下的资源的访问不缓存
对特定类型的资源取消其私有的cookie标识,并强行设定其可以varnish缓存的时长:
vcl_backend_response
if (beresp.http.cache-control !~ "s-maxage") {
if (bereq.url ~ "(?i)\.jpg$") { //没有设置公共缓存s-maxage,并且为jpg资源
set beresp.ttl = 3600s; //设置公共缓存时长
unset beresp.http.Set-Cookie;
}
if (bereq.url ~ "(?i)\.css$") {
set beresp.ttl = 600s;
unset beresp.http.Set-Cookie;
}
}
官方配置示例:https://www.varnish-cache.org/trac/wiki/VCLExamples
backend server的定义:
backend name {
.attribute = "value";
}
.host: BE主机(后端主机)的IP;
.port:BE主机监听的PORT;
.probe: 对BE做健康状态检测;
.max_connections:并连接最大数量;
后端主机的健康状态检测方式:
probe name {
.attribute = "value";
}
.url: 判定BE健康与否要请求的url;
.expected_response:期望响应状态码;默认为200;
示例1:
backend websrv1 {
.host = "172.16.100.68";
.port = "80";
.probe = {
.url = "/test1.html";
}
}
backend websrv2 {
.host = "172.16.100.69";
.port = "80";
.probe = {
.url = "/test1.html";
}
}
sub vcl_recv {
if (req.url ~ "(?i)\.(jpg|png|gif)$") {
set req.backend_hint = websrv1;
} else {
set req.backend_hint = websrv2;
}
}
示例2:负载均衡
import directors;
sub vcl_init {
new mycluster = directors.round_robin();
mycluster.add_backend(websrv1);
mycluster.add_backend(websrv2);
}
sub vcl_recv {
set req.backend_hint = mycluster.backend();
}
负载均衡算法:
fallback, random, round_robin, hash
掌握:varnishlog, varnishncsa, varnishtop, varnishstat的用法
作业:
vcl: backend, backend的调用,健康状态检测的定义,负载均衡的实现,根据资源类型不同完成分发,控制哪些内容不查或查询缓存;
评论
发表评论