两类缓存服务器:
1.代理式缓存服务器;proxy-like cache server;
2.旁挂式缓存服务器;bypass cache server;

缓存服务器也可以根据缓存数据内容分类:
1.数据缓存;data cache
2.页面缓存;page cache
数据存在访问热区,指被经常访问的数据。

缓存的实质是:用空间换时间;
缓存的局部性特征:空间局部性和时间局部性:

缓存的时效性:
过期清理:PURGE,修剪;
未过期但溢出清理:LRU(最少使用原则);
未过期但被修改:PURGE,修剪;

缓存命中率:Hits/(Hits + Miss) ,取值范围区间是(0,1),通常也会用百分数进行表示;
页面命中率:基于命中的页面数量进行统计衡量的一种标准;
字节命中率:基于命中的页面的体积进行统计衡量的一种标准;(更为精确)

数据缓存与否:
1.私有数据:private data,放置于私有缓存中;
http/1.1版本后的首部中,提供了一个Cach-Control的首部;Cache-Control首部的值中包含有private字样,或者提供了Cookie或者Cookie2的首部;此类数据大多数都是由浏览器完成缓存;
2.公共数据:public data,可以放置于公共缓存,也可以放置于私有缓存中;
此类数据大多数缓存在反代服务器上或者专用的Cache Server上;
小部分也可以缓存在浏览器上;

注意:
浏览器的缓存(一般是私有缓存):
仅针对于单独的用户生效,使用户重复访问某资源时能够加速访问;
缓存服务器的缓存(一般是公共缓存):
为前端调度器或反代服务器加速资源访问,降低后端资源服务器的访问压力;
对于缓存服务器来说,缓存的处理步骤(大致成功的处理步骤):
接收请求 --> 解析请求(从请求报文的http协议首部中提取URL及其他相关的首部信息) --> 查询缓存 --> 缓存数据的新鲜度检测 --> 构建响应报文 --> 发送响应报文--> 记录日志

缓存数据的有效性判断机制:
1.过期时间:
HTTP/1.0:
Expires,绝对时间;
HTTP/1.1:
1.Expires
2.Cache-Control(首部):max-age=86400
3.Cache-Control:s-maxage=10000 (s代表公共缓存)
2.条件式请求:
Last-Modified/If-Modified-Since :响应报文/请求报文的条件请求
Etag/If-None-Match :扩展标签,对标签进行哈希计算;If-None-Match:如果不匹配,返回200代表不匹配

示例:查看百度的logo资源:
Cache-Control max-age=2592000 //缓存资源的最大有效时间
ETag "593645fd-664" //得到的16进制的哈希值
Expires Wed, 11 Jul 2018 03:43:28 GMT //过期时间
Last-Modified Tue, 06 Jun 2017 06:04:45 GMT //自 06 Jun 2017 06:04:45 GMT这个时间点开始资源无变化(GMT:格林尼治时间)

一、memcached缓存服务器:
属于旁挂式缓存服务器,也属于数据缓存;

memcached存储形式:
1.将所有数据采用键值对儿的形式存储于内存当中;
2.无持久存储功能;
3.通常用于缓存小文件,小数据,单项缓存数据内容上限是1MB;

memcached由LiveJournal公司旗下的子公司Danga Interactive研发者Brad Fitzpatrick研发;

memcached特性:
1.k/v cache;可序列化数据,扁平化数据; //常见的还有JSON,也是序列化数据
2.存储项:key(键), value(值), flag(16位二进制数字,0-65535), expire_time(超时时间), length(保存数据的长度)等简单部分组成;
3.旁挂式缓存,功能实现一半依赖于客户端,另一半靠memcached server;
4.O(1)的查找和执行效率;
5.可以构建分布式缓存系统,各服务器之间互不通信的分布式集群系统;
6.缓存数据的处理方式(较为特殊):
1)缓存空间耗尽:根据LRU(最近最少使用算法)完成清理过期数据;
2)缓存项过期:惰性清理机制---用来尽可能减少内存碎片
7.内存分配方式:
slab allocation:按照页面进行打散,将打散的页面分成若干个更小的页面,最大1M
facter:增长因子;默认1.25倍递增;小页面根据增长因子来分配空间大小,最后会留下一个最大不超过1M的空间。

安装配置memcached:
1.base源中有对应的rpm包;可以直接使用yum方式安装内容;
~]# yum install memcached -y
2.从memcached.org官方站点下载源代码包,编译安装;

memcached缓存服务监听的端口:
    11211/TCP, 11211/UDP;

memcached缓存服务程序安装后的默认环境:
    主程序:/usr/bin/memcached
    环境配置文件:/etc/sysconfig/memcached
        ~]# cat /etc/sysconfig/memcached 
        PORT="11211"        //监听的端口号
        USER="memcached"    //程序属于哪个用户
        MAXCONN="1024"      //服务的最大连接数
        CACHESIZE="64"      //缓存大小默认为64
        OPTIONS=""                  //其他选项默认为空

memcached缓存服务使用的协议是memcached协议,memcached协议支持的数据传输格式是:
    1.文件格式
    2.二进制格式

交互式操作(~]# telnet+载有memcached服务主机的IP地址+端口号(默认是11211),使用telnet命令进入交互式操作模式):
    命令:
        1.统计类:stats, stats items(缓存项查看), stats slabs(内存空间的查看), stats sizes
        2.管理类:set(修改特定键的值), add(添加一个新的键), replace(替换原有键的值), append(在原有键值后附加一个值), prepend(在原有键值前附加一个值), delete(删除键), incr(给键添加值), decr(给键删除值), flush_all(清空所有键)
        3.查看类:get

    memcached交互式命令的一般格式:
         key_name [flags] [expire_time] [length_bytes] \n

         key_name:键名
         [flags]:标志位,范围是0-65535
         [expire_time]:键最大缓存时间(秒)
         [length_bytes]:字符长度

        例:
            添加一个新键:
                add testkey 0 300 11
                hello world
                STORED
            查看新键:
                get testkey
                VALUE testkey 0 11
                hello world
                END
            在新键后添加字符并查看:
                添加:
                    append testkey 0 300 2
                    hi
                    STORED
                查看:
                    get testkey
                    VALUE testkey 0 13
                    hello worldhi
                    END
            在新键前添加字符并查看:
                添加:
                    prepend testkey 0 300 3
                    hi 
                    STORED
                查看:
                    get testkey
                    VALUE testkey 0 14
                    hi hello world
                    END

memcached命令选项:
    -c num :指名并发连接数量,默认是1024
    -m num :分配多大的内存空间,默认是64M
    -u username :指定哪个用户启动memcached服务进程
    -p port :指定端口号,默认是11211
    -U port :指定UDP协议的端口号,默认是11211,0是关闭
    -l ipaddress :监听哪一个地址,默认是所有
    -f facter :指明增长因子,默认是1.25倍
    -t thread_num :设置线程数,默认是4个线程
    -v,-vv,-vvv :显示的详细信息程度

二、VARNISH缓存服务器:
varnish缓存服务器是属于页面缓存服务器的一种,用来为客户端请求提供查询结果,也属于代理式缓存服务器。

varnish缓存服务器特点:
varnish缓存服务器可以实现的功能:反向代理 + 缓存服务器
varnish缓存服务器默认在内存中占用128M内存空间去进行缓存服务
缓存服务器的实现:
开源解决方案:
squid:上世纪90年代中期出现;使用率较低
varnish:反向代理式缓存:使用率较高的缓存服务器实现方案;
https://www.varnish-software.com/ //商业版本服务站点
http://varnish-cache.org/ //开源站点

varnish程序的组织结构:
1.Management进程:
1)varnish的主进程;
2)提供命令行工具的访问接口,用来管理子进程,初始化缓存;
2.Child/Cache进程:拥有多种线程模型,如下:
command line
storage/hashing
log/stats
accept
worker threads
object expiry
backend communication
...
3.VCL compiler:C compiler(gcc)

varnish的线程池作用:
统计数据:数据统计和计数器;
日志区域:日志数据;

VCL文件的处理方式:
vcl compiler (vcl编译器编译完成)--> C compiler (再到C的编译器中编译处理)--> shared object

vcl配置文件的重载工具:
/usr/sbin/varnish_reload_vcl

VCL:Varnish Configuration Language,varnish配置语言;
统一存放于后缀名为".vcl"的文件中,在初次安装了varnish之后,在配置主目录中会自动创建出一个名为"default.vcl"的文件,但其内容几乎为空;
varnish的安装:
在EPEL源中直接提供了varnish的稳定版本;
安装命令:yum install -y varnish (需先配置EPEL源)

varnish的程序环境:
1.配置文件:
/etc/varnish/default.vcl
定义缓存策略的默认配置文件,主要用于配置各Child/Cache线程的工作属性;
/etc/varnish/varnish.params
定义varnish缓存服务的运行时参数以及工作特性;
/etc/varnish/secret
在使用varnishadm命令行管理工具时,为了安全起见使用的预共享密钥;

2.主程序:  /usr/sbin/varnishd

 1)CLI(简单的命令行接口管理工具):
    /usr/bin/varnishadm

 2)Share Memory Log交互工具:
    /usr/bin/varnishhist
    /usr/bin/varnishlog
    /usr/bin/varnishncsa
    /usr/bin/varnishstat
    /usr/bin/varnishtop

            开启varnish日志记录(默认没有开启):
                1./usr/bin/varnishlog
                2./usr/bin/varnishncsa(建议在需要开启日志记录的时候开启,因为其更接近于Apache的command的命令形式)

3)缓存测试工具:
    /usr/bin/varnishtest

4)varnish的Unit FIle:
    /usr/lib/systemd/system/varnish.service:管理varnish的Management进程;
    实现日志持久化存储的服务文件;
        /usr/lib/systemd/system/varnishlog.service
        /usr/lib/systemd/system/varnishncsa.service

主程序:/usr/sbin/varnishd
varnishd - HTTP accelerator daemon --http加速器守护进程
常用选项:
-a address[:port][,address[:port][...]
指定用于接收客户端请求所监听的地址和服务端口,默认值为127.0.0.1:6081
-b host[:port]:添加一个backend sever的主机和端口号
-T address[:port]:实现管理的时候需要用到的地址和端口号;
-f config:
指明此次需要编译并装载的VCL配置文件,默认为/etc/varnish/default.vcl;
-p param=value
设置varnish线程模型的运行时参数和参数值;
大多数的运行时参数都有默认值,不要轻易尝试调整运行时参数的值;
在命令行工具中使用此选项调整的运行时参数的值,仅当次生效;
-r param[,param...]
将运行时参数设置为只读属性;意味着当再次运行时,其值无法被修改;
-s [name=]type[,options]:指定缓存的存储机制
定义缓存数据的存储方式,目前有三种存储机制:
1.malloc[,size]:性能最好,但是所有的数据保存在内存中;
2.file[,path[,size[,granularity]]]:只是一种黑盒文件,内容无法观察;键值对儿存放于内存当中,哈希值存放于磁盘中,保证快速检索,不会占用内存太多空间
3.persistent,path,size (experimental,体验测试版):持久存储(机制不成熟)

        -T address[:port]
            在指定的IP地址和端口号上提供管理接口;默认为127.0.0.1:6082;
        -u user、-g group
            指定允许varnish服务进程的系统用户和系统组,默认均为varnish;

运行时参数的配置文件:/etc/varnish/varnish.params
    DAEMON_OPTS="-p param1=value1 -p param2=value2 ..."

    thread_pool_min=5
    thread_pool_max=500
    thread_pool_timeout=300

命令行管理工具:varnishadm (交互式模式)
varnishadm - Control a running Varnish instance
常用选项:
-S secret_file
指定通过命令行工具实现验证时的预共享密钥文件;
-T address:port
指定管理地址和端口;

交互式模式的命令:
    help [] :varnishadm命令帮助
    ping [] :做连通测试
    auth  :做认证
    quit :退出交互式模式
    banner :做条幅
    status :状态输出
    start :启动varnish服务(不建议使用)        //重启、关闭、开启都会把缓存清空,这是致命的
    stop :关闭varnish服务(不建议使用)
    管理vcl:
        vcl.load  :装载并且编译vcl文件
        vcl.inline  :
        vcl.use :激活已经编译好的vcl文件;
        vcl.discard :删除已经编译好的非激活状态下的vcl配置文件;
        vcl.list:vcl配置文件一共有哪些;
    param.show [-l] []:列举所有运行时参数并且输出详细参数;
    param.set  :临时修改某个运行时参数的值,一次性修改,重启后恢复默认
    panic.show:显示运行时参数列表或显示指定的运行时参数的详细信息;
    panic.clear:清空运行时参数列表;
    storage.list:显示缓存存储相关信息;
    vcl.show [-v]  :显示default.vcl所有配置历史更改列表,包括正在使用和使用过的;
    backend.list [] :后端服务器列表显示;
    backend.set_health   :设置后端服务器将康状态码;

常用的命令:
VCL配置文件管理相关:
vcl.load:装载并编译VCL配置文件;
vcl.use:激活已经编译完成的VCL配置文件;
vcl.discard:删除非激活状态下的VCL配置文件;

运行时参数相关:
    param.show:显示运行时参数列表或显示指定的运行时参数的详细信息;
    param.set:实时设置或修改运行时参数的值;(不要轻易尝试修改,一定要清楚操作的目的)

缓存存储相关:
    storage.list:显示缓存存储相关信息;

后端服务器相关:
    backend.list:显示可以直接访问的后端服务器列表;
    backend.set_health:指明后端服务器的健康状态检测方式;

VCL:Varnish Configuration Language;
"域"专有类型的配置语言;

VCL中定义了多个状态引擎,各状态引擎之间存在相关性,同时又彼此隔离;每个状态引擎内都可以使用return()关键字指明各状态引擎之间的关联关系;在VCL文件中,状态引擎使用如下的方式进行定义:
    sub STATE_ENGINE_NAME { ...; }
    sub+状态引擎的名字+{ 配置指令1;配置指令2;... }

三个varnish状态引擎版本对比以及数据处理流程:
1.varnish 2.0-状态引擎包括:
vcl_recv:接收请求,并且判断是否可以使用缓存数据;
vcl_hash:对于从backend端取回的数据,如果可被缓存,则进行哈希计算;
vcl_hit:对于请求的资源可以在缓存对象中直接获取;
vcl_miss:对于请求的资源无法在缓存对象中直接获取;
vcl_deliver:构建响应报文;
vcl_fetch:从backend端取回数据;

    varnish2.0的处理流程:
        1.vcl_recv --> vcl_hash --> vcl_hit --> vcl_deliver
        2.vcl_recv --> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver
        3.vcl_recv --> vcl_fetch --> vcl_deliver (不走缓存)

2.varnish 3.0状态引擎包括:
    vcl_recv:接收请求,并且判断是否可以使用缓存数据;
    vcl_hash:对于从backend端取回的数据,如果可被缓存,则进行哈希计算;
    vcl_hit:对于请求的资源可以在缓存对象中直接获取;
    vcl_miss:对于请求的资源无法在缓存对象中直接获取;
    vcl_deliver:构建响应报文;
    vcl_fetch:从backend端取回数据;
    较varnish2.0新增:
        vcl_pass:对于本来可以从缓存中查找到资源明确的设置不使用缓存;多数用于私有缓存的查找策略;
        vcl_pipe:对于无法理解的请求,直接按照原样的封装直接代理至backend端;
        vcl_error:本地发生错误时,构建错误响应报文;

    varnish的处理流程:
        1.vcl_recv --> vcl_hash --> vcl_hit --> vcl_deliver
        2.vcl_recv --> vcl_hash --> vcl_hit --> vcl_pass --> vcl_fetch -->vcl_deliver
        3.vcl_recv --> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver
        4.vcl_recv --> vcl_hash --> vcl_miss --> vcl_pass --> vcl_fetch --> vcl_deliver
        5.vcl_recv --> vcl_pass --> vcl_fetch --> vcl_deliver
        6.vcl_recv --> vcl_pipe

3.varnish 4.0+状态引擎包括:
    vcl_recv:接收请求,并且判断是否可以使用缓存数据;
    vcl_hash:对于从backend端取回的数据,如果可被缓存,则进行哈希计算;
    vcl_hit:对于请求的资源可以在缓存对象中直接获取;
    vcl_miss:对于请求的资源无法在缓存对象中直接获取;
    vcl_deliver:构建响应报文;
    vcl_pass:对于本来可以从缓存中查找到资源明确的设置不使用缓存;多数用于私有缓存的查找策略;
    vcl_pipe:对于无法理解的请求,直接按照原样的封装直接代理至backend端;
    较于varnish3.0新增:
        vcl_backend_fetch:从backend端取回数据;
        vcl_backend_response:处理从backend取回的数据;
        vcl_backend_error:本地发生错误时,构建错误响应报文;
        vcl_synth:主要用于缓存修剪及信息发送;(由varnish3.0中的error变化而来)
        vcl_purge:修剪缓存;

    varnish的处理流程:
        1.vcl_recv --> vcl_hash --> vcl_hit --> vcl_deliver
        2.vcl_recv --> vcl_hash --> vcl_hit --> vcl_pass --> vcl_backend_fetch --> vcl_backend_response --> vcl_deliver
        3.vcl_recv --> vcl_hash --> vcl_pass --> vcl_backend_fetch --> vcl_backend_response --> vcl_deliver
        4.vcl_recv --> vcl_hash --> vcl_miss[ --> vcl_pass ] --> vcl_backend_fetch --> vcl_backend_response --> vcl_deliver
        5.vcl_recv --> vcl_hash --> vcl_purge --> vcl_synth
        6.vcl_recv --> vcl_hash --> vcl_pipe
        7.vcl_recv --> vcl_hash --> waiting
                                                                ↑                                   ↓
                                                                 ←←←←←

    varnish中还有两个特殊的状态引擎:
        vcl_init:
            在处理任何请求之前要调用此引擎,主要用于初始化VMODs;
        vcl_fini:
            在所有的请求都已经处理结束,在VCL的配置被丢弃时调用此引擎,主要用于清理VMODs;

VCL的语法格式:
1.与C、C++语言的语法非常相似,可以支持C、C++或perl风格的注释方式:
//, #, / ... /
2.VCL不支持循环和跳转语句;但可以是if条件分支(单分支、双分支及多分支);
if的单分支格式:
if (condition) {
...;
}
if的双分支格式:
if (condition) {
...;
} else {
...;
}
if的多分支格式:
if (condition1) {
...;
} elseif (condition2) {
...;
} else {
...;
}
3.所有的字符串内容应该放置于""之内,且不能使用换行符;
4.支持内建和自定义的ACL;
5.支持丰富的操作符:=(赋值符号), ==(等值比较), >, >=, <, <=, !, &&(与运算), ||(或运算), ~
6.使用return()关键字来决定下一个处理流程使用哪个引擎,且return()关键字无返回值;
7.支持内建变量及自定义变量,并且内建变量之间存在依赖关系,只能在特定的引擎中调用特定的内建变量;
set var_name = value
unset var_name

VCL中的内建变量:
req.:request,表示客户端发送来的请求报文相关的变量;
bereq.
:backend request,由varnish向backend端主机发送请求的相关变量;
resp.:response,由varnish响应给前端设备或客户端的响应报文的相关变量;
beresp.
:backend response,由backend主机响应给varnish的响应报文的相关变量;
obj.*:存在在缓存空间中的缓存对象相关的变量,只读;

常用的内建变量:
    req类:
        req.http.HTTP_HEADER_NAME:
            req.http.Cache-Control
            req.http.User-Agent
            req.http.Host:
            ...
        req.url:客户端发送来的请求报文中的URL相关信息;
            if (req.url ~ (?i)\.php$) {
                return(pass);
            }
        req.method:客户端发送来的请求报文中的请求资源的方法;
        req.proto:客户端发送来的请求报文中使用的http协议版本;

    bereq类:
        bereq.http.HTTP_HEADER_NAME:
            bereq.http.Cache-Control
            bereq.http.User-Agent
            bereq.http.Host:

        bereq.url:varnish向backend端发送的请求报文中的URL相关信息;
        bereq.method:varnish向backend端发送的请求报文中的请求资源的方法;
        bereq.proto:varnish向backend端发送的请求报文中使用的http协议版本;
        bereq.backend:指明要调度的后端主机;

    resp类:
        resp.http.HTTP_HEADER_NAME:
        resp.status:varnish自身向客户端发送的响应报文中的响应状态码;
        resp.proto:varnish自身向客户端发送的响应报文中的http协议版本号;

    beresp类:
        beresp.http.HTTP_HEADER_NAME:
        beresp.status:backend端主机向varnish发送的响应报文中的响应状态码;
        beresp.proto:backend端主机向varnish发送的响应报文中的http协议版本号;
        beresp.backend.name:backend端主机型varnish发送的响应报文中的主机名;
        beresp.ttl:backend端主机响应的内容剩余的可缓存时长;

    obj类:
        obj.hits:指定的对象从缓存中命中的次数;(实时数值)
        obj.miss:指定的对象从缓存中未命中的次数;(实时数值)
        obj.ttl:指定的对象在缓存中剩余有效缓存时长;

VCL的自定义变量:
定义变量:
set VAR_NAME = VALUE;
取消定义的变量:
unset VAR_NAME;
为了方便展示下面的配置示例,说一下环境:
1.在安装好的varnish缓存服务器主机上,/etc/varnish/varnish.params中修改监听的后端服务器端口号为80而不是默认的6081,其他默认就可以,方便显示;
2.在/etc/varnish/varnish.params中VARNISH_LISTEN_PORT=80,然后保存退出重启服务(重启命令:systemctl reload varnish.service)
3.iptables -F关闭防火墙;
4.setenforce 0 更改SELinux的状态,防止访问受影响;