1. 博客/

varnish缓存服务器的配置

·1095 字·6 分钟
Linux Varnish

Varnish简介
#

Varnish是一款高性能且开源的反向代理服务器和 HTTP 加速器,支持采用基于linux系统内存的缓存服务器。

varnish的系统架构如下图:

varnish
  1. varnish是主要运行两个进程:Management进程和Child进程(也叫Cache进程),基于 epoll机制的单进程多线程架构
  • Management进程类似于nginx中的master,主要实现 编译VCL并应用新配置(通知子进程);监控varnish格子进程运行状态,初始化varnish; 提供一个CLI接口(命令行接口)指挥管理进程 等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。
  • Child进程包含多种类型的线程,常见的如:
    • Acceptor线程:接收新的连接请求并响应
    • Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多
    • Expiry线程:从缓存中清理过期内容
  1. varnish通过使用VCL(Varnish Configuration Language )配置缓存系统的缓存策略,VCL编译器调用C编译器,C编译器编译配置文件为二进制文件并连接至child进程。

VCL语法格式

(1)//、#或/* comment */用于注释 (2)sub $name 定义函数 (3)不支持循环,有内置变量 (4)使用终止语句,没有返回值 (5)域专用 (6)操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)

三类主要语法:

sub subroutine {
    ...
}

if CONDITION {
    ...
} else {    
    ...
}

return(), hash_data()
  1. Varnish状态引擎(state engine)

varnish内部有几个所谓的状态(state),在这些状态上可以附加通过VCL定义的策略以完成相应的缓存处理机制,因此VCL也经常被称作“域专用”语言或状态引擎,“域专用”指的是有些数据仅出现于特定的状态中。在VCL状态引擎中,状态之间具有相关性,但彼此间互相隔离,每个引擎使用return(x)来退出当前状态并联至哪个下一级引擎;每个状态引擎对应于vcl文件(default.vcl)中的一个配置段,即为subroutine。例如:

vcl_recv – 处理客户端请求的第一步,分析是否为标准HTTP请求,是否为可缓存资源等

vcl_synth – 用于合成响应报文

vcl_purge – 用于删除某条缓存记录

vcl_backend_fetch – 根据服务器端的响应作出缓存决策(eg:是否先缓存再响应给客户端)

vcl_pass – 不能缓存的请求跳转到vcl_backend_fetch状态

两个特殊的引擎: vcl_init – 在处理任何请求之前要执行的vcl代码:主要用于初始化加载额外模块;vcl配置文件中要先于vcl_recv定义 vcl_fini – 所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs;

  1. 变量

在vcl配置文件中指定缓存规则时,可以引用变量,包括内建变量与自定义变量

  • 内建变量:

​ req.*:request,表示由客户端发来的请求报文相关

​ req.http.*

​ req.http.User-Agent 客户端设备类型

​ req.http.Referer 超链接跳转地址

​ bereq.*:由varnish发往BE主机请求报文相关

​ bereq.http.*

​ beresp.*:由BE主机响应给varnish的响应报文相关

​ beresp.http.*

​ resp.*:由varnish响应给client相关

​ obj.*:存储在缓存空间中的缓存对象的属性;只读

​ server.*

​ server.ip:varnish主机的IP

​ server.hostname:varnish主机的Hostname

​ client.*

​ client.ip:发请求至varnish主机的客户端IP

  • 自定义变量

​ set/unset

详情请参考https://varnish-cache.org/docs/4.0/

varnish安装与配置
#

  • 使用yum源安装varnish$ yum install -y varnish

  • 配置文件:/etc/varnish/varnish.params –> 配置varnish服务进程的工作特性

    • VARNISH_LISTEN_PORT=6081 – varnish 服务进程监听的端口

    • VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1

      VARNISH_ADMIN_LISTEN_PORT=6082

    ​ varnishadm命令行工具连入CLI接口的地址与端口

    • VARNISH_STORAGE=“malloc,1024M”

      ​ varnish的缓存存储机制( Storage Types):

      ​ malloc[,size] — 内存存储,[,size]用于定义空间大小;重启后所有缓存项失

      ​ file[,path[,size[,granularity]]] — 磁盘文件存储,黑盒;重启后所有缓存项失效

      ​ persistent,path,size — 文件存储,黑盒;重启后所有缓存项有效;实验阶段

    • DAEMON_OPTS="-P thread_pools=2 -p thread_pool_max=1000 thread_pool_timeout=300"

​ 指定varnish的运行时参数thread、timer相关

  • 配置文件:/etc/varnish/default.vcl –>配置各Child/Cache线程的缓存策略

结合一下示例来熟悉vcl配置:

  1. 使用内建变量obj.hits(用于保存某缓存项的从缓存中命中的次数)在响应报文中添加缓存标记
$ vim /etc/varnish/default.vcl
backend default {                                               <-- 定义后端服务器监听的IP与端口
 .host = "192.168.196.132";
 .port = "80";
}
sub vcl_deliver {
if (obj.hits>0) {
         set resp.http.X-Cache = "HIT via " + server.ip;
     } else {
         set resp.http.X-Cache = "MISS from " + server.ip;
    }
}

$ varnish_reload_vcl                                                 <--自动加载cmd
Loading vcl from /etc/varnish/default.vcl
Current running config name is
Using new config name reload_2017-09-07T16:02:29
VCL compiled.
VCL 'reload_2017-09-07T16:02:29' now active
available       0 boot
active          0 reload_2017-09-07T16:02:29                          <--当期使用的版本
Done

浏览器中访问http://192.168.196.133:6081,刷新之后,从响应报文的X-Cache字段可以看出请求的资源是否被缓存

img
  1. 强制对某类资源的请求不检查缓存(eg:用户私有数据)
$ vim /etc/varnish/default.vcl
vcl_recv {
     if (req.url ~ "(?i)^/(login|admin)") {                <-- /login与/admin目录下均不能缓存
        return(pass);
     }
}

$ varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082      <-- 使用varnishadm工具手动reload配置文件
vcl.list
200        
available       0 boot
active          0 reload_2017-09-07T16:02:29

vcl.load test1 default.vcl
200        
VCL compiled.

vcl.use test1
200        
VCL 'test1' now active

浏览器中访问http://192.168.196.133:6081/login,无论如何刷新,X-Cache字段均显示’MISS from 192.168.196.133'

  1. 缓存对象的修剪 –> 在缓存有限期内,后端服务端资源更新时就需要手动删除缓存
  • purge 一次删除一条缓存记录
$ vim /etc/varnish/default.vcl
acl purgers {                                        <--只允许acl内的IP能使用purge方法
            "127.0.0.0"/8;                               <--必须以127.0.0.1为client发出请求才符合此acl
            "192.168.196.130";
}

vcl_recv {
        if (req.method == "PURGE") {                      <--自定义请求方法PURGE时转到vcl_purge
                    if (!client.ip ~ purgers) {
                        return(synth(405,"Purging not allowed for " + client.ip));
                    }
                        return(purge);
         }
}  

reload之后在客户端192.168.196.130上使用curl命令测试

$ curl -I http://192.168.196.133:6081
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 07 Sep 2017 12:57:43 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 05 Sep 2017 07:38:56 GMT
ETag: "59ae5490-11"
X-Varnish: 32819 32817
Age: 2
Via: 1.1 varnish-v4
X-Cache: HIT via 192.168.196.133                                  <--已缓存
Connection: keep-alive

$ curl -X PURGE http://192.168.196.133:6081                       <--定义请求方法为PURGE
<!DOCTYPE html>
<html>
  <head>
    <title>200 Purged</title>
  </head>
  <body>
    <h1>Error 200 Purged</h1>
    <p>Purged</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 131101</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>

[root@Centos7 varnish]# curl -I http://192.168.196.133:6081
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 07 Sep 2017 13:01:10 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 05 Sep 2017 07:38:56 GMT
ETag: "59ae5490-11"
X-Varnish: 32821
Age: 0
Via: 1.1 varnish-v4
X-Cache: MISS from 192.168.196.133                           <--未到过期时间,已经没有缓存
Connection: keep-alive

$ curl -X PURGE 192.168.196.133:6081                         <--客户端192.168.196.132中访问
<!DOCTYPE html>
<html>
  <head>
    <title>405 Purging not allowed for 192.168.196.132</title>     <--132不在acl定义中,没有权限
  </head>
  <body>
    <h1>Error 405 Purging not allowed for 192.168.196.132</h1>
    <p>Purging not allowed for 192.168.196.132</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 32833</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
  • Banning

    • 使用varnishadm工具删除

    ​ ban

  $ varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
  ban req.url ~ ^/images                     <-- 将images开头的请求的缓存,全部删除
  • 在配置文件中定义,使用ban()函数
     $ vim /etc/varnish/default.vcl
     acl bans {
     "127.0.0.0"/8;
     "192.168.196.130";
     }
  
     if (req.method == "BAN" ){
         if (!client.ip ~ bans){
         return(synth(405,"Ban not allowed for " + client.ip));
      }
         #将请求的资源删除。请求什么,删什么
         ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
         return(synth(200,"Ban succeed"));
     }

reload之后在客户端192.168.196.130上使用curl命令测试

$ curl -I 192.168.196.133:6081
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 07 Sep 2017 13:41:13 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 05 Sep 2017 07:38:56 GMT
ETag: "59ae5490-11"
X-Varnish: 131127 32840
Age: 2
Via: 1.1 varnish-v4
X-Cache: HIT via 192.168.196.133

$ curl -X BAN 192.168.196.133:6081                         <--定义请求方法为BAN
<!DOCTYPE html>
<html>
  <head>
    <title>200 Ban succeed</title>
  </head>
  <body>
    <h1>Error 200 Ban succeed</h1>
    <p>Ban succeed</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 131129</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>

$ curl -X BAN 192.168.196.133:6081                           <--客户端192.168.196.132中访问
<!DOCTYPE html>
<html>
  <head>
    <title>405 Ban not allowed for 192.168.196.132</title>
  </head>
  <body>
    <h1>Error 405 Ban not allowed for 192.168.196.132</h1>
    <p>Ban not allowed for 192.168.196.132</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 131144</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
  1. 调度多个后端主机的设定
  • varnish服务器的设定
$ vim /etc/varnish/default.vcl
import directors;                                       <--需要先导入directors模块
backend imgsrv1 {
    .host = "192.168.196.129";
    .port = "80";
}
backend imgsrv2 {
    .host = "192.168.196.130";
    .port = "80";
}
backend default {
    .host = "192.168.196.132";
    .port = "80";
}

sub vcl_init {                                         <-- 初始化directors设定,需要在vcl_recv之前
    new imgsrvs = directors.round_robin();             <-- 自定义后端集群名字、调度算法
    imgsrvs.add_backend(imgsrv1);                      <-- 指定要调度的后端主机
    imgsrvs.add_backend(imgsrv2);
}

sub vcl_recv {
if (req.url ~ "(?i)\.(jpg|png|txt)$"){
        set req.backend_hint = imgsrvs.backend();       <-- 对jpg/png/txt访问调度到后端imgsrvs集群
    }else{
        set req.backend_hint = default;
    }
     
    if (req.url ~ "(?i)\.txt$"){                        <-- 为看出轮询效果,不缓存.txt文件
       return(pass);
    }

}
  • 在imgsrv1/imgsrv2根目录上分别创建test.txt

    192.168.196.129 –> echo “Backend imgsrv1” > /usr/share/nginx/html/test.txt

    192.168.196.130 –> echo “Backend imgsrv2” > /usr/share/nginx/html/test.txt

  • 为了看出后端服务器轮询的调度效果,在vcl配置文件中定义了不缓存.txt结尾的文件,使用curl命令访问

    $ while : ; do curl 192.168.196.133:6081/test.txt; sleep 1; done
    Backend imgsrv1
    Backend imgsrv2
    Backend imgsrv1
    Backend imgsrv2
    Backend imgsrv1
    
  1. 后端主机健康检测设置

方法一:直接在Backend 下定义.probe 健康状态检测方法

backend BE_NAME {
    .host =  
    .port =
    .probe = {
        .url=                                           <--检测时要请求的URL,默认为”/"
        .timeout=                                       <--超时时长
        .interval=                                      <--检测频率
        .window=                                        <--基于最近的多少次检查来判断其健康状态
        .threshold=                                     <--最近.window次检查中多少次成功才算健康
    }
}

方法二:定义probe,然后在各个backend中调用

probe PB_NAME  { }            <---定义一个probe 再调用               
backend NAME = {
      .probe = PB_NAME;
      ...
}  
  • 在各个后端主机Web服务根目录创建.healthchk.html文件,用作健康检测
  • 修改vcl配置文件
$ vim /etc/varnish/default.vcl
probe healthchk{
   .url = "/.healthchk.html";       
   .timeout = 1s;
   .interval = 2s;
   .window = 5;
   .threshold =4;
}
backend imgsrv1 {
    .host = "192.168.196.129";
    .port = "80";
    .probe = healthchk;
}
backend imgsrv2 {
    .host = "192.168.196.130";
    .port = "80";
    .probe = healthchk;
}
backend default {
    .host = "192.168.196.132";
    .port = "80";
    .probe = healthchk;
}
  • 在reload之后使用varnishadm工具查看backend状态
$ varnishadm -S secret -T 127.0.0.1:6082
backend.list
200        
Backend name                   Refs   Admin      Probe
imgsrv1(192.168.196.129,,80)   1      probe      Healthy 5/5
imgsrv2(192.168.196.130,,80)   1      probe      Healthy 5/5
default(192.168.196.132,,80)   1      probe      Healthy 5/5
  • 手动停止imgsrv1的nginx web服务,curl命令测试
$ while : ; do curl 192.168.196.133:6081/test.txt;sleep 1; done
Backend imgsrv1
Backend  imgsrv2
Backend imgsrv1
Backend  imgsrv2
<!DOCTYPE html>
<html>
  <head>
    <title>503 Backend fetch failed</title>
  </head>
  <body>
    <h1>Error 503 Backend fetch failed</h1>
    <p>Backend fetch failed</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 32828</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
Backend  imgsrv2
Backend  imgsrv2
Backend  imgsrv2
  • varnishadm工具查看backend状态, imgsrv1显示为Sick;重启imgsrv1 nginx服务即可恢复
$ varnishadm -S secret -T 127.0.0.1:6082
backend.list
200        
Backend name                   Refs   Admin      Probe
imgsrv1(192.168.196.129,,80)   1      probe      Sick 0/5               
imgsrv2(192.168.196.130,,80)   1      probe      Healthy 5/5
default(192.168.196.132,,80)   1      probe      Healthy 5/5
  • 手动设定BE主机的状态
    • sick – 手动标记为down
    • healthy – 管理up, 永久健康
    • auto – probe auto
$ varnishadm -S secret -T 127.0.0.1:6082
backend.set_health imgsrv1 sick
200        

backend.list
200        
Backend name                   Refs   Admin      Probe
imgsrv1(192.168.196.129,,80)   1      sick       Healthy 5/5
imgsrv2(192.168.196.130,,80)   1      probe      Healthy 5/5
default(192.168.196.132,,80)   1      probe      Healthy 5/5
  1. 后端主机其它属性设置
backend BE_NAME {
    ...
    .connect_timeout = 0.5s;                  <--注意是TCP连接,不是http连接
    .first_byte_timeout = 20s;                <--后端主机响应首字节传输超时时间
    .between_bytes_timeout = 5s;              <--字节传输中间间隔时长
    .max_connections = 50;                    <--最大并发连接数
}

varnish日志
#

  • varnishlog –Display Varnish logs

实时获取varnish服务器详细的接收请求及响应日志,常用于debug

  • varnishncsa - Display Varnish logs in Apache / NCSA combined log format

ncsa格式的日志,使用命令行cmd实时获取

$ varnishncsa
192.168.196.130 - - [09/Sep/2017:13:05:10 +0800] "GET http://192.168.196.133:6081/ HTTP/1.1" 200 25 "-" "curl/7.29.0"

或者使此服务工作于后台记录日志

$ /usr/bin/varnishncsa -a -w /var/log/varnish/varnishncsa.log -D

在Centos7中varnishncsa为单独的服务,启动即可$systemctl start varnishncsa

Related

DNS服务器据源地址解析的实现
·585 字·3 分钟
Linux DNS
使用XtraBackup工具实现MySQL数据备份及恢复
·1177 字·6 分钟
Linux Mysql Xtrabackup
使用mysqldump工具实现MySQL数据备份
·885 字·5 分钟
Linux Mysql