缓存服务器Varnish

阳光之吻 2019-06-21

博文参考

http://www.178linux.com/76700
http://www.mamicode.com/info-detail-229142.html

Varnish简介

varnish 是非常轻量级,也很强大的一款提供缓存服务的应用.高性能且开源的反向代理服务器和HTTP加速器;
缓存服务器Varnish

varnish的配置是通过VCL缓存策略工具实现的,这个工具是一种简单的编程语言,用户可以自定义变量、

有好几个内置的函数和变量,但是它的函数不支持接受参数,而且没有返回值。使用VCL编写的缓存策略通常保存至.vcl文件中,

其需要编译成二进制的格式后才能由varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、

vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义。

VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序,

所以varnish的安装和运行依赖于gcc库。编译完成后,management负责将其连接至varnish实例,

即子进程。编译时会检查语法是否有误,避免了装载错误语法的VCL。一但编译完成并且没有语法错误就会被装载,

同时可以保存好几份配置,当你觉得之前的配置策略更科学时,调用之前的配置即可. 只要调用库中的配置策略,就可以使规则生效,

无需重启或者reload.所以修改配置策略的代价很小。配置的策略只有在varnish重启时才会清除,当然,也可以手动清理,

可以使用varnishadm的vcl.discard命令完成。

varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:

(1)file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果内存够大,条件允许); 可以指定其所保存的位置,大小,以及缓存分配粒度, 即每次分配的大小,直到size大小为止不再分配.使用方法 file[,path[,size[,granularity]]]

(2)malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象; 使用方法malloc[,size]

(3)persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期,悲催,好不容易有一个能持久保存的,还不稳定;

varnish的进程分两类,

管理进程, (master进程),其工作职责如下

1,读入配置文件

2,调用合适的存储类型 ,varnish支持将缓存写入磁盘

3,创建/读入相应大小的缓存文件 (但是这个功能还处于测试阶段,建议暂时不要使用)

4,初始化管理,将缓存文件结构空间关联到存储结构体 ,以待分配,

5,fork出多个空闲子进程并监控各child进程

工作进程 (child子进程)

1,将前面打开的存储文件整个mmap到内存

2,创建并实始化空闲的结构体,用来存储缓存对象,

3,由诸多线程各司其职负责完成相关的工作:

主进程 fork 子进程,主进程等待子进程的信号,子进程退出后,主进程重新启动子进程,子进程生成若干线程。

Accept 线程:接受请求,将请求分配到空闲子进程上,并让空闲的work线程响应用户请求

Work线程: work线程有多个,从队列领取请求,并对请求处理,处理完成后,继续领取下一个请求进行处理

work线程处理时,会读取该请求的url, 以此判定本地缓存中是否有该缓存对象命中,如果命中直接构建响应报文,

如果没有,则去上游服务器查找数据,并缓存至本地再构建响应报文响应请求.

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

Expire 线程:对于缓存的对象,根据过期时间,组织成二叉堆,该线程周期检查该堆的根,处理过期的文件。

线程之间的关系:

worker:处理用户请求

  accept: 接收用户请求

当缓存空间耗尽:

需要清理缓存空间了,可以使用LRU算法清理,(LRU指最近最少使用的)

缓存处理流程

缓存服务器Varnish

什么是web cache?

Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在与Web服务器和客户端(浏览器)直接的副本。缓存会根据进来的请求保存输出内容的副本;当下一个请求到来的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求还是向源服务器再次发送请求。 —–摘自Alloy Team

缓存命中率类型:

文档命中率:按文档数量进行衡量

字节命中率:按命中的字节数量进行衡量

缓存处理流程:

接受请求:接受来自client的访问请求

解析请求:提取client访问请求的URL中的头部信息

查询缓存:根据提取的头部信息查询缓存数据是否含有客户端访问的请求数据

新鲜度监测:如果缓存数据中含有客户端访问的数据,则检查数据的有效性

创建响应报文:当确定缓存命中的数据有效,则创建响应报文

发送响应报文:当响应报文构建完成之后,发送响应报文给客户端

记录日志:发送响应报文的同时记录日志信息

新鲜度监测的方法:

1、过期日期或有效性:

HTTP/1.0:使用Expries定义缓存过期的绝对时间

例如:Expires:Sat, 18 Jul 2015 03:41:04 GMT

HTTP/1.1: 利用Cache-Control定义文档的最大使用期限,是相对时长

例如:Cache-Control: max-age 1d: 缓存有效期为1天

2、服务器再验证:向服务器验证数据是否发送改变

1)如果原始内容没有改变,则服务器仅响应首部,不附带body部分,响应码为304;

2)如果原始内容发生改变,则正常响应,响应码为200;

3)若果原始内容已不存在,则响应码为404,此时缓存也应该清除缓存项;

3、条件式请求首部:

If-Modified-Since: 从指定时间之后的时间内,原始内容是否发生啦的改变

If-None-Match: 每个版本的文档都有一个标签ETag,当内容发生改变此ETag也会发送更改

控制缓存能力:

服务器端:Cache-Control

no-store: 不准缓存;

no-cache: 可以缓存,但在提供给请求者之前必须做新鲜度监测;

must-revalidate:可以缓存,但在提供给请求者之前必须做新鲜度监测;

max-age: 最大使用期限

Expires:过期的绝对时间

客户端新鲜度限制:Cache-Control

max-stale: 最大失效时间

max-stale=<s>:指定最大失效时间

min-fresh=<s>:最短有效时间

max-age=<s>:最大有效时间

注意:含有private、authentication、cookie等信息最好不要缓存;

varnishi有两类线程:

management:

1)读入配置文件

2)调用合适类型的存储(有malloc内存、tmp、persisten三种存储类型)

3)创建/读入相应大小的缓存文件

4)初始化管理结构体空间

5)fork并监控child进程

child/cache:

1)将打开的存储文件映射进内存空间

2)创建并初始化空闲的结构体空间

varnish有九个状态引擎,如下图所示:

varnish九个状态引擎

缓存服务器Varnish

varnish配置文件介绍:

1)后端节点定义:

backend name { } ;

代理缓存:子进程定义

sub+状态引擎 { };

引擎之间都有相关性,前一个引擎通过return(x)定义退出状态,进而决定继续处理下一个引擎;

2)vcl:

vcl是基于“域”的简单编程语言;支持算术运算和逻辑运算,支持正则表达式,支持使用set、unset自定义变量或取消变量,支持if条件判断,有内置的函数和变量;

配置语法:

①注释://单行注释,/…../多行注释

②sub $name 定义函数

③不支持循环

④支持终止语句return,没有返回值

⑤域专用

⑥操作符:=(赋值)、==(比较)、~(正则)、!(取反)、&&(和)、||(或者)

3)vcl的内置函数

regsub(str,regexp,sub):以regexp为模式匹配str,将匹配到的第一个替换为sub

  regsuball(str,regexp,sub):以regexp为模式匹配str,将所有匹配到的都替换为sub

  hash_date(str):做hash计算

  purge:从缓存中挑出某对象并删除

  return(x): 定义退出状态
4)内置变量: 
![clipboard.png](/img/bVTJhn)
![clipboard.png](/img/bVTJhI)
# 配置文件:
·/etc/varnish/varnish.params—配置varnish服务进程的工作特性,例如监听的地址和端口,缓存机制;
·/etc/varnish/default.vcl—配置各Child/Cache线程的缓存工作属性;

配置函数

1、vcl_recv函数

用于接收和处理请求,当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。
此函数一般以如下几个关键字结束:
pass:表示进入pass模式,把请求控制权交给vcl_pass函数。
pipe:表示进入pipe模式,把请求控制权交给vcl_pipe函数。

lookup: 表示进入hash,把请求控制权交给vcl_hash函数.
error code [reason]:表示返回“code”给客户端,并放弃处理该请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。
2、vcl_pipe函数
此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容返回给客户端,直到这个链接关闭
此函数一般以如下几个关键字结束:
error code [reason]
pipe
3、vcl_pass函数
此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,后端主机应答数据后送给客户端,但不进行任何缓存,在当前连接下每次都返回最新的内容, 关键字结束:
error code [reason]
pass
4、lookup
表示在缓存里查找被请求的对象,并且根据查找的结果把控制权交给函数vcl_hit或者函数vcl_miss
5、vcl_hit函数
在执行lookup指令后,如果在缓存中找到请求的内容,将自动调用该函数
此函数一般以如下几个关键字结束:
deliver:表示将找到的内容发送给客户端,并把控制权交给函数vcl_deliver
error code [reason]
pass
6、vcl_miss函数
在执行lookup指令后,如果没有在缓存中找到请求的内容时自动调用该方法,此函数可以用于判断是否需要从后端服务器取内容
此函数一般以如下几个关键字结束:
fetch:表示从后端获取请求的内容,并把控制权交给vcl_fetch函数
error code [reason]
pass :去后端主机取数据时,额外再做一些操作
7、vcl_fetch函数
在从后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是否将内容放入缓存,还是直接返回给客户端
此函数一般以如下几个关键字结束:
error code [reason]
pass 可以不缓存
deliver 也可以缓存
8、vcl_deliver函数
在缓存中找到请求的内容后,发送给客户端前调用此方法。此函数一般以如下几个关键字结束:
error code [reason]
deliver 响应客户端请求
9、vcl_timeout 函数
此函数在缓存内容到期前调用。一般以如下几个关键字结束:
discard:从缓存中清除该内容。
fetch 也可以去后端主机取数据
10、vcl_discard函数
在缓存内容到期后或缓存空间不够时,自动调用该方法,一般以如下几个关键字结束:
keep:表示将内容继续保留在缓存中
discard:从缓存中清除该内容。

配置文件:

·/etc/varnish/varnish.params—配置varnish服务进程的工作特性,例如监听的地址和端口,缓存机制;
·/etc/varnish/default.vcl—配置各Child/Cache线程的缓存工作属性;

1)安装

[root@varnish ~]# yum -y install varnish

2)配置varnish服务配置文件

[root@varnish ~]# vim /etc/sysconfig/varnish 
# Configuration file for varnish

NFILES=131072 \\定义可以打开的最大文件数量

MEMLOCK=82000 \\定义log信息使用多大的内存空间,注意varnish log信息保存在内存中
 
NPROCS="unlimited"  \\ 每个线程响应多少请求

# DAEMON_COREFILE_LIMIT="unlimited" \\ 保持默认即可

RELOAD_VCL=1 \\保持默认即可

# This file contains 4 alternatives, please use only one. \\有四种配置方法:

## Alternative 1, Minimal configuration, no VCL \\方法一
#
# Listen on port 6081, administration on localhost:6082, and forward to
# content server on localhost:8080.  Use a fixed-size cache file.
#
#DAEMON_OPTS="-a :6081 \
#             -T localhost:6082 \
#             -b localhost:8080 \
#             -u varnish -g varnish \
#             -s file,/var/lib/varnish/varnish_storage.bin,1G"


## Alternative 2, Configuration with VCL \\方法二
#
# Listen on port 6081, administration on localhost:6082, and forward to
# one content server selected by the vcl file, based on the request.  Use a
# fixed-size cache file.
#
#DAEMON_OPTS="-a :6081 \
#             -T localhost:6082 \
#             -f /etc/varnish/default.vcl \
#             -u varnish -g varnish \
#             -S /etc/varnish/secret \
#             -s file,/var/lib/varnish/varnish_storage.bin,1G"


## Alternative 3, Advanced configuration  \\方法三
#
# See varnishd(1) for more information.
#
# # Main configuration file. You probably want to change it ?
VARNISH_VCL_CONF=/etc/varnish/test.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=
VARNISH_LISTEN_PORT=80  \\定义监听端口,默认为6081
#
# # Telnet admin interface listen address and port
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1    \\管理varnish监听地址
VARNISH_ADMIN_LISTEN_PORT=6082   \\管理varnish的监听端口
#
# # Shared secret file for admin interface
VARNISH_SECRET_FILE=/etc/varnish/secret \\varnish加密文件
#
# # The minimum number of worker threads to start
VARNISH_MIN_THREADS=50  \\varnish最小进程数
#
# # The Maximum number of worker threads to start
VARNISH_MAX_THREADS=1000 \\varnish最大进程数
#
# # Idle timeout for worker threads
VARNISH_THREAD_TIMEOUT=120 \\varnish工作进程超时时长
#
# # Cache file location
VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin \\缓存文件存储类型,可以定义使用内存存储
#
# # Cache file size: in bytes, optionally using k / M / G / T suffix,
# # or in percentage of available disk space using the % suffix.
VARNISH_STORAGE_SIZE=1G  \\定义存储空间大小
#
# # Backend storage specification
VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" \\定义存储属性
#
# # Default TTL used when the backend does not specify one
VARNISH_TTL=120 \\缓存时长
#
# # DAEMON_OPTS is used by the init script.  If you add or remove options, make
# # sure you update this section, too.
DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
             -f ${VARNISH_VCL_CONF} \
             -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
             -t ${VARNISH_TTL} \
             -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
             -u varnish -g varnish \
             -S ${VARNISH_SECRET_FILE} \
             -s ${VARNISH_STORAGE}"
#

## Alternative 4, Do It Yourself. See varnishd(1) for more information. \\方法四
#
# DAEMON_OPTS="

3)配置varnish主配置文件,添加响应报文首部

[root@varnish sysconfig]# cd /etc/varnish/
[root@varnish varnish]# cp default.vcl test.vcl
[root@varnish varnish]# vim test.vcl 
backend default {  \\定义后端主
  .host = "172.16.2.14";  \\后端主机地址
  .port = "80"; \\后端主机监听端口
}
sub vcl_deliver {   \\在vcl_deliver状态引擎中定义
     if (obj.hits > 0) {    \\如果缓存命中次数大于0
       set resp.http.X-Cache = "HIT";  \\添加响应首部X-Cache;设置值为HIT;
     } else {
       set resp.http.X-Cache = "MISS"; \\ 添加响应首部X-Cache;设置值为MISS;
     }
     return (deliver); \\定义返回状态
}

应用此配置:

[root@varnish ~]# /etc/init.d/varnish start
root@varnish ~]# varnishadm -S /etc/varnish/secret  -T 127.0.0.1:6082 \\进入varnish管理界面
200        
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,2.6.32-431.el6.x86_64,x86_64,-sfile,-smalloc,-hcritbit
varnish-3.0.7 revision f544cd8

Type 'help' for command list.
Type 'quit' to close CLI session.

varnish> vcl.load t1 /etc/varnish/test.vcl  \\载入配置文件
200        
VCL compiled.
varnish> vcl.use t1  \\使用配置文件
200

 VCL状态引擎:

 内建变量:

·req.*:request,表示由客户端发来的请求报文相关;
·bereq.*:由varnish发往BE主机的httpd请求相关;
·beresp.*:由BE主机响应给varnish的响应报文相关;
·resp.*:由varnish响应给client相关;
·obj.*:存储在缓存空间中的缓存对象的属性;只读;

常用变量:

·bereq., req.

bereq.http.HEADERS
bereq.request:请求方法;
bereq.url:请求的url;
bereq.proto:请求的协议版本;
bereq.backend:指明要调用的后端主机;
req.http.Cookie:客户端的请求报文中Cookie首部的值;
req.http.User-Agent ~ “chrome”

·beresp., resp.

beresp.http.HEADERS
beresp.status:响应的状态码;
reresp.proto:协议版本;
beresp.backend.name:BE主机的主机名;
beresp.ttl:BE主机响应的内容的余下的可缓存时长;

·obj.*

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

·server.*

server.ip
server.hostname

·client.*

交互式配置

varnishadm
登录:

-S /etc/varnish/secret -T 127.0.0.1:80

配置文件相关:

vcl.list :状态引擎列表;
vcl.load:装载,加载并编译;
vcl.use:激活;
vcl.discard:删除;
vcl.show [-v] <configname>:查看指定的配置文件的详细信息,可看默认配置;

运行时参数:

param.show -l:显示列表;
param.show <PARAM>
param.set <PARAM> <VALUE>

缓存存储:

storage.list

后端服务器:

backend.list

对某种请求不检查缓存

示例:
vcl_recv {
    if (req.url ~ “(?i)^/(login|admin)”) {
    return(pass);
}
}

拒绝某种请求访问

示例:
vcl_recv {
    if (req.http.User-Agent ~ “(?i)curl”) {
    return(synth(405));
}
}

对公开资源,取消私有标记,并设定缓存时长

示例:
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;
}
}

显示后端主机IP

示例:
if (req.restarts == 0) {
if (req.http.X-Fowarded-For) {
    set req.http.X-Forwarded-For = req.http.X-Forwarded-For + “,” + client.ip;
} else {
    set req.http.X-Forwarded-For = client.ip;
}
}

根据purge请求清除缓存

示例:
sub vcl_recv {
    if (req.method == “PURGE”) {
    return(purge);
}
}

设置acl访问控制

示例:
acl purgers {
“127.0.0.0”/8;
“10.1.0.0”/16;
}
sub vcl_recv {
    if (req.method == “PURGE”) {
    if (!client.ip ~ purgers) {
    return(synth(405,”Purging not allowed for ” + client.ip));
}
    return(purge);
}
}

用ban命令清除缓存

示例:
ban req.url ~ ^/javascripts
ban req.url ~ /js$

配置varnish后端多台主机

示例:
import directors; # 导入模块
backend server1 {
    .host = “172.16.42.2”;
    .port = “80”;
}
backend server2 {
    .host = “172.16.42.3”;
    .port = “80”;
}
sub vcl_init {
    new websrvs = directors.round_robin();
    websrvs.add_backend(server1);
    websrvs.add_backend(server2);
}
sub vcl_recv {
# 用哪一组server来请求
set req.backend_hint = websrvs.backend();
}

varnish动静分离

示例:
backend default {
    .host = “172.16.42.10”;
    .port = “80”;
}
backend appsrv {
    .host = “172.16.42.2”;
    .port = “80”;
}
sub vcl_recv {
if (req.url ~ “(?i)\.php$”) {
    set req.backend_hint = appsrv;
} else {
    set req.backend_hint = default;
}
}

对后端主机进行健康状态检测

.probe:定义健康状态检测方法;
.url:检测时请求的URL,默认为”/”;
.request:发出的具体请求;
.window:基于最近的多少次检查来判断其健康状态;
.threshhold:最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的;
.interval:检测频度;
.timeout:超时时长;
.expected_response:期望的响应码,默认为200;
示例:
backend server1 {
    .host = “172.16.42.3”;
    .port = “80”;
    .probe = {
    .url= “/.healthcheck.html” #得先创建这个测试页面;
    .timeout= 1s;
    .interval= 2s;
    .window=5;
    .threshold=5;
    }
}

varnish的性能优化

·thread_pools: 最好小于或等于CPU核心数量;
·thread_pool_max:每线程池的最大线程数;
·thread_pool_min:额外意义为“最大空闲线程数”;
·thread_pool_timeout:线程超时时间
·thread_pool_add_delay:新创建线程
·thread_pool_destroy_delay:杀死空闲线程延迟时间
设置方式:
/etc/varnish/varnish.params (永久有效)
param.set
示例:
DAEMON_OPTS=”-p thread_pools=6 -p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300″

varnish日志查看

1、varnishstat – Varnish Cache statistics

-1
-1 -f FILED_NAME
-l:可用于-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

相关推荐