前言
这篇博客主要讲解关于varnish的基础应用。
Varnish是一款高性能的开源HTTP加速器,据传挪威最大的在线报纸 Verdens Gang 使用3台
Varnish代替了原来的12台Squid,性能比以前更好。varnish缓存已经成为了一种趋势。
但是因为varnish实在是更新换代太快了,而且每一代之间都有30%左右的不同,可以说网络上
都不能找到什么特别贴切有用的文档。
现在最新的版本已经是2017-09-15 出的Varnish 5.2.0版本了,
但是,在生产中,绝大部分还是使用的4版本,我这里也是使用的4版本来学习的。
原理
对了,现在7上epel源里面自带的是4.0.4版本
6上epel源里面自带的是2.1.5的版本,实在是太老的版本,建议使用时编译安装。
程序的运行具有局部性特征:
时间局部性:一个数据被访问过之后,可能很快会被再次访问到;
空间局部性:一个数据被访问时,其周边的数据也有可能被访问到。
cache:命中
热区:局部性;
时效性:
缓存空间耗尽:LRU,最近最少使用的;
过期:缓存清理
缓存命中率:hit/(hit+miss)
页面命中率:基于页面数量进行衡量
字节命中率:基于页面的体积进行衡量
缓存与否:建议只缓存共有数据就好,私有数据不建议缓存。
私有数据:private,private cache;
公共数据:public, public or private cache;
条件式请求:
Last-Modified/If-Modified-Since:基于文件的修改时间戳来判别;
Etag/If-None-Match:基于文件的校验码来判别;
Expires:Thu, 13 Aug 2026 02:05:12 GMT
Cache-Control:max-age=315360000
ETag:"1ec5-502264e2ae4c0"
Last-Modified:Wed, 03 Sep 2014 10:00:27 GMT
缓存层级:
私有缓存:用户代理附带的本地缓存机制;
公共缓存:反向代理服务器的缓存功能;
接收请求 -> 解析请求 -> 查询缓存 -> 新鲜度检测 -> 创建响应报文 -> 发送响应 -> 写入日志
请求报文用于通知缓存服务如何使用缓存响应请求:
cache-request-directive =
"no-cache",
"no-store"
"max-age" "=" delta-seconds
"max-stale" [ "=" delta-seconds ]
"min-fresh" "=" delta-seconds
"no-transform"
"only-if-cached"
cache-extension
响应报文用于通知缓存服务器如何存储上级服务器响应的内容:
cache-response-directive =
"public"
"private" [ "=" <"> 1#field-name <"> ]
"no-cache" [ "=" <"> 1#field-name <"> ],可缓存,但响应给客户端之前需revalidation,即必须发出条件式请求进行缓存有效性验正;
"no-store" ,不允许存储响应内容于缓存中;
"no-transform"
"must-revalidate"
"proxy-revalidate"
"max-age" "=" delta-seconds
"s-maxage" "=" delta-seconds
cache-extension
新鲜度检测机制:
过期时间检测
HTTP/1.0 Expires : expires:Mon, 06 Nov 2017 12:28:49 GMT
HTTP/1.1 Cache-Control : max-age=600
有效性再验证
1、文件修改时间是否发送改变
2、文件内容etag 标签校验
如果原始内容未改变,则仅响应首部(不附带body部分),响应码304(Not Modified)
如果原始内容发生改变,则正常响应,响应码200
如果原始内容消失,则响应404,此时缓存中的cache object也应该被删除
代理式缓存:
varnish
squid
旁挂式缓存:
memcached
varnish结构
程序架构:
Manager进程
Cacher进程,包含多种类型的线程:
accept, worker, expiry, ...
shared memory log:
统计数据:计数器;
日志区域:日志记录;
varnishlog, varnishncsa, varnishstat...
Varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)。
management : 编译VCL并应用新配置、监控varnish、初始化varnish、CLI接口
Command line 命令行管理工具
Child process mgmt 子进程管理
initialisation 初始化
child/cache
Commad line 线程 : 管理接口
Storage/hashing 线程 :缓存存储
Log/stats 线程:日志管理线程
Backend Communication 线程:管理后端主机线程
Accept : 接受新的连接请求
worker threads : 处理用户请求,child进程会为每个会话启动一个worker线程
Object Expiry : 清理缓存中的过期对象
vcl : varnish configuration language,基于”域” 的编程语言,花括号{}括起来,
配置接口:VCL
Varnish Configuration Language,
vcl complier --> c complier --> shared object
配置与参数
varnish的程序环境:
/etc/varnish/varnish.params: 配置varnish服务进程的工作特性,例如监听的地址和端口,缓存机制;
/etc/varnish/default.vcl:配置各Child/Cache线程的缓存策略;
主程序:
/usr/sbin/varnishd
CLI interface:
/usr/bin/varnishadm
Shared Memory Log交互工具:
/usr/bin/varnishhist
/usr/bin/varnishlog
/usr/bin/varnishncsa
/usr/bin/varnishstat
/usr/bin/varnishtop
测试工具程序:
/usr/bin/varnishtest
VCL配置文件重载程序:
/usr/sbin/varnish_reload_vcl
Systemd Unit File:
/usr/lib/systemd/system/varnish.service
varnish服务
/usr/lib/systemd/system/varnishlog.service
/usr/lib/systemd/system/varnishncsa.service
日志持久的服务;
varnish的缓存存储机制( Storage Types):
-s [name=]type[,options]
· malloc[,size]
内存存储,[,size]用于定义空间大小;重启后所有缓存项失效;
· file[,path[,size[,granularity]]]
磁盘文件存储,黑盒;重启后所有缓存项失效;
· persistent,path,size
文件存储,黑盒;重启后所有缓存项有效;实验;
varnish程序的选项:
程序选项:/etc/varnish/varnish.params文件
-a address[:port][,address[:port][...],默认为6081端口;
-T address[:port],默认为6082端口;
-s [name=]type[,options],定义缓存存储机制;
-u user
-g group
-f config:VCL配置文件;
-F:运行于前台;
...
运行时参数:/etc/varnish/varnish.params文件, DEAMON_OPTS
DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
-p param=value:设定运行参数及其值; 可重复使用多次;
-r param[,param...]: 设定指定的参数为只读
重载vcl配置文件
~ ]# varnish_reload_vcl
命令行工具varnishadm
[ root@YGL ~ ]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
VCL
Varnish Configuration Language (VCL)是varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等。使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义。
VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成。
vcl状态引擎
在varnish里面同iptables里面的四表五链一样,可以配置什么文件缓存,什么文件不缓存等等,在vcl里面这里的钩子我们称为状态引擎
VCL函数
函数 作用
- vcl_recv 用户请求成功接收后,遇到的第一个函数,可以在这里对请求的数据进行处理,并决定选取下一步的处理策略
- vcl_fetch 从后端主机获取内容,并判断是否缓冲此内容,然后发送给客户端
- vcl_hash 对URL进行hash,可以自定义hash键
- vcl_pass 将请求直接发给backend,而不是用缓存中的数据
- vcl_hit 在缓存中找到缓存对象时,要执行的操作
- vcl_miss 在缓存中未找到对象时,要执行的操作
- vcl_deliver 响应给客户端时调用此方法
- vcl_pipe 不经由varnish直接将请求发往后端主机的时候调用,请求和内容不做任何改变,如同为客户端和backend建立一个管道
- vcl_error 在varnishi上合成错误响应页时,调用此函数
这些函数类似或就是回调函数,是Vanish调用用户逻辑的接口。
内置变量
请求到达时可以使用的变量
req.url
req.http
req.http.header
req.restart
server.ip
server.hostname
server.port
req.backend
请求发往后端主机时可以使用的变量
bereq.url
bereq.http
bereq.http.header
bereq.proto
bereq.connect_timeout
缓存对象进入cache后可用的变量
obj.response
obj.status
obj.http.header
obj.proto
obj.ttl
obj.hits
后端主机响应的内容可用的变量
beresp.response
beresp.http.header
beresp.ttl
beresp.proto
beresp.do_gzip
beresp.do_gunzip
beresp.backend.name
beresp.backend.ip
响应客户端可以使用的变量
resp.response
resp.proto
resp.status
resp.http.header
varnish
配置varnish的三种应用
1、varnishd应用程序的命令行参数
监听的socket,使用的存储类型等等
-p param=value
-r param,param... 设定只读参数列表
/etc/varnish/varnish.params
2、-p 选项指定的参数
运行时参数:可在程序运行中,通过其CLI进行配置
3、vcl
配置缓存系统的缓存机制
通过vcl配置文件进行配置,先编译,后应用,依赖于c编译器
设定后端主机backend
修改default.vcl配置文件,指明backend,
backend default { # 为后台backend起一个名称
.host = "172.18.56.52"; # 设定后台backend主机地址
.port = "80"; # 设定后台backend主机端口
}
设定使用多个后端主机
backend default {
.host = "172.18.56.50";
.port = "80";
}
backend webimg {
.host = "172.18.56.51";
.port = "80";
}
# 设定两个backend后端主机,如果是php文件指定到一台服务器,如果是其他文件指定到默认服务器
sub vcl_recv {
if (req.url ~ "(?i)\.php$"){
set req.backend_hint = webimg;
}else{
set req.backend_hint = default;
}
}
varnish负载均衡
使用前需要导入 import directors;
varnish module
sub vcl_init{
new GROUP_NAME = directors.round_robin();
GROUP_NAME.add_backend(srv1);
GROUP_NAME.add_backend(srv2);
}
sub vcl_recv {
set req.backend.hint = GROUP_NAME.backend();
}
基于cookie的session sticky:
sub vcl_init {
new h = directors.hash();
h.add_backend(one, 1); // backend 'one' with weight '1'
h.add_backend(two, 1); // backend 'two' with weight '1'
}
sub vcl_recv {
// pick a backend based on the cookie header of the client
set req.backend_hint = h.backend(req.http.cookie);
}
后端服务器状态监测
BE Health Check:
backend BE_NAME {
.host =
.port =
.probe = {
.url=
.timeout=
.interval=
.window=
.threshold=
}
}
.probe:定义健康状态检测方法;
.url:检测时要请求的URL,默认为”/";
.request:发出的具体请求;
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close"
.window:基于最近的多少次检查来判断其健康状态;
.threshold:最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的;
.interval:检测频度;
.timeout:超时时长;
.expected_response:期望的响应码,默认为200;
健康状态检测的配置方式:
示例:
probe check {
.url = "/.healthcheck.html";
.window = 5;
.threshold = 4;
.interval = 2s;
.timeout = 1s;
}
backend default {
.host = "10.1.0.68";
.port = "80";
.probe = check;
}
backend appsrv {
.host = "10.1.0.69";
.port = "80";
.probe = check;
}
手动设定BE主机的状态:
sick:管理down;
healthy:管理up;
auto:probe auto;
设置后端的主机属性:
backend BE_NAME {
...
.connect_timeout = 0.5s;
.first_byte_timeout = 20s;
.between_bytes_timeout = 5s;
.max_connections = 50;
}
varnish的运行时参数:
线程模型:
cache-worker
cache-main
ban lurker
acceptor:
epoll/kqueue:
...
varnish.params
[ root@YGL /etc/varnish ]# cat varnish.params
# Varnish environment configuration description. This was derived from
# the old style sysconfig/defaults settings
# Set this to 1 to make systemd reload try to switch VCL without restart.
RELOAD_VCL=1
# Main configuration file. You probably want to change it.
VARNISH_VCL_CONF=/etc/varnish/default.vcl
# Default address and port to bind to. Blank address means all IPv4
# and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted
# quad, or an IPv6 address in brackets.
# VARNISH_LISTEN_ADDRESS=192.168.1.5
VARNISH_LISTEN_PORT=6081
# Admin interface listen address and port
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
# Shared secret file for admin interface
VARNISH_SECRET_FILE=/etc/varnish/secret
# Backend storage specification, see Storage Types in the varnishd(5)
# man page for details.
VARNISH_STORAGE="malloc,256M"
# User and group for the varnishd worker processes
VARNISH_USER=varnish
VARNISH_GROUP=varnish
# Other options, see the man page varnishd(1)
#DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
varnish日志
shared memory log
计数器
日志信息
1、varnishstat - Varnish Cache statistics
-1
-1 -f FILED_NAME
-1:可用于-f选项指定的字段名称列表;
MAIN.cache_hit
MAIN.cache_miss
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
显示指定参数的当前统计数据;
# varnishstat -l -f MAIN -f MEMPOOL
列出指定配置段的每个参数的意义;
2、varnishtop - Varnish log entry ranking
-1 Instead of a continously updated display, print the statistics once and exit.
-i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;
-I <[taglist:]regex>
-x taglist:排除列表
-X <[taglist:]regex>
3、varnishlog - Display Varnish logs
4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format
最后
由于现阶段学习实在是过于繁重,没有太多的时间去细细的写博客,
只能写一些基础入门的东西,博客写的十分的粗糙。
等以后闲下来了,一定把这些东西都细细的来整理一遍。
嗯,vainish是一个非常强大的代理式缓存器,他取代squid的趋势基本已成定局。