Varnish配置应用

  1. 云栖社区>
  2. 博客>
  3. 正文

Varnish配置应用

技术小牛人 2017-11-05 20:56:00 浏览869
展开阅读全文

一、Varnish简介

    Varnish是一款高性能的开源缓存代理服务器。Varnish分为Master(management)进程和Child(worker,也叫cache进程)进程。

    Master 进程读入存储配置文件,调用合适的存储类型,然后创建/读入相应大小的缓存文件,接着 master 初始化管理该存储空间的结构体,然后 fork 并监控 child 进程。

    Child 进程在主线程的初始化的过程中,将前面打开的存储文件整个 mmap 到内存中,此时创建并初始化空闲结构体,挂到存储管理结构体,以待分配。

    分配缓存的过程:根据所读到object的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个object的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据LRU机制,把最旧的object释放掉。

     释放缓存的过程:有一个超时线程,检测缓存中所有object的生存期,如果超初设定的TTL(Time To Live)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。

   Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。

      Child 进程分配若干线程进行工作,主要包括一些管理线程和很多worker线程,可分为:

      Accept线程:接受请求,将请求挂在overflow队列上;

     Work线程:有多个,负责从overflow队列上摘除请求,对请求进行处理,直到完成,然后处理下一个请求;

   Epoll线程:一个请求处理称为一个session,在session周期内,处理完请求后,会交给Epoll处理,监听是否还有事件发生;

    Expire线程:对于缓存的object,根据过期时间,组织成二叉堆,该线程周期检查该堆的根,处理过期的文件,对过期的数据进行删除或重取操作。

wKiom1Zw12_C2TcaAAMzcdw3OPo818.jpg



二、Varnish安装

1
2
3
# yum install epel-release
# rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-4.1.el7.rpm 
# yum install varnish


三、Varnish配置

①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使用

主要有以下几点:

a. 块是由花括号分隔,语句以分号结束,使用‘ # ’符号可以添加注释。

b. VCL 使用指定运算符“=”、比较运算符“==”、逻辑运算符“!,&&,!!”等形式,还支持正则表达式和用“~”进行 ACL 匹配运算。

c. VCL 没有用户自己定义的变量,你可以在 backend、request 或 object 上设置变量值,采用 set 关键字进行设置。例如 set req.backend_hint = cluster1.backend();

d. 两个字符串的连接,他们之间没有任何运算符。例如 set resp.http.X-Cache = "HIT via" + " " + server.hostname;

e. \”字符在 VCL 里没有特别的含义,这点与其他语言略有不同。

f. VCL 可以使用 set 关键字设置任何 HTTP 头,可以使用 remove 或是 unset 关键字移除 HTTP 头。

g. VCL 有 if/else 的判断语句,但是没有循环语句。


③设置Varnish参数

1
2
3
4
5
6
7
8
9
10
# cat /etc/varnish/varnish.params |grep -v "#"
RELOAD_VCL=1              ##重新启动服务时是否重新读取VCL并重新编译
VARNISH_VCL_CONF=/etc/varnish/default.vcl       ##默认读取的VCL文件
VARNISH_LISTEN_PORT=80                    ##设置监听的端口(默认监听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_USER=varnish                        ##varnish默认用户
VARNISH_GROUP=varnish                        ##varnish默认组


④定义VCL backend

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
# cp /etc/varnish/default.vcl /etc/varnish/default.vcl.bak
# cat /etc/varnish/default.vcl |grep -v "#"
vcl 4.0;                             ##指明varnish版本
backend web1 {                        ##创建后端主机
    .host = "192.168.10.132";        ##注:可使用域名,须添加hosts
    .port = "80";
}
# systemctl start varnish           ##启动服务
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082    ##varnish命令操作
200        
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,3.10.0-229.el7.x86_64,x86_64,-junix,-smalloc,-smalloc,-hcritbit
varnish-4.1.0 revision 3041728
Type 'help' for command list.
Type 'quit' to close CLI session.
help
200        
help [<command>]
ping [<timestamp>]
auth <response>
quit
banner
status
start
stop
vcl.load <configname> <filename> [auto|cold|warm]
vcl.inline <configname> <quoted_VCLstring> [auto|cold|warm]
vcl.use <configname>
vcl.state <configname> [auto|cold|warm]
vcl.discard <configname>
vcl.list
param.show [-l] [<param>]
param.set <param> <value>
panic.show
panic.clear [-z]
storage.list
vcl.show [-v] <configname>
backend.list [-p] [<backend_expression>]
backend.set_health <backend_expression> <state>
ban <field> <operator> <arg> [&& <field> <oper> <arg> ...]
ban.list

wKioL1Zw4pqR2yuLAABADNeWg-k486.png

wKioL1ZxDtbDKI4uAACGfo_X0ik405.png


⑤定义VCL 后端的集合 director

VCL 可以把多个 backends 聚合成一个组,这些组被叫做 director,这样可以增强性能和弹力,当组里一个 backend 挂掉后,可以选择另一个健康的 backend。VCL 有多种 director,不同的 director 采用不同的算法选择 backend,主要有以下几种:

a. The random director

       Random director 会根据所设置的权值(weight)来选择 backend,.retries 参数表示尝试找到一个 backend 的最大次数,.weight 参数表示权值

b. The round-robin director

     Round-robin director 在选择 backend 时,会采用循环的方式依次选择。

c.  The client director

     Client director 根据 client.identity 来选择 backend,您可以设置 client.identity 的值为 session cookie 来标识 backend。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# vi /etc/varnish/default.vcl
vcl 4.0;                                      ##指明varnish版本
backend server1 {                              ##定义后端服务器1
    .host = "192.168.10.132";        
    .port = "80";
}
backend server2 {                              ##定义后端服务器2
    .host = "192.168.10.133";
    .port = "80";
}
import directors;                            ##定义directors
sub vcl_init {                                      ##定义vcl_init子例程
    new cluster1 = directors.round_robin();    ##创建一个轮叫调度的directors
    cluster1.add_backend(server1);
    cluster1.add_backend(server2);
}
sub vcl_recv {                       ##定义vcl_recv子例程
    set req.backend_hint = cluster1.backend();        ##指定后端directors
}

详情:https://www.varnish-cache.org/docs/4.1/reference/vmod_directors.generated.html#object-hash

⑥设置响应是否命中

1
2
3
4
5
6
7
8
sub vcl_deliver {                   ##定义子例程
        if (obj.hits > 0) {      
                set resp.http.X-Cache = "HIT via" " " + server.ip;
        else {
                set resp.http.X-Cache = "MISS via" " " + server.ip;
        }             ##判断如果命中就在http响应首部设置X-Cache为HIT,否则
                就在http响应首部设置X-Cache为MISS。
}

wKioL1ZxExKhTGOpAACmntDiwCY342.pngwKioL1ZxE2njkMHqAACuerhybZ0140.png





⑦指定某些文件不能查缓存

1
2
3
4
5
sub vcl_recv {
        if (req.url ~ "^/test.html$") {
                return(pass);
        }            ##定义请求的文件中如果匹配test.html就pass,不查缓存
}

 wKiom1ZxF9iDZgU_AABiGwZal7k428.pngwKioL1ZxGAzg3PV7AABrSinPFKk274.png


⑧进行健康检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
backend server1 {
    .host = "192.168.10.132";
    .probe = {
        .url = "/";         ##指定哪个url需要varnish请求
        .timeout = 1s;         ##指定超时等待时间
        .interval = 5s;         ##指定检查时间间隔
        .window = 5;            ##最多尝试5次
        .threshold = 3;          ##至少有3次成功就宣告backend健康
    }
}
backend server2 {
    .host = "192.168.10.133";
    .probe = {
        .url = "/";
        .timeout = 1s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

详细:https://www.varnish-cache.org/docs/4.1/users-guide/vcl-backends.html#health-checks

⑨设定缓存时长

1
2
3
4
5
6
7
8
sub vcl_backend_response {
    if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") {
        set beresp.ttl = 2h;
    }                 ##如果url是以图片格式结尾的缓存2小时
    if (bereq.url ~ "\.(html|css|js|jsp)$") {
        set beresp.ttl = 30m;
    }                  ##如果url是以html|css|js|jsp结尾的缓存30分钟
}


⑩优雅模式(Grace mode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sub vcl_backend_response {
  set beresp.grace = 2m;
}             ##指定保持缓存对象超出TTL值2分钟(就是该过期的缓存不让它过期)
sub vcl_hit {
   if (obj.ttl >= 0s) {
       // A pure unadultered hit, deliver it
       return (deliver);   ##如果TTL值大于等于0秒,将已获取的请求内容直接
                         ##发送给客户端
   }
   if (obj.ttl + obj.grace > 0s) {
       // Object is in grace, deliver it
       // Automatically triggers a background fetch
       return (deliver);
   }                  ##如果TTL值加上优雅模式设定值大于0秒,将已获取
                        ##的请求内容直接发送给客户端
   // fetch & deliver once we get the result
   return (fetch);       ##否则从后端获取请求的内容
}

   

四、VCL相关

注:varnish4.0后版本所使用参数和以前版本有所改变,详见:

https://www.varnish-cache.org/docs/4.0/whats-new/index.html

https://www.varnish-cache.org/docs/4.1/whats-new/index.html


①VCL主要内置函数

a. vcl_recv 函数

       用于接收和处理请求。当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。例如如何响应、怎么响应、使用哪个后端服务器等。

   此函数一般以如下关键字结束:

1). pass:表示进入 pass 模式,把请求控制权交给 vcl_pass 函数;

2). pipe:表示进入 pipe 模式,把请求控制权交给 vcl_pipe 函数;

3). lookup:表示进入 lookup 模式,把请求控制权交给 lookup 指令处理,在缓存中查找被请求的对象,并且根据查找的结果把控制权交给函数 vcl_hit 或函数 vcl_miss;

4). synth code [reason]:表示返回“code”给客户端,并放弃处理该请求。“code”是错误标识,例如 200 和 405 等。“reason”是错误提示信息。


b. vcl_pipe 函数

    此函数在进入 pipe 模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容返回给客户端,直到这个连接被关闭。

     此函数一般以 如下关键字结束:

1). synth code [reason]

2).pipe 


c. vcl_pass 函数

     此函数在进入 pass 模式时被调用,用于将请求直接传递至后端主机。后端主机在应答数据后将应答数据发送给客户端,但不进行任何缓存,在当前连接下每次都返回最新的内容。

   此函数一般以如下关键字结束:

1).  synth code [reason];

2).  pass;

3).  restart 重新启动流程,增加启动次数,如果重新启动次数高于 max_restarts 发出一个错误警告


d. vcl_hash函数

    如果想把一个数据添加到 hash 上时,调用此函数。

    此函数一般以 Hash 该关键字结束。


e. vcl_hit 函数

    在执行 lookup 指令后,在缓存中找到请求的内容后将自动调用该函数。

    此函数一般以如下关键字结束:

1).deliver:表示将找到的内容发送给客户端,并把控制权交给函数 vcl_deliver;

2).synth code [reason];

3).pass;

4).restart 重新启动流程,增加启动次数,如果重新启动次数高于 max_restarts 发出一个错误警告


f. vcl_miss 函数

    在执行 lookup 指令后,在缓存中没有找到请求的内容时自动调用该方法。此函数可用于判断是否需要从后端服务器获取内容。

    此函数一般以如下关键字结束:

1).fetch:表示从后端获取请求的内容,并把控制权交给 vcl_backend_response 函数;

2).synth code [reason];

3).pass。


g. vcl_backend_response 函数

    在后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是将内容放入缓存,还是直接返回给客户端。

    此函数一般以如下关键字结束:

1).synth code [reason]

2).pass

3).deliver

4).esi

5).restart 


h.vcl_deliver函数

    将在缓存中找到请求的内容发送给客户端前调用此方法。

    此函数一般以如下关键字结束:

1).synth code [reason]

2).deliver

3).restart 


i.vcl_backend_error函数

    出现错误时调用此函数。

    此函数一般以如下关键字结束:

1).deliver

2).restart


②varnish处理HTTP请求的过程

wKioL1ZxRtmQ9tBaAAFloAqePRc453.png

Varnish 处理 HTTP 请求的过程如下:

1. Receive状态(vd_recv):请求处理的入口状态,根据VCL规则判断该请求应该pass(vd_pass)或是pipe(vd_pipe),还是进入lookup(本地查询)

2. Lookup状态:进入该状态后,会在hash表中查询数据,若找到,则进入hit状态(vcl_hit),否则进入miss状态(vcl_miss)

3. Pass状态(vcl_pass):在此状态下,会直接进入后端请求,即进入fetch状态(vcl_backend_response)

4.Backend_response状态:由原来的vcl_fetch独立为vcl_backend_fetch和vcl_backend_response2个函数,在该状态下,对请求进行后端获取,发送请求,获得数据,并根据设置进行本地存储

5. Deliver状态(vcl_deliver):将获取到的数据发送给客户端,然后完成本次请求


内置函数(也叫子例程):

1.vcl_recv:用于接收和处理请求,当请求到达并成功接收后被调用,通过判断请求的数据

来决定如何处理请求;

2.vcl_pipe:此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,并将后端响应原样返回客户端;

3.vcl_pass:此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,但后端主机的响应并不缓存直接返回客户端;

4.vcl_hit:在执行lookup指令后,在缓存中找到请求的内容后将自动调用该函数;

5.vcl_miss:在执行lookup 指令后,在缓存中没有找到请求的内容时自动调用该方法,此函数可用于判断是否需要从后端服务器获取内容;

6.vcl_hash:在vcl_recv调用后为请求创建一个hash值时,调用此函数,此hash值将作为varnish中搜索缓存对象的key;

7.vcl_purge:pruge操作执行后调用此函数,可用于构建一个响应;

8.vcl_deliver:将在缓存中找到请求的内容发送给客户端前调用此方法;

9.vcl_backend_fetch:向后端主机发送请求前,调用此函数,可修改发往后端的请求;

10.vcl_backend_response:获得后端主机的响应后,可调用此函数;

11.vcl_backend_error:当从后端主机获取源文件失败时,调用此函数;

12.vcl_init:VCL加载时调用此函数,经常用于初始化varnish模块(VMODs);

13.vcl_fini:当所有请求都离开当前VCL,且当前VCL被弃用时,调用此函数,经常用于清理varnish模块.

详情:https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html


③varnish变量解释

wKioL1ZxSvmD8cjMAAH4qTHpZEE825.jpg

VCL 内置的公共变量(变量也叫object)可以用在不同的 VCL 函数中:

req:The request object,请求到达时可用的变量

bereq:The backend request object,向后端主机请求时可用的变量

beresp:The backend response object,从后端主机获取内容时可用的变量

resp:The HTTP response object,对客户端响应时可用的变量

obj:存储在内存中时对象属性相关的可用的变量


a. 请求到达时可用公共变量

req.backend_hint: 指定对应的后端主机

server.ip: 表示服务器 IP

client.ip: 表示客户端 IP

req.method: 只是请求的类型,例如 GET、HEAD 等

req.url: 指定请求的地址

req.proto: 表示客户端发起请求的 HTTP 协议版本

req.http.header: 表示对应请求中的 HTTP 头部信息

req.restarts: 表示重启次数,默认最大值为4


b. 向后端主机请求时可用公共变量

beresp.requset: 指定请求类型,例如 GET、HEAD 等

beresp.url: 表示请求地址

beresp.proto: 表示客户端发起请求的 HTTP 协议版本

beresp.http.header: 表示对应请求中 HTTP 头部信息

beresp.ttl: 表示缓存的生存周期,cache 保留时间(单位秒)


c. 后端主机获取内容时可使用公共变量

obj.status: 返回内容的请求状态码,例如 200、302、504 等

obj.cacheable: 返回的内容是否可以缓存

obj.valid: 是否有效的 HTTP 请求

obj.response: 返回内容的请求状态信息

obj.proto: 返回内容的 HTTP 版本

obj.ttl: 返回内容的生存周期,也就是缓存时间(单位秒)

obj.lastuse: 返回上一次请求到现在的时间间隔(单位秒)


d.对客户端相应时可使用公共变量

resp.status: 返回给客户端的 HTTP 代码状态

resp.proto: 返回给客户端的 HTTP 协议版本

resp.http.header: 返回给客户端的 HTTP 头部消息

resp.response: 返回给客户端的 HTTP 头部状态

本文转自  结束的伤感  51CTO博客,原文链接:http://blog.51cto.com/wangzhijian/1745993


网友评论

登录后评论
0/500
评论
技术小牛人
+ 关注