分布式缓存
-
缓存概念
缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题。提供高性能的数据快速访问。
WebCache web 缓存,是一种缓存技术,用于临时存储(缓存)的网页文件,如 HTML 页面和图像等静态资源(此处不绝对,也可以缓存动态页面,但是存储到本地后也为静态文件),减少带宽以及后端服务器的压力,通常一个 WebCache 也是一个反向代理软件,既可以通过缓存响应用户的请求,当本地没有缓存时,可以代理用户请求至后端主机。
缓存的原理
- 将数据写入/读取速度更快的存储(设备)
- 将数据缓存到离应用最近的位置
- 将数据缓存到离用户最近的位置
缓存的类型
CDN缓存
CDN主要解决将数据缓存到离用户最近的位置,一般缓存静态资源文件(页面,脚本,图片,视频,文件等)。国内网络异常复杂,跨运营商的网络访问会很慢。为了解决跨运营商或各地用户访问问题,可以在重要的城市,部署CDN应用。使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
反向代理缓存
反向代理是指在网站服务器机房部署代理服务器,实现负载均衡,数据缓存,安全控制等功能。
分布式Cache
分布式缓存,主要指缓存用户经常访问数据的缓存,数据源为数据库。一般起到热点数据访问和减轻数据库压力的作用。
本地应用缓存
本地缓存是指应用内部的缓存,标准的分布式系统,一般有多级缓存构成。本地缓存是离应用最近的缓存,一般可以将数据缓存到硬盘或内存。
-
代理缓存
与 Redis 或者 Memcached 不同,代理缓存通常运行在代理服务器上,而前者则旁挂在后端服务器外侧,为后端服务器提供数据缓存。
缓存有效性验证机制:
如果原始内容未发生改变,则仅响应首部(不附带body部分),响应码304(Not Modified)
如果原始内容发生改变,则正常响应,响应码200
如果原始内容消失,则响应404,此时缓存中的cache object应被删除
代理缓存HTTP报文
Cache-Control:针对上述的“Expires时间是相对服务器而言,无法保证和客户端时间统一”的问题,http1.1新增了 Cache-Control 来定义缓存过期时间。注意:若报文中同时出现了 Expires 和 Cache-Control,则以 Cache-Control 为准。
语法:<span class="hljs-string">"Cache-Control" <span class="hljs-string">":" cache-directive</span></span>
当该字段值为no-cache
的时候,会知会客户端不要对该资源读缓存,即每次都得向服务器发一次请求才行。Cache-Control也是一个通用首部字段,这意味着它能分别在请求报文和响应报文中使用。
也就是说优先级从高到低分别是 Pragma -> Cache-Control -> Expires 。
Pragma:设置页面是否缓存,为Pragma则缓存,no-cache则不缓存
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match(Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
Expires:有了Pragma来禁用缓存,自然也需要有个东西来启用缓存和定义缓存时间,对 http1.0 而言,Expires 就是做这件事的首部字段。 Expires的值对应一个 GMT(格林尼治时间),如果还没过该时间点则不发请求。
Varnish
-
Varnish构架
Management
Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。 Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回 应,Management将会重启此Child进程
varnishadm 命令行接口,目前 vagent 2 为收费接口,而 telnet 是纯文本传输,所以只能使用varnishadm.Varnish 服务运行时监听在两个套接字上,一个监听前端发送来的请求(tcp:6081),另一个监听管理接口的管理命令(tcp:6082)
Child/Cache Process
Acceptor:接收新的连接请求
Worker:用于处理并响应用户请求
Expiry:从缓存中清理过期cache object
Shared Memory Log
shared memory log,共享内容日志方式存储,一般其大小为90MB,分为两部分:前一部分为计数器、后一部分为客户请求相关的数据
可以使用 varnishlog 将日志文件从内存提取到磁盘当中保存
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 命令完成。
varnish缓存功能有如下优点:
- 是基于内存缓存,重启后数据将消失;
- 利用虚拟内存方式,IO性能好。
- 支持设置0~60秒内的精确缓存时间。
- VCL配置管理比较灵活
- 32位机器上缓存文件大小最大为2G
- 具有强大的管理功能,例如top、stat、admin、list等。
- 状态机设计巧妙,结构清晰
- 利用二叉堆管理缓存文件,达到积极删除目的
-
Varnish工作原理
上图是 Varnish 官方站点提供的 varnish 工作流程图。大致总结一下可以理解为以下四种常见情况
还有两种引擎图中没有 vcl_init 与 vcl_finish 分别负责
在处理任何请求之前要执行的vcl代码:主要用于初始化VMODs
所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs
-
varnish命令
varnishd
程序选项:
-a address[:port][,address[:port][...],默认为6081端口;
-T address[:port],默认为6082端口;
-s [name=]type[,options],定义缓存存储机制;
-u user
-g group
-f config:VCL配置文件;
-F:运行于前台
varnishadm
语法:varnishadm -S 秘钥文件 -T IP地址:端口 [-t 超时时长] [-n 缓存名称]
配置文件相关:
vcl.list 列出vcl配置列表
vcl.load 装载,加载并编译
vcl.use 激活
vcl.discard 删除
vcl.show [-v] <configname> 查看指定的配置文件的详细信息
运行时参数:
param.show -l:显示列表;
param.show <PARAM>
param.set <PARAM> <VALUE>
缓存存储:
storage.list
后端服务器:
backend.list
Varnish运行时参数
在线程池内部,其每一个请求由一个线程来处理; 其worker线程的最大数决定了varnish的并发响应能力
thread_pools:线程数,最好小于或等于CPU核心数量;
thread_pool_max: 每线程池的最大线程数;
thread_pool_min:额外意义为“最大空闲线程数”;
设置方式:
vcl.param
param.set
永久有效的方法:
保存在 varnish.params 中
语法:DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"
-
Varnish日志
varnishstat
varnishstat 工具用于显示 Varnish 缓存的状态信息
选项:
-1 一次显示所有状态信息
-f 查看指定字段名称列表
[root@CentOS74 ~]# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
MAIN.cache_hit 52 0.01 Cache hits
MAIN.cache_miss 75 0.01 Cache misses
varnishtop
varnishtop 工具用于显示 Varnish 的缓存使用排名
选项:
-1 一次显示所有状态信息
-i taglist 可以同时使用多个-i选项,也可以一个选项跟上多个标签;
-I <[taglist:]regex> 对指定的标签的值基于regex进行过滤;
-x taglist 排除列表
-X <[taglist:]regex> 对指定的标签的值基于regex进行过滤,符合条件的予以排除;
varnishlog
varnishlog 工具用于显示 Varnish 的日志信息
varnishncsa
varnishncsa 工具用于显示 combined 格式的 Varnish 的日志信息
- 日志的持久化
varnishlog 和 varnishncsa 都能够以守护进程的方式运行在后台
[root@CentOS74 ~]# cat /usr/lib/systemd/system/varnishncsa.service /usr/lib/systemd/system/varnishlog.service
[Unit]
Description=Varnish Cache HTTP accelerator NCSA logging daemon
After=varnish.service
[Service]
RuntimeDirectory=varnishncsa
Type=forking
PIDFile=/run/varnishncsa/varnishncsa.pid
User=varnish
Group=varnish
ExecStart=/usr/bin/varnishncsa -a -w /var/log/varnish/varnishncsa.log -D -P /run/varnishncsa/varnishncsa.pid #可以修改日志保存的路径
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
[Unit]
Description=Varnish Cache HTTP accelerator logging daemon
After=varnish.service
[Service]
RuntimeDirectory=varnishlog
Type=forking
PIDFile=/run/varnishlog/varnishlog.pid
User=varnish
Group=varnish
ExecStart=/usr/bin/varnishlog -a -w /var/log/varnish/varnish.log -D -P /run/varnishlog/varnishlog.pid #可以定义日志保存的路径
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target