0%

缓存为王 Varnish 入门 一个高效又轻量的缓存服务器

关于 Varnish 系列其他文章的传送门

  1. 《 缓存为王 Varnish 入门 一个高效又轻量的缓存服务器 》     您当前所在位置

  2. 《 Varnish 缓存双活 构建高可用架构之路 》



varnish

一、Cache is King

为什么需要缓存

Cache is King 的理念在计算机的方方面面都能得到体现,从 CPU 的 L1、L2、L3 级缓存,再到硬盘的缓存模块,就连内存其实也是为了缓存各种数据而存在。

在互联网的应用中,很多内容其实是不需要经常变化的,因此可以将这些不需要经常变动的数据生成缓存,可以有以下几点好处:

  • 可以节约大量重复计算和资源;
  • 降低延迟,提升用户体验。

king

缓存是如何实现的

一个程序的运行具有局部性特征:

  • 时间局部性:一个数据被访问过之后,可能很快会被再次访问到;
  • 空间局部性:一个数据被访问时,其周边的数据也有可能被访问到。

所以通常会在后端服务器前增加 cache 服务器,如果客户端的请求命中了 cache,缓存服务器就会直接响应给客户端。所以对热区数据做缓存的话,能大大提高响应速度,也能减轻后端服务器的压力。

缓存有时效性,缓存空间也会耗尽,会使用 LRU,遵循最近最少使用原则清理过期缓存。

缓存命中率算法:hit/(hit+miss)

  • 页面命中率:基于页面数量进行衡量;
  • 字节命中率:基于页面的体积进行衡量。

缓存有两个层级:

  • 私有缓存:用户代理附带的本地缓存机制,比如浏览器缓存;
  • 公共缓存:反向代理服务器的缓存功能,比如对热区数据的缓存。

实现缓存功能的软件

缓存软件目前有两个开源的解决方案,他们的关系就像 Apache 和 Nginx 一样:

  • squid:老牌缓存服务器,支持的功能多,但是性能差;
  • Varnish:年轻的新生力量,虽然功能和 squid 比略徐一筹,但是运行是却是丝滑般流畅;

这里主要介绍 Varnish

二、Varnish 介绍

什么是 Varnish

Varnish 是一款高性能的开源的 HTTP 加速器,挪威最大的在线报纸平台 Verdens Gang 使用 3 台 Varnish 代替了原来的 12 台 Squid,而且性能比以前更好。

diagram

Varnish 的作者 Poul-Henning Kamp 是 FreeBSD 的内核开发者之一,他认为现在的计算机比起 1975 年已经复杂许多。在 1975 年时,储存媒介只有两种:内存与硬盘。但现在计算机系统的内存除了主存外,还包括了 CPU 内的 L1、L2,甚至有 L3 缓存。硬盘上也有自己的缓存装置,因此 Squid Cache 自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,这就是 Varnish cache设计架构。
Varnish 项目在 2006 年发布第一个版本 0.9,经过 varnish 开发团队和网友们的辛苦耕耘,现在的 varnish 已经很健壮。很多门户网站已经部署了 varnish,并且反应都很好,甚至比 squid 还稳定,且效率更高,资源占用更少。相信在反向代理,web 加速方面,varnish 已经有足够能力代替squid。

Varnish 的特点

Varnish 是一个轻量级的 Cache 和反向代理软件。先进的设计理念和成熟的设计框架是 Varnish 的主要特点。现在的 Varnish 总共代码量不大,虽然功能在不断改进,但是还需要继续丰富和加强。

下面总结了 Varnish 的一些特点

  • 基于内存进行缓存,重启后数据将消失;
  • 利用虚拟内存方式,I/O 性能好;
  • 支持设置 0~60 秒内的精确缓存时间;
  • VCL 配置管理比较灵活;
  • 32 位机器上缓存文件大小为最大 2GB;
  • 具有强大的管理功能,例如 top,stat,admin,list 等;
  • 状态机设计巧妙,结构清晰;
  • 利用二叉堆管理缓存文件,达到积极删除目的。

Varnish 与 Squid 对比

说到 Varnish,不能不提 Squid,Squid 是一个高性能的代理缓存服务器,它和 Varnish 之间有诸多的异同点,下面进行分析。

下面是 Varnish 与 Squid 之间的相同点。

  • 都是一个反向代理服务器;
  • 都是开源软件。

下面是它们的不同点,也是 Varnish 的优点

  • Varnish 的稳定性很高。两者在完成相同负荷的工作时,Squid 服务器发生故障的几率要高于 Varnish,因为 Squid 需要经常重启;
  • Varnish 访问速度更快。Varnish 采用了 “Visual Page Cache” 技术,所有缓存数据都直接从内存读取,而 Squid 是从硬盘读取缓存数据,因此 Varnish 在访问速度方面会更快;
  • Varnish 可以支持更多的并发连接。因为 Varnish 的 TCP 连接释放要比 Squid 快,所以在高并发连接情况下可以支持更多 TCP 连接;
  • Varnish 可以通过管理端口,使用正则表达式批量清除部分缓存,而 Squid 做不到。

vs

当然,与传统的 Squid 相比,Varnish 也有缺点

  • Varnish 在高并发状态下 CPU、I/O 和内存等资源开销都高于 Squid;
  • Varnish 进程一旦挂起、崩溃或者重启,缓存数据都会从内存中完全释放,此时所有请求都会被发送到后端服务器,在高并发情况下,这会给后端服务器造成很大压力。

Varnish 官方站点:http://www.varnish-cache.org/

分为商业版和社区版

  • Community
  • Enterprise

三、Varnish 的安装

安装 varnish

Varnish 已经被收录在 EPEL 源中,安装 EPEL 源并使用 YUM 即可安装。

1
2
3
yum install epel-release

yum install varnish -y

程序架构

manager

Varnish 程序和 Nginx 类似分为主进程和子进程。

  • Manager 进程;
  • Child/cache 进程。

Management 进程负责:

  • 提供命令行管理工具;
  • 完成初始化;
  • 管理子进程;
  • 编译缓存的步骤;
    1. VCL 编译器读取 VCL(Varnish Configuration Language),转换成 C 语言代码;
    2. 由 C 语言编译器再转换成二进制的 Shared opject,再由 Child 进程加载成共享模块使用。

Child/cache 进程负责:

  • 提供命令行接口;
  • 把缓存构建为 HASH 格式的数据,存放到存储;
  • 记录缓存使用的日志和运行状态;
  • 接收用户请求;
  • 与后端被代理的服务器通信;
  • 处理用户请求;
  • 缓存过期管理。

Varnish 的程序环境

  • /usr/sbin/varnishd:主程序;
  • /usr/bin/varnishadm:命令行工具;
  • /usr/bin/varnishtest:测试工具程序:
  • /usr/sbin/varnish_reload_vcl:VCL 配置文件重载程序;
  • /usr/lib/systemd/system/varnish.service:Systemd Unit File;
  • /usr/lib/systemd/system/varnishlog.service:日志持久的服务;
  • /usr/lib/systemd/system/varnishncsa.service:日志持久的服务;

配置文件

  • /etc/varnish/varnish.params:配置 Varnish 服务进程的工作特性,例如监听的地址和端口,缓存机制等,通过 Systemd Unit File 加载;
  • /etc/varnish/default.vcl:配置各 Child/Cache 线程的缓存策略;

Shared Memory Log 交互工具

  • /usr/bin/varnishhist:保存日志为原始格式,日志和统计计数器等是放置在内存中的,如果想永久保存到磁盘中的工具,可使用此工具的服务;
  • /usr/bin/varnishlog:每一个请求独立显示。
  • /usr/bin/varnishncsa:保存日志为 http_combined 格式,日志和统计计数器等是放置在内存中的,如果想永久保存到磁盘中的工具,可使用此工具的服务;
  • /usr/bin/varnishstat:交互式的显示统计信息;
  • /usr/bin/varnishtop:实时显示速率日志;

Varnish 程序的选项

程序选项:从 /etc/varnish/varnish.params 文件加载。

  • -a address[:port][,address[:port][...]:设置面向 web 服务的监听网络,默认为 6081 端口;
  • -T address[:port]:设置面向客户端工具的监听网络,默认为 6082 端口;
  • -s [name=]type[,options]:定义缓存存储机制;
  • -u:user;
  • -g:group;
  • -f:config(VCL配置文件);
  • -F:运行于前台;

设定运行时参数:通过 Systemd Unit 文件中的 DEAMON_OPTS 变量引用。

示例:

1
DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
  • -p param=value:设定运行参数及其值; 可重复使用多次;
  • -r param[,param...]:设定指定的参数为只读状态;

定义后端缓存存储机制

[name=]type,[,options]:指定 varnish 的缓存存储机制( Storage Types)。

例如:

  • malloc<,size>:使用 malloc 类型,内存类存储,<size> 用于定义空间大小,重启后所有缓存项会失效。由于 malloc 是串行机制,大并发量时性能差,可以使用 jemalloc,这是一个并行的支持扩展的 malloc 的实现,默认作为依赖已安装,但没有启用。
  • file<,dir_or_file><,size><,granularity>:使用文件或目录类型,默认路径是 /tmp下,数据在黑盒中,无法直接查看,重启后所有缓存项失效。

建议

  1. 内存容易出现碎片,建议使用高性能硬盘存储,比如 SSD
  2. 缓存区大小可调整,不建议过大,最好和热区数据接近

四、Varnish 配置文件

Varnish 的配置文件有两个:

  • /etc/varnish/varnish.params:配置 Varnish 服务进程的工作特性,例如监听的地址和端口,缓存机制等;重启服务才能生效;
  • /etc/varnish/default.vcl:配置各 Child/Cache 线程的缓存策略;使用专用工具重载即可生效。

1. varnish.params 的相关参数

配置 Varnish 服务进程的工作特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 将此值设置为 1 时,使用 systemd 进行重新加载会尝试在不重启的情况下切换 VCL
RELOAD_VCL=1

// 主要的配置文件,可以变更
VARNISH_VCL_CONF=/etc/varnish/default.vcl

// 设定要绑定的默认地址和端口,空白表示所有 IPv4 和 IPv6 地址,或者指定一个主机名
## VARNISH_LISTEN_ADDRESS=192.168.1.5
VARNISH_LISTEN_PORT=6081

// 设定管理接口的监听地址和端口
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082

// 指定管理接口的密码文件
VARNISH_SECRET_FILE=/etc/varnish/secret

// 配置后端缓存存储机制,接下来有详细介绍
#VARNISH_STORAGE="malloc,256M"
VARNISH_STORAGE="file,/data/varnish/,256M"

// 设定 Varnishd 工作进程的用户和组
VARNISH_USER=varnish
VARNISH_GROUP=varnish

2. default.vcl 的相关参数

主要用于配置缓存策略,VCL 配置文件遵循 C 语言语法,必须以 ; 结尾

Varnish 的所有配置都是通过 VCL(varnish configure language) 来配置的。它是一种基于“域” (domain specific) 的简单编程语言,仅生效在特定的状态引擎(state engine)。它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用 set 自定义变量、支持 if 判断语句,也有内置的函数和变量等。使用 VCL 编写的缓存策略通常保存至 .vcl 文件中,其需要编译成二进制的格式后才能由 varnish 调用。

VCL 有多个状态引擎,状态之间存在相关性,但状态引擎彼此间互相隔离;每个状态引擎可使用 return(action) 指明关联至哪个下一级引擎;每个状态引擎对应于 vcl 文件中的一个配置段,即为 subroutine

状态引擎列表

  • 前端状态引擎
    • vcl_recv:用于接受和处理请求。当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。例如如何响应、怎么响应、使用哪个后端服务器等;
    • vcl_hash:将数据来源生成 HASH 值;
    • vcl_hit:命中缓存时要执行的操作;
    • vcl_pass:不是 GET 和 HEAD 的其他正常请求,将请求直接发往后端主机;
    • vcl_miss:没有命中缓存,直接将请求发给后端主机;
    • vcl_purge:执行缓存清理;
    • vcl_synth:用于在 Varnish 中生成内容;
    • vcl_pipe:遇到无法理解的用户请求,直接结束;
    • vcl_deliver:将用户请求的内容响应给客户端时用到的方法;
  • 后端状态引擎
    • vcl_backend_fetch:后端引擎读取首部报文;
    • vcl_backend_response:收到响应报文并判断是否缓存;
    • vcl_backend_error:接收响应报文错误;
  • 两个特殊的引擎
    • vcl_init:在接收任何处理请求之前要执行的 vcl 代码,主要用于初始化 VMODs;
    • vcl_fini:所有的请求都已经结束,Varnish 即将关闭,在 vcl 配置被丢弃时调用,主要用于清理 VMODs;

各个引擎的工作流程图

simplified_fsm

可用的变量

subroutine 中可用的变量,R/W 代表对数据是否有读/写权限。

subroutine req. bereq. beresp. obj. resp.
vcl_backend_fetch R/W
vcl_backend_response R/W R/W
vcl_backend_error R/W R/W
vcl_recv R/W
vcl_pipe R R/W
vcl_pass R/W
vcl_hash R/W
vcl_purge R/W
vcl_miss R/W
vcl_hit R/W R
vcl_deliver R/W R R/W
vcl_synth R/W R/W

常用到的变量

请求报文类bereq.*, req.*

  • bereq.http.HEADERS:可以使用各种首部信息;
  • bereq.request, req.request:请求方法;
  • bereq.url, req.url:请求的 url;
  • bereq.proto,req.proto:请求的协议版本;
  • bereq.backend:指明要调用的后端主机;
  • req.http.Cookie:客户端的请求报文中 Cookie 首部的值;
  • req.http.User-Agent:客户端浏览器信息;

响应报文类beresp.*, resp.*

  • beresp.http.HEADERS:可以使用各种首部信息;
  • beresp.status, resp.status:响应的状态码;
  • reresp.proto, resp.proto:协议版本;
  • beresp.backend.name:后端主机的主机名;
  • beresp.ttl:后端主机响应的内容的余下的可缓存时长;

缓存类obj.*

  • obj.hits:此对象从缓存中命中的次数;
  • obj.ttl:对象的 ttl 值

Varnish 自身类server.*

  • server.ip:Varnish 主机的 IP;
  • server.hostname:Varnish 主机的 Hostname;

客户端类client.*

  • client.ip:发请求至 Varnish 主机的客户端 IP;

用户自定义

  • set:定义一个变量
  • unset:引用一个变量

如果想引用 http 报文头部变量就可以写成这样

  • req.http:客户端发给代理的请求报文;
  • bereq.http:代理发给后端的请求报文;
  • beresp.http:后端发给代理的响应报文;
  • resp.http:代理发给客户端的响应报文;

3. 缓存策略自定义

默认的缓存策略如下所示:

vim /etc/varnish/default.vcl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 告诉编译器这是 4.0 版本
vcl 4.0;

// 定义默认后端服务器,指向内容服务器
backend default {
.host = "127.0.0.1";
.port = "8080";
}

// 以下是各个动作引擎的自定义区域,默认都为空
sub vcl_recv {
}

sub vcl_backend_response {
}

sub vcl_deliver {

示例 1:显示缓存与否

vcl_deliver 中定义一个动作,增加一个响应报文首部,显示当前页面是否为缓存。

  • obj.hits:是内建变量,用于保存某缓存项的从缓存中命中的次数。
  • resp.http:代理发给客户端的响应报文;
1
2
3
4
5
6
if (obj.hits>0) {   // 如果缓存命中次数如果大于 0
// varnish 就在发给客户端的响应报文中增加自定义一个首部 "X-Cache"," " 内是字符串,后边的 server.ip 是一个变量
set resp.http.X-Cache = "HIT via" + " " + server.ip;
} else {
set resp.http.X-Cache = "MISS from " + server.ip;
}

示例 2:不使用缓存

强制对某类资源的请求不检查缓存,(?i) 表示忽略大小写:

1
2
3
4
5
vcl_recv {
if (req.url ~ "(?i)^/(login|admin)") {
return(pass);
}
}

示例 3:缓存私转公

对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由 varnish 缓存的时长;

vcl_backend_response 中定义:

  • "s-maxage":公共缓存最大的可缓存时长
1
2
3
4
5
6
if (beresp.http.cache-control !~ "s-maxage") {
if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") {
unset beresp.http.Set-Cookie;
set beresp.ttl = 3600s;
}
}

示例 4:客户端 IP 传递

传递客户端的真实 IP。

vcl_recv 中定义:

1
2
3
4
5
6
7
if (req.restarts == 0) {            // 如果不是被重写的请求
if (req.http.X-Fowarded-For) { // 如果有此首部
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip; // 就重新定义这个值,在这个值后追加一个 client.ip
} else {
set req.http.X-Forwarded-For = client.ip; // 否则就重新定义为 client.ip 的值
}
}

VCL 配置重载

配置好后可使用 varnish_reload_vcl 命令重载 VCL 文件,使其生效。

1
2
3
4
5
6
7
8
9
10
11
12
-> # varnish_reload_vcl
Loading vcl from /etc/varnish/default.vcl
Current running config name is
Using new config name reload_2019-08-12T17:13:12
VCL compiled.
VCL 'reload_2019-08-12T17:13:12' now active
available 0 boot
available 0 reload_2019-08-12T17:11:13 // available 代表可用但没用的版本
available 0 reload_2019-08-12T17:13:07
active 0 reload_2019-08-12T17:13:12 // active 代表当前正在使用的版本

Done

五、管理工具 varnishadm

管理工具 varnishadm,是C/S架构。

默认连接地址 127.0.0.1:6082

可使用交互式模式(长连接),也可直接运行命令加参数(短连接)。

语法:varnishadm [-t timeout] [-S secretfile] -T [address]:port command [...]

控制相关命令

  • ping:存活性探测;
  • auth:认证;
  • baaner:显示欢迎页;
  • start:启动;
  • stop:停止;
  • stats:查看状态;

配置文件相关的命令

  • vcl.list:列出 VCL;
  • vcl.load:装载,加载并编译;
  • vcl.use:激活指定的 VCL;
  • vcl.discard:删除指定的 VCL;
  • vcl.show [-v] <configname>:查看指定的规则的详细信息;

运行时参数

注意:临时有效,写在配置文件中可永久生效

  • param.show -l:显示所有可调参数列表;
  • param.show <PARAM>:
  • param.set <PARAM> <VALUE>:

后端管理命令

  • storage.list:列出后端使用的存储;
  • backend.list:列出后端服务器,(no probe) 代表未定义健康状态检测方式。
  • ban.list:

六、在 VCL 中定义一些功能的配置示例

1. 清理过期缓存

缓存对象的修剪可以使用 purge 或 ban:

  • purge:对指定的 url 清理缓存。
  • ban:支持使用正则表达模式,对 url 匹配,并清理缓存。

使用 purge 清理方式

当请求方法是 PURGE 时,就清理缓存。

  • (1) 自定义何时执行 purge 操作。
1
2
3
4
5
6
7
sub vcl_recv {
...
if (req.method == "PURGE") { // 如果请求方法是 PURGE
return(purge); // 就调用 purge
}
...
}
  • (2) 定义执行 purge 的操作。
1
2
3
sub vcl_purge {
return (synth(200,"Purged")); // 调用 synth 清理缓存,并返回 200
}

限制指定的客户端才能执行 PURGE 操作

  • (1) 定义 acl 列表,acl 属于单独的配置段。
1
2
3
4
acl purgers {
"127.0.0.0"/8;
"10.1.0.0"/16;
}
  • (2) 何时执行 purge 操作。
1
2
3
4
5
6
7
8
9
10
sub vcl_recv {
...
if (req.method == "PURGE") {
if (!client.ip ~ purgers) { // 并判断如果客户端 IP 不是允许的,就返回 405
return(synth(405,"Purging not allowed for " + client.ip));
}
return(purge);
}
...
}
  • (3) 定义执行 purge 操作
1
2
3
sub vcl_purge {
return (synth(200,"Purged"));
}

生效后,通过 curl -X PRUGE ip:port/path 就可以 清理缓存

使用 ban 清理方式

  • (1) 使用客户端工具 varnishadm

语法:ban <field> <operator> <arg>

示例:

1
ban req.url ~ (?i)^/javascripts
  • (2) 在 vcl 配置文件中定义,使用 ban() 函数定义

示例:

如果执行 curl -X BAN http://www.ilinux.io/test1.html,就 ban req.http.host==www.ilinux.io && req.url==/test1.html

1
2
3
4
5
6
7
8
sub vcl_recv {
...
if (req.method == "BAN") {
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return(synth(200, "Ban added"));
}
...
}

2. 如何设定多个后端主机,并动静分离

  • Nginx 中使用:proxy_pass
  • Haproxy 中使用:use_backend

而在 Varnish 中,先定义多个后端:

1
2
3
4
5
6
7
8
9
backend default {
.host = "172.16.100.6";
.port = "80";
}

backend appsrv {
.host = "172.16.100.7";
.port = "80";
}

再定义匹配规则,可以实现 php 分离:

1
2
3
4
5
6
7
8
9
sub vcl_recv {
...
if (req.url ~ "(?i)\.php$") {
set req.backend_hint = appsrv;
} else {
set req.backend_hint = default;
}
...
}

3. 设置后端的主机属性

1
2
3
4
5
6
7
backend BE_NAME {
...
.connect_timeout = 0.5s; // 与后端服务器的超时时间
.first_byte_timeout = 20s; // 从后端服务区接收响应报文时,第一字节等待的超时时间
.between_bytes_timeout = 5s; // 从后端服务区接收响应报文时,每字节传输时的间隔时间,大于此值表示后端服务器状态差
.max_connections = 50; // 设置后端最大连接数
}

4. 对后端进行负载均衡+动静分离调度

Varnish 中的负载均衡通过 Director 模块实现。

import directors:使用前需要导入。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import directors;   // 加载 director 模块

backend php1 { // 定义后端提供 php 的主机
.host = 172.17.0.6;
.port = 80;
}
backend php2 {
.host = 172.17.0.7;
.port = 80;
}

backend static1 { // 定义后端提供 static 的主机
.host = 172.17.0.2;
.port = 80;
}
backend static2 {
.host = 172.17.0.3;
.port = 80;
}

sub vcl_init { // 在初始化配置段中定义组
new phpsrv = directors.round_robin(); // 定义一个名为 phpsrv 的组,使用 rr 调度算法,不支持权重
phpsrv.add_backend(php1); // 定义 phpsrv 组的后端主机
phpsrv.add_backend(php2);

new staticsrv = directors.random(); // 定义一个名为 staticsrv 的组,使用 random 调度算法,支持权重
staticsrv.add_backend(static1,2); // 定义 staticsrv 组的后端主机,并定义权重
staticsrv.add_backend(static2,10);
}

sub vcl_recv {
...
if (req.url ~ "(?i)\.php$") { // 定义如果是 .php 结尾就找 phpsrv
set req.backend_hint = phpsrv.backend();
} else { // 否则就找 staticsrv
set req.backend_hint = staticsrv.backend();
}

// 因为缓存的关系,轮询可能看不出效果,所以设置对测试页不予缓存
if (req.url ~ "(?i)(\.html|\.php)$") {
return(pass);
}
...
}

测试查看效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-> # while true; do curl 192.168.50.11/index.html; done
web111111111111111
web2222222222222222
web111111111111111
web2222222222222222
web111111111111111
web2222222222222222

-> # while true; do curl -s 192.168.50.11/index.php | head -n1; done
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok1111111111111<h1>
<h1>php.test.ok1111111111111<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>
<h1>php.test.ok2222222222222<h1>

使用 varnishadm 查看定义的后端

1
2
3
4
5
6
-> # varnishadm backend.list
Backend name Refs Admin Probe
php1(172.17.0.6,,80) 3 probe Healthy (no probe)
php2(172.17.0.7,,80) 3 probe Healthy (no probe)
static1(172.17.0.2,,80) 3 probe Healthy (no probe)
static2(172.17.0.3,,80) 3 probe Healthy (no probe)

在上一个的配置基础上,定义基于 Cookie 的 session 绑定。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sub vcl_init {      // 在初始化配置段中定义组
...
new staticsrv = directors.hash(); // 定义一个名为 staticsrv 的组,使用 HASH 绑定,支持权重
staticsrv.add_backend(static1,1); // 定义 staticsrv 组的后端主机,并定义权重
staticsrv.add_backend(static2,10);
...
}

sub vcl_recv {
...
if (req.url ~ "(?i)\.php$") {
set req.backend_hint = phpsrv.backend(req.http.cookie); // 指定基于 Cookie 的绑定
}
...
}

6. 健康状态检测

健康状态检测的定义方式,使用 .probe 模块,可用参数:

1
2
3
4
5
6
7
8
9
10
.url =                // 检测时要请求的 URL,默认为 /
.request = // 定义发出的具体请求
"GET /.healthtest.html HTTP/1.1"
"Host: www.monster.com"
"Connection: close"
.timeout = // 定义为超时的时间是多少
.interval = // 定义检测间隔
.window = // 定义在过去 N 次的检测结果中,少于 .threshold 中定义的次数为超时
.threshold = // 定义最少超时次数
.expected_response = // 期望的响应码,默认为 200

健康状态检测的两种配置方法:

  • (1) 单独定义 probe 模块,之后引用即可。
1
2
3
4
5
6
7
8
9
10
11
12
probe web_health {     // 先定义
.url = "/index.html";
.interval = 2s;
.timeout = 1s;
.window = 8;
.threshold = 6;
}

backend static1 { // 在需要启用健康状态检测的 backend 中引用
.probe = web_health;
...
}
  • (2) 在每个需要的 backend 中都定义一次。
1
2
3
4
5
6
7
8
9
backend static1 {
.probe = {
.url = "/index.html";
.interval = 2s;
.timeout = 1s;
.window = 8;
.threshold = 6;
}
}

手动设定健康状态的命令

  • backend.set_health <ARG>
    • sick:管理强制 down;
    • healthy:管理强制 up;
    • auto:自动探测;

七、设置运行时参数

使用 varnishadm 设置运行时参数,立刻生效,但是重启后失效。

  • param.show -l:显示所有可调参数列表;
  • param.show <PARAM>:显示某个参数当前运行的值;
  • param.set <PARAM> <VALUE>:设定一个参数;

想永久生效的话需要保存在 /etc/varnish/varnish.params 配置文件中;

  • -p param=value:设定运行参数及其值;每个值前都需要加 -p
  • -r param[,param...]:设定指定的参数为只读状态;

示例:

1
DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"

设置参数在 Varnish 运行时不能修改,只能重启修改,缓存会全部失效。

  • -r param[,param...]

示例:

1
DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300 -r thread_pools,thread_pool_max"

thread_pools 相关参数

线程相关的参数,thread_pools 可以设定要运行的线程数,和 Nginx 一样,Varnish 也使用 epoll 模型,即一个线程处理多个请求,所以线程数量设置最好小于或等于 CPU 核心数量。

  • thread_pools Number:设置线程池的个数,最好小于或等于 CPU 核心数量;

  • thread_pool_max:每线程池的最大并发连接数,所以最大并发连接数 = thread_pools * thread_pool_max

  • thread_pool_min:额外意义为“最大空闲线程数”;

  • thread_pool_timeout:当空闲的线程数大于 thread_pool_min 设置的值后,超过此值设置的时间后,空闲的线程将被 KILL 掉;

  • thread_pool_add_delay:至少要等待这么长时间后,再创建新线程;

  • thread_pool_destroy_delay:至少要等待这么长时间后,再销毁线程;

Timer 相关的参数

  • send_timeout:向客户端发送响应报文时的连接超时时长;
  • timeout_idle:客户机连接的空闲超时时长;
  • timeout_req:等待客户端传输完成请求报文的超时时长;
  • cli_timeout:等待客户端接收响应报文的超时时长;

八、日志

Varnish 的日志保存在一段内存空间中,是循环覆盖的方式,太老旧的会被覆盖掉。

1. 实时显示统计信息

varnishstat:交互式的显示统计信息;

  • -1 -f FILED_NAME -f FILED_NAME:只显示指定的统计项,-1 只显示一批次的信息就退出;
  • -l:查看所有可用的统计项;

主要有:MAIN.cache_hit, MAIN.cache_miss

2. 实时显示速率日志

varnishtop:实时显示速率日志;

  • -1:只显示一批次的信息就退出;
  • -i taglist:白名单,可以同时使用多个 -i 选项,也可以一个选项跟上多个标签;
  • -I <[taglist:]regex>:对指定的标签的值,基于 regex 进行过滤;
  • -x taglist:黑名单
  • -X <[taglist:]regex>:对指定的标签的值,基于 regex 进行过滤,符合条件的予以排除;

3. 实时抽取出详细独立日志

  • varnishlog:每一个请求独立显示。
  • /usr/lib/systemd/system/varnishlog.service:运行为服务态,将日志持久保存而不被覆盖;

4. 原始格式日志

  • varnishncsa:显示为类似于 httpd 日志样式的原始日志。
  • /usr/lib/systemd/system/varnishncsa.service:运行为服务态,将日志持久保存而不被覆盖;