首页 > 技术文章 > Linux----------varnish缓存加速

wangchengshi 2019-06-03 15:54 原文

一、varnish简介

Varnish是一款高性能、开源的反向代理服务器和缓存服务器。Varnish使用内存缓存文件来减少响应时间和网络带宽消耗。这个项目是由挪威的一家报纸Verdens Gang的网络分支起始的,其架构设计和开发总监Poul-Henning Kamp是FreeBSD核心的开发人员之一,最初项目的管理与基础设施及额外开发由挪威一家Linux咨询公司Linpro提供。

说到varnish,squid就不得不提及。squid算得上是古老的缓存服务器。由于varnish先进的设计理念,性能要比squid高上许多,varnish还可以通过端口进行管理,使用正则语句做到清除指定缓存的功能,这些squid都做不到。但是varnish在高并发的情况下,资源消耗较高,而且varnish服务进程一旦崩溃,重启,内存中的缓存数据将全部丢失。

1.1 varnish原理

varnish是基于现代设备设计的服务项目,所以仅支持64位系统。Manager Process 负责处理请求任务,保证每个任务分配一个worker threads。所以varnish是一个重线程型服务。除此之外,manager process 包含接受CLI命令控制的功能,包括调整运行参数,vcl配置更新。初始化子进程Cacher Process,并按一定频率检测cacher在线与否。

  • Cacher Process 功能:

监听客户端请求
管理worker 线程
存储缓存数据
记录流量日志
根据统计更新计数器数值
varnish使用工作空间减少每个线程需要请求或者修改内存时发生的争抢。varnish具有多个工作空间,最为重要的是 session 工作空间,用来维护session 相关数据。

在日志记录方面,Cacher process 使用VSL 机制来处理,这是一个共享内存空间,可以有效减少记录阻塞。日志空间分为两个部分,分别记录格式化的请求日志,以及计数器数值。可以通过varnish自带log工具进行查看,分析或者永久存储日志。

1.2 缓存机制

varnish的缓存存储机制( Storage Types):
-s [name=]type[,options]

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

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

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

1.3 程序环境

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 //ogger daemon
  /usr/lib/systemd/system/varnishncsa.service //lgger daemon in apache format

systemd方式启动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:运行于前台;

  • 线程相关的参数:
    在线程池内部,其每一个请求由一个线程来处理; 其worker线程的最大数决定了varnish的并发响应能力;

thread_pools:Number of worker thread pools. 线程池数量,默认值为2,官方介绍2个线程池已足够用,再增加该数值没有提升效果;
thread_pool_max:The maximum number of worker threads in each pool.每个线程池创建最大线程的数量;默认5000
thread_pool_min:The minimum number of worker threads in each pool. 每个线程池保持最少线程的数量;额外意义为“最大空闲线程数”;默认100
所以我们经常需要调整的参数就是thread_pool_max,thread_pool_min
计算varnish最大并发连接数=thread_pools * thread_pool_max

thread_pool_timeout: 线程空闲时间,超过阈值则摧毁线程
thread_pool_add_delay:创建一个新线程的延迟时间,默认值为0s
thread_pool_destroy_delay:摧毁一个线程的延迟时间,默认值为2s;

设置方式:

运行动态修改通过varniadm接口设置
命令:param.set

永久有效的方法:
运行时参数:/etc/varnish/varnish.params文件, DEAMON_OPTS

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

1.3 varnish管理工具

  用法:varnishadm -S /etc/varnish/secret -T [ADDRESS:]PORT

    指定了连接密钥,安装varnish时生成的。指明管理接口的端口地址,默认为127.0.0.1 可省略。

进入之后,输入help [command] 获取帮助

梳理常用指令

配置文件相关:
vcl.list :查看vcl 列表
vcl.load:装载,加载并编译;
vcl.use:激活;
vcl.discard:删除;
vcl.show [-v] :查看指定的配置文件的详细信息;-v 选项查看默认vcl代码

运行时参数:
param.show -l:显示列表;
param.show
param.set 设定参数

缓存存储:
storage.list

后端服务器:
backend.list

二、配置示例

2.1 响应首部增加一个cache是否命中的字段X-cache

~]$ vi /etc/varnish/default.vcl

复制代码
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;
   }

}
复制代码
~]$ varnish_reload_vcl           #重载vcl

或者 使用varnishadm 进入管理接口,使用如下命令

~]$ vcl.load   test1   default.vcl         #装载vcl,并指定一个命名test1

如果返回状态码200,则语法正确,编译通过

2.2 强制对某类资源的请求不检查缓存:

设定访问/login 或 /admin 下的目录任何文件都不查询缓存

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

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

复制代码

sub vcl_backend_response {
 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;
	}
 }
}

2.4 缓存对象的修剪:purge, ban

(1) 能执行purge操作

sub vcl_purge {
return (synth(200,"Purged"));
}

(2) 何时执行purge操作

sub vcl_recv {
if (req.method == "PURGE") {
return(purge);
}
...
}

上面的定义比较简单,任何人都可以对cache做清理操作,下面则根据IP地址做出限制添加此类请求的访问控制法则:

acl purgers {
"127.0.0.0"/8;
"10.1.0.0"/16;
}

sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {                      #这里正则匹配的时acl列表,不需要引号
return(synth(405,"Purging not allowed for " + client.ip));       #来自不属于acl定义的purgers组的purge请求则返回错误代码
}
return(purge);
}
...
}

2.5 设定使用多个后端主机

backend default {
  .host = "172.16.100.6";
  .port = "80";
}

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

sub vcl_recv {	
  if (req.url ~ "(?i)\.php") {
    set req.backend_hint = appsrv;            #php资源转发至appsrv处理
  } else {
      set req.backend_hint = default;
   }	
  ...
}

三、定义后端服务器组

3.1 定义后端服务器组

使用前需要在vcl配置中导入模块:
import director;

  • 示例:
import directors; # load the directors

backend server1 {                 
.host = 
.port = 
}
backend server2 {
.host = 
.port = 
}

sub vcl_init {                    #在init 子函数中定义
new GROUP_NAME = directors.round_robin();         #创建组,并命名为GROUP_NAME,指定调度方法
GROUP_NAME.add_backend(server1);                    #为组添加服务器成员
GROUP_NAME.add_backend(server2);
}

sub vcl_recv {
# send all traffic to the bar director:
set req.backend_hint = GROUP_NAME.backend();  #组引用方法
}

3.2 后端主机健康检测机制

varnish可以对后端主机进行健康检测,动态进行移除或恢复后端主机调度列表

.probe:定义健康状态检测方法;
.url:检测时请求的URL,默认为"/";
.request:发出的具体请求;
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close"
.window:基于最近的多少次检查来判断其健康状态;
.threshhold:最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的;
.interval:检测频度;
.timeout:超时时长;
.expected_response:期望的响应码,默认为200;

健康状态检测的配置方式:

(1) probe PB_NAME = { }
backend NAME = {
.probe = PB_NAME;
...
}

(2) backend NAME {
.probe = {
...
}
}
  • 示例:
probe check {                               #probe   先定义好
.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;
}
  • 在varniadm 命令接口中查看检测状况

推荐阅读