centos7.3 后端主机1--192.168.1.10
centos7.3-2 后端主机2--192.168.1.8
centos7.4 varnish服务器--192.168.1.12
centos7.4-2 客户端
各个主机同步时间
ntpdate ntp1.aliyun.com
centos7.3和centos7.3(后端主机)
yum仓库为Centos-*.repo(不做改变),不用光盘做yum
yum -y install httpd php
vim /var/www/html/test.html
Test Page Backend Server1/2
vim /var/www/html/info.php
systemctl start httpd
ss -ntl 80端口
centos7.4(varnish服务器)
vim /etc/hosts
添加信息
192.168.1.10 www.fgq.com
192.168.1.8 www.feng.com
curl http://www.fgq.com/info.php ok
curl http://www.fgq.com/test.html ok
curl http://www.feng.com/info.php ok
curl http://www.feng.com/test.html ok
yum仓库为Centos-*.repo+epel源
rz 上传epel-release-latest-7.noarch.rpm
yum -y install epel-release; yum repolist; yum list varnish ok
yum -y install varnish
yum info jemalloc 此包是malloc的升级版,可提升varnish基于内存中的缓存性能
yum list all varnish*
rpm -ql varnish 看文档
varnishd -h
cp /etc/varnish/varnish.params{,.bak}
vim /etc/varnish/varnish.params 进程的工作特性--"Manager Process"
VARNISH_LISTEN_PORT=80 更改为80端口即可
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 不变
VARNISH_ADMIN_LISTEN_PORT=6082 不变
cp /etc/varnish/default.vcl{,.bak} 服务器的工作机制
vim /etc/varnish/default.vcl 服务器的工作机制--"Cacher Process"
backend default { 默认的后端主机
.host = "192.168.1.10"; 后端主机1的IP
.port = "80";
}
systemctl start varnish
ss -nlt 80和6082端口
浏览器:192.168.1.12/test.html F12:Via X-Varnish
centos7.4-2(客户端)
curl 192.168.1.12/test.html ok 访问varnish主机,跳转至后端主机1
varnish2.0
varnish4.0
vcl变量使用范围
VCL-->DSL(域专用语言--用在固定的位置)
varnish内部的域--状态引擎(state engine)--写的代码只能使用于特定状态引擎--专用
varnish收到客户端请求后,判断能否缓存:
前端(处理客户端请求)
非标准请求
是否有权限访问
无权限访问-->vcl_synth varnish自己合成的响应报文,不向后端主机请求
有权限访问-->vcl_pipe 传递用户请求给后端主机
标准请求
不能查缓存-->vcl_pass 传递用户请求给后端主机
能够查缓存-->vcl_hash
命中-->vcl_hit 直接封装响应报文并返回给客户端
未命中-->vcl_miss 直接到后端服务器获取资源
缓存清理
vcl_purge 未过期但已经更改的缓存,一次清除一个缓存项
ban 定义要清理的缓存项,支持正则表达式模式匹配
禁止使用一类未过期但已经更改缓存项
匹配到模式的内容禁止从缓存中响应,要从元数据获取
然后再次进行缓存,覆盖之前的缓存内容,达到清理缓存的效果
后端
对后端服务器的响应报文,判断资源是否允许缓存
查看服务器发送的响应报文首部(no-cache、no-storege等字段),判断是否允许缓存服务器缓存该资源:
允许--先缓存再响应给客户端
不允许--直接响应给客户端
变量--有固定位置--req.*/bereq.*/obj.*/......
上图varnish4.0中--椭圆形代表子例程,即域,也叫状态引擎;
vim /etc/varnish/default.vcl
sub vcl_recv { # ...... }
sub内容为空--不代表没有定义内容--而是有默认内容,即builtin文件(内建文件)
builtin.vcl文件内容:有许多sub子例程
vcl是域配置语言,每一个sub的作用是定义一个域
varnish -S /etc/varnish/secret -T 127.0.0.1:6082
-S /etc/varnish/secret 和服务器端使用同一个密钥文件
-T 127.0.0.1:6082 指明哪个主机和端口
help 查看命令 管理varnish客户端的命令行控制程序
status 状态
vcl.list active--状态 boot--启动时,自动加载的vcl,即default.vcl
vcl.show boot 查看boot对应的文件,即default.vcl
vcl.show -v boot 显示详细配置
req.method 请求报文的请求方法
req.http.Authorization http请求报文的指定首部
vim /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 from " + server.ip;
}
varnish_reload_vcl 重载配置文件
available 可用,但当前没用
active 当前正在使用
浏览器:192.168.1.12/test.html F12查看"响应报文"信息--刷新--再看(Miss-->Hit)
login和admin 不能查缓存,且不让varnish缓存
centos7.3(后端主机1)
mkdir /var/www/html/login
mkdir /var/www/html/admin
vim /var/www/html/login/index.html
Login Page
vim /var/www/html/admin/index.html
Admin Page
浏览器:192.168.1.12/admin F12查看"响应报文"信息--刷新--再看(Miss-->Hit)
centos7.4
vim /etc/varnish/default.vcl
在sub vcl_recv中添加信息,强制对"url是login或者admin开头"的请求不检查缓存
if (req.url ~ "(?i)^/(login|admin)") {
return(pass);
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.list
vcl.load test1 default.vcl 把后面的文件编译为test1
vcl.list 显示available-->test1(可用,但是没用)
vcl.use test1 使用test1 重新加载配置文件的另一种方法(编译+使用)
vcl.list 显示active-->test1(正在使用)
浏览器:192.168.1.12/admin F12查看"响应报文"信息--刷新--再看(一直是Miss)
192.168.1.12/login 一直是Miss,不允许查询缓存
状态引擎(state engine)--FSM 有限状态基
vcl_recv
vcl_pipe,vcl_synth,vcl_purge,vcl_hash,vcl_pass
vcl_hash
vcl_hit,vcl_miss
vcl_backend_fetch,vcl_backend_error,vcl_backend_response
vcl_deliver
工作环境不能重启主机,不能shutdown/-r,只有当重启时,不会有影响,才重启
不能用管理员账号,必要时--sudo 切换
centos7.4(varnish)
vim /etc/varnish/default.vcl
在sub vcl_recv中添加信息,传递真正的client-IP非后端主机
if (req.restarts == 0) {
if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test2 default.vcl 显示"VCL compiled",就是编译完成,没有语法错误
vcl.use test2 使用
centos 7.3(后端主机1)
tail /var/log/httpd/access_log 都是varnish服务器IP
vim /etc/httpd/conf/httpd.conf
/LogFormat--第一行--%h-->%{X-Forwarded-For}i
systemctl restart httpd
浏览器:192.168.1.12/test.html--F12--"X-cache"
centos 7.3(后端主机1)
tail /var/log/httpd/access_log 显示真正的客户端的IP
缓存对象的修剪
centos7.4(varnish)
vim /etc/varnish/default.vcl
在sub vcl_recv中添加信息if条件,同时添加sub vcl_purge信息:如下图1
if (req.method == "PURGE") {
return(purge);
}
sub vcl_purge {
return (syn(200,"Purged"));
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test3 default.vcl
vcl.use test3
浏览器:192.168.1.12/test.html--F12--"X-cache"
centos7.4-2(客户端):
curl -I 192.168.1.12/test.html 显示hit
curl -X PURGE 192.168.1.12/test.html 进行缓存清理
curl -I 192.168.1.12/test.html 第一次:Miss(请求的缓存被清理)-->第二次:hit
centos7.4(varnish)
vim /etc/varnish/default.vcl
在vcl 4.0下面添加acl控制列表信息--只有此表中的用户才可以用purge,清理缓存
acl purgers { 图2
"127.0.0.0"/8;
"192.168.1.7"; (只允许192.168.1.7--centos7.4-2客户端使用PURGE)
或者 "192.168.1.7"/16;(允许一个网段的客户端主机使用PURGE)
}
在sub vcl_recv的"if (req.method == "PURGE")"中添加信息if条件 图3
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return(synth(405,"Purging is not allowed for " + client.ip));
}
return(purge);
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test4 default.vcl
vcl.use test4
centos7.4-2(客户端):
curl -I 192.168.1.12/test.html 第一次:Miss(请求的缓存被清理)-->第二次:hit
curl -X PURGE 192.168.1.12/test.html 进行缓存清理,显示200
curl -I 192.168.1.12/test.html 第一次:Miss(请求的缓存被清理)-->第二次:hit
centos7.4-3(客户端):
curl -I 192.168.1.12/test.html 第一次:hit
curl -X PURGE 192.168.1.12/test.html 不能进行缓存清理,显示405
curl -I 192.168.1.12/test.html 第一次:hit
centos7.4(varnish)
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
ban req.url ~ ^/test 清理一类缓存
centos7.4-2或者centos7.4-3(客户端):
curl -I 192.168.1.12/test.html 第一次:Miss(请求的缓存被清理)-->第二次:hit
centos7.4(varnish)
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
ban req.url ~ ^/test 请求的url是以/test开头的文件内容,都失效
centos7.4-2或者centos7.4-3(客户端):
curl -I 192.168.1.12/test.html 第一次:Miss(请求的缓存被清理)-->第二次:hit
centos7.3(后端主机1)
for i in {1..10};do echo "Test Page $i" > /var/www/html/test$i.html;done
centos7.4-2或者centos7.4-3(客户端):
curl -I 192.168.1.12/test1.html 第一次:Miss(请求的缓存被清理)-->第二次:hit
for i in {1..10};do curl 192.168.1.12/test$i.html;done 第一次访问
for i in {1..10};do curl -I 192.168.1.12/test$i.html;done 第二次:X-cache显示hit
centos7.4(varnish)
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
ban req.url ~ ^/test 清理一类缓存
centos7.4-2或者centos7.4-3(客户端):
for i in {1..10};do curl -I 192.168.1.12/test$i.html;done 第1次:X-cache显示Miss
for i in {1..10};do curl -I 192.168.1.12/test$i.html;done 第2次:X-cache显示hit
centos7.4(varnish)
vim /etc/varnish/default.vcl
在"vcl 4.0;"中,添加acl信息 图4
acl banners {
"127.0.0.1"/8; 仅本机可以使用,操作很可怕
}
在"sub vcl_recv"中,添加信息 图5
if (req.method == "BAN") {
if (client.ip !~ banners) {
return(synth(405,"Banning is not allowed for " + client.ip));
} else {
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return(synth(200,"Ban added"));
}
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test5 default.vcl
vcl.use test5
curl -I 127.0.0.1/test1.html 第1次: X-cache显示Miss;第2次: X-cache显示hit
curl -X BAN 127.0.0.1/test1.html 显示200
curl -I 127.0.0.1/test1.html 第1次: X-cache显示Miss;第2次: X-cache显示hit
centos7.4-2或者centos7.4-3(客户端):
curl -I 192.168.1.12/test1.html 第1次: X-cache显示Miss;第2次: X-cache显示hit
curl -X BAN 192.168.1.12/test1.html 显示405
curl -I 192.168.1.12/test1.html 第1次: X-cache显示hit
centos7.4(varnish)
vim /etc/varnish/default.vcl
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.show -v test5
显示两部分
input
Builtin
分析:
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip); 命中率较低(除非确保只有一个域名或者n个域名对应的都是同一个主机)
}
return (lookup);
}
sub vcl_hit {
if (obj.ttl >= 0s) { 缓存期限--没有过期
// A pure unadultered hit, deliver it
return (deliver);
}
if (obj.ttl + obj.grace > 0s) { 缓存期限+宽限期--没有过期
// Object is in grace, deliver it
// Automatically triggers a background fetch
return (deliver);
}
// fetch & deliver once we get the result
return (fetch); 否则,到后端主机取数据
}
sub vcl_backend_response {
if (beresp.ttl <= 0s || 不能缓存响应的数据
beresp.http.Set-Cookie || 私有数据不能缓存
beresp.http.Surrogate-control ~ "no-store" || 不能缓存响应的数据
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "no-cache|no-store|private") || no-cache--需验证
beresp.http.Vary == "*") { 首部Vary,值是*--不能缓存
/*
* Mark as "Hit-For-Pass" for the next 2 minutes
*/
set beresp.ttl = 120s; 一个用户可能在2分钟内,不止一次的访问
set beresp.uncacheable = true;
}
return (deliver);
}
sub vcl_synth sub vcl_backend_error
return (deliver)--二者自己会生产响应报文,发送给客户端,不会去后端主机请求
两个特殊的状态引擎
sub vcl_init { 初始化(处理代码前,做一个初始化,加载varnish的额外模块)
return (ok); 不需要初始化
}
sub vcl_fini { 结束(所以功能结束前,做一次清理操作)
return (ok); 不需要清理
}
根据自己需求,调整可缓存时长,不可缓存对象也可以缓存下来,
缓存--较多的命中率--才有价值
后端主机不止一个--调度,轮询,健康状态做监测
图1
图2
图3
图4
图5
centos7.3--php+httpd--动态应用程序服务器--192.168.1.10--后端主机1
前面实验已经安装了php和httpd
centos7.4-3--nginx(高效服务静态内容)--图片服务器--192.168.1.13--后端主机2
centos7.4-4--nginx(高效服务静态内容)--图片服务器--192.168.1.11--后端主机3
centos7.4-2--客户端--192.168.1.7
centos7.4--varnish--192.168.1.12
前面实验已经安装
centos7.4-3(nginx-后端主机2)和centos7.4-4(后面实验做准备)后端主机3
yum -y install nginx
vim /etc/nginx/nginx.conf
更改server中的root:
root /data/web/images;
mkdir -p /data/web/images
find /usr/share/ -iname "*.jpg" -exec cp {} /data/web/images/ \;
systemctl start nginx.service
ss -nlt
centos7.4(varnish)
vim /etc/varnish/default.vcl
配置不同的后端主机
backend websrv1 {
.host = "192.168.1.10";
.port = "80";
}
backend imgsrv1 {
.host = "192.168.1.13";
.port = "80";
}
配置不同的后端主机,提供不同的服务,在"sub vcl_recv"中添加信息
if (req.url ~ "(?i)\.(jpg|jpeg|png|gif|svg)$") {
set req.backend_hint = imgsrv1;
} else {
set req.backend_hint = websrv1;
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test1 default.vcl
vcl.use test1
浏览器:
http://192.168.1.12/info.php--centos7.3后端主机1
http://192.168.1.12/test1.html ok
http://192.168.1.12/sky.jpg ok
实际环境中,两类location
1 图片请求-->varnish主机
2 php-->应用程序主机--主站的访问--index.php/index.jsp--如果可缓存--可以静态化--放在缓存服务器上
多个后端主机,varnish需要调度--需要Director模块
配置varnish使用centos7.4-4后端主机3
centos7.4(varnish)
vim /etc/varnish/default.vcl
在vcl 4.0;下面添加信息
import directors; 加载此模块
添加 backend imgsrv2 信息 如图2
backend imgsrv2 {
.host = "192.168.1.11";
.port = "80";
}
定义组
sub vcl_init {
new imgsrvs = directors.round_robin(); imgsrvs--组名 round_robin()--轮询
imgsrvs.add_backend(imgsrv1);
imgsrvs.add_backend(imgsrv2);
}
如果websrv也有很多,可以再添加一个组new websrvs = ...
sub vcl_recv更改imgsrv1为imgsrvs.backend(),发送给组,实现轮询 如图3
set req.backend_hint = imgsrvs.backend();
如果websrv也有很多,可以更改websrv1为websrvs.backend()
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test2 default.vcl
vcl.use test2
centos7.4-4后端主机3
为了显示效果
cd /data/web/images
mv sky.jpg skys.jpg
cp chess.jpg sky.jpg
centos7.4-2(客户端)
firefox 192.168.1.12/sky.jpg 图形界面
curl -X PURGE 192.168.1.12/sky.jpg(前面实验,给centos7.4-2purge权限了)
firefox 192.168.1.12/sky.jpg 两次结果不一样--轮询
真正情况下,轮询无意义,因为缓存时间
健康状态检查
centos7.3(后端主机1)
定义健康状态页
vim /var/www/html/.healthchk.html
Server1 Ok
centos7.4-3和centos7.4-4(后端主机2-3)
vim /data/web/images/.healthchk.html
Server2/3 Ok
centos7.4(varnish)
定义健康状态检查--如图4
probe healthchk {
.url = "/.healthchk.html";
.timeout = 2s;
.interval = 2s;
.window = 8;
.threshold = 5;
}
backend 后端主机中,添加".probe = healthchk;"
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test3 default.vcl
vcl.use test3
backend.list 列出后端主机-->no probe--没有检查 Healthy--检查了
centos7.4-4(后端主机3):
systemctl stop nginx.service
centos7.4(varnish):
varnishadm:backend.list 显示后端主机3--Prob--Sick
centos7.4-2(客户端):
firefox 192.168.1.12/sky.jpg 图形界面
curl -X PURGE 192.168.1.12/sky.jpg
firefox 192.168.1.12/sky.jpg 图形界面 一直都是一样的图片,后端主机3下线了
centos7.4-4(后端主机3):
systemctl start nginx.service
centos7.4(varnish):
varnishadm:backend.list 显示后端主机3--Healthy
centos7.4-2(客户端):
firefox 192.168.1.12/sky.jpg 图形界面
curl -X PURGE 192.168.1.12/sky.jpg
firefox 192.168.1.12/sky.jpg 两次结果不一样--轮询--后端主机3上线了
centos7.4(varnish) varnishadm:
backend.set_health imgsrv2 sick 手工设定为sick
backend.list 显示后端主机3--Prob--Healthy,Admin--Sick--后端主机3下线
backend.set_health imgsrv2 auto 显示Prob--Healthy,Admin--probe--后端主机3上线
backend.set_health imgsrv2 healthy 不能这样用
将来发布新产品时候,可以先把服务器标记为down,配置完成之后再使其上线
centos7.4(varnish): varnishadm:
param.show -l 详细参数
param.show thread_pools
param.show thread_pool_max
param.set thread_pools 4 设定线程池数为4个(小于等于cpu数量)--重启后失效
vim /etc/varnish/varnish.params 更改配置文件--永久有效
在最下方的添加信息
DAEMON_OPTS="-p thread_pools=4 -p thread_pool_max=10000"
设定后不允许更改--设定为只读
kv结构的日志数据--ncsa处理--httpd的combined格式的
man varnishstat
varnishstat
uptime--运行时长 mgt--管理程序
MAIN--核心配置,全局参数
MGT--控制进程相关
MEMPOOL--内存池
SMA
VBE
LCK--锁
varnishstat -l 显示参数的意义,并非值
varnishstat -l -f MAIN -f MGT -f ...
varnishstat -1 显示参数的值并退出
varnishstat -1 -f MAIN.pools -f MAIN.cache_hit -f MAIN.cache_miss -f ...
-f MAIN.pools 线程池数
-f MAIN.cache_hit 缓存命中数
-f MAIN.cache_miss 缓存没命中数
-f 引导每个参数--利用后面的监控工具展示出来
以下数值之和=客户端的请求数量
MAIN.client_req_400
MAIN.client_req_411
MAIN.client_req_413
MAIN.client_req_417
MAIN.client_req 收到的客户端正常请求
监控系统--重要服务的重要参数
varnishtop 实时记录--先开启--再访问观察--人工监控
收到某个内容的次数 ÷ 时间长度 = 速率
根据速率来排序
varnishtop -1 显示所有数据
过滤
varnishtop -i ... 指定要显示的内容(自己感兴趣的数据),先开启--再访问观察
varnishtop -i reqheader 用户请求的头部(不区分字符大小写)
varnishtop -i reqmethod 用户请求时所用的方法
varnishtop -x ... 指定的内容不显示,其他都要显示(不区分字符大小写)
varnishtop -I ... 正则表达式--显示模式匹配的内容(字符大小写--敏感)
varnishtop -I Req.*
varnishtop -I ^Req.* 值的开头,并不是我们要的标签的开头,注意
varnishtop -X ... 正则表达式--不显示模式匹配的内容--其他都显示
varnishlog 先开启--再访问观察--kv格式的日志数据--量很大--需要转化
varnishncsa combined格式(httpd日志常用格式)--kv格式的日志数据被转化了
varnishncsa -h
-a 追加
-D 守护进程
-w 指定文件名
-P 指定进程文件名
less /usr/lib/systemd/system/varnishncsa.service
此服务可以长期记录varnish的日志,不用再手工创建日志文件
systemctl start varnishncsa.service
ps aux 显示日志文件/var/log/varnish/varnishncsa.log已经创建
访问之后
tail /var/log/varnish/varnishncsa.log 生产日志
图1
图2
图3
图4
例子:
backend imgsrv1 {
.host = "192.168.10.11";
.port = "80";
}
backend imgsrv2 {
.host = "192.168.10.12";
.port = "80";
}
backend appsrv1 {
.host = "192.168.10.21";
.port = "80";
}
backend appsrv2 {
.host = "192.168.10.22";
.port = "80";
}
sub vcl_init {
new imgsrvs = directors.random();
imgsrvs.add_backend(imgsrv1,10);
imgsrvs.add_backend(imgsrv2,20);
new staticsrvs = directors.round_robin();
appsrvs.add_backend(appsrv1);
appsrvs.add_backend(appsrv2);
new appsrvs = directors.hash();
appsrvs.add_backend(appsrv1,1);
appsrvs.add_backend(appsrv2,1);
}
sub vcl_recv {
if (req.url ~ "(?i)\.(css|js)$" {
set req.backend_hint = staticsrvs.backend();
}
if (req.url ~ "(?i)\.(jpg|jpeg|png|gif)$" {
set req.backend_hint = imgsrvs.backend();
} else {
set req.backend_hint = appsrvs.backend(req.http.cookie);
}
}
缓存为王--配置缓存机制--命中率要高,否则没有价值
CDN--缓存服务器
命中
没命中--找上级或者同级服务器
贵--流量收费/月收费
LAMP
一台主机--httpd,mariadb,php
raid空间/cpu计算能力--不够用
多台主机(如下图)
--httpd(,php)--一台主机
--php--fpm-php--一台主机
--mariadb--一台主机