Linux入门攻坚——58、varnish入门

WEB系统架构及cache基础

WEB系统架构的扩展:一个最简单的WEB系统,就是一台主机承担所有的功能,如以LAMP为例

随着用户访问量的增加,服务器端承压,响应缓慢,此时分析原因,开始扩展:

增加服务器,做负载均衡:

进一步,可能要考虑网站内容分别存放,如图片、.html、.css等静态内容与动态内容分离,数据库独立运行,然后为了加速,会增加缓存服务器,对某些内容进行缓存,数据库服务器会做成主从模式和读写模式,也可增加缓存。

一般的,服务器会先从缓存中请求响应,如果缓存中没有,由缓存服务器向后端服务器发起请求,获得响应内容后缓存,同时反馈给请求前端。

一个系统的性能瓶颈,一般是由于IO系统性能不足造成的,内存的读写速度要远高于磁盘IO的速度,在大规模并发访问的情景中,磁盘IO都会成为性能瓶颈,所以,不管是文件的读写,还是数据库的读写,解决瓶颈的一种方式就是增加中间的缓存服务器。然后是做负载均衡,增加服务器数量。

负载均衡器,可用的有lvs、nginx、HAProxy,缓存服务器,可以使用varnish、squid等,而一般缓存服务器也具有反向代理功能,需要在请求内容未命中时向后端服务器发起请求。

本次学习varnish缓存服务器。

之所以能够做缓存,是因为程序具有局部性:    时间局部性、空间局部性。

缓存一般是按照key-value,即键值对的方式保存的:
    key是访问路径,由url进行hash后的值,所以查找速度快;
    value是请求的内容值;

缓存的内容有命中率指标,即命中的请求与全部请求的比值:hit/(hit+miss)

缓存对象:具有生命周期
缓存空间耗尽:使用LRU(最近最少使用)原则,清理缓存的内容
不是所有内容都能缓存,对于用户私有数据一般不可缓存,即使要缓存,也要设置访问控制。

缓存的处理步骤(以WEB应用为例):
    接收请求 --> 解析请求(提取请求的URL及各种首部) --> 查询缓存 --> 新鲜度检测 --> 创建响应报文  --> 发送响应  --> 记录日志

新鲜度检测机制:
    过期日期:
        HTTP/1.0:Expires: Thu, 18 Dec 2025 07:11:52 GMT,这是一个绝对时间
        HTTP/1.1: Cache-Control:max-age,Cache-Control:    no-cache, no-store, max-age=0

有效性再验证:revalidate
    如果原始内容未改变,仅相应首部(不附带body部分),响应码304(Not Modified)
    如果原始内容发生改变,则正常响应,响应码200;
    如果原始内容消失,则响应404,此时缓存中的cache object也应该被删除;

条件式请求首部:
    If-Modified-Since:基于请求内容的时间戳做验证;
    If-Unmodified-Since:
    If-Match:
    If-None-Match:使用Etag判断,可能是校验码
        Etag:校验码

Cache-Control = "Cache-Control" ":" 1#cache-directive
Cache-Control:各种指令
请求:
  no-cache(不要缓存的实体,要求现在从WEB服务器去取) 
  max-age:(只接受 Age 值小于 max-age 值,并且没有过期的对象) 
  max-stale:(可以接受过去的对象,但是过期时间必须小于 max-stale 值) 
  min-fresh:(接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象) 
响应:
  public(可以用 Cached 内容回应任何用户) 
  private(只能用缓存内容回应先前请求该内容的那个用户) 
  no-cache(可以缓存,但是只有在跟WEB服务器验证了其有效后,才能返回给客户端) 
  max-age:(本响应包含的对象的过期时间) 
  ALL: no-store(不允许缓存)

常见的缓存服务解决方案:
    varnish,squid

Varnish:

Varnish 是一款高性能且开源的反向代理服务器和 HTTP 加速器,varnish的系统架构:
varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)。
Varnish Architecture:

管理进程Management:主要负责从对应的配置文件(vcl)中读取配置完成系统配置,实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。

Child(或叫做cache)进程包含多种类型的线程:
    Acceptor线程:接收新的连接请求并响应;
    Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多;
    Expiry线程:从缓存中清理过期内容;
    Command line:通过命令行接收管理child的命令接口;
    Storage/hashing:对缓存内容进行哈希和存储;
    Log/stats:日志和状态信息;
    Backend communication:与后端服务器通信;
日志:是Shared Memory Log,共享内存日志,大小一般为90MB,空间分文两部分:前一部分为计数器,后一部分为请求的相关数据;

varnish的配置文件vcl(Varnish Configuration Language)比较特殊,是一种DSL格式文件,DSL(Domain Specific Language,领域特定语言),其最终需要使用C编译器编译成二进制格式,是缓存策略配置接口,基于“域”的简单编程语言。

Varnish安装

Varnish包在epel源中:


一个高并发的服务端程序,需要随时为客户的连接请求创建会话并维持会话,这就需要不断地申请内存空间、释放内存空间,而默认Linux内核是靠内核系统调用malloc()和free()实现的,性能不高。Varnish使用jemalloc(),更加高效。

Varnish的安装后文件:

varnish的启动文件是/usr/lib/systemd/system/varnish.service

varnish如何存储缓存对象:三种方式,单个文件中,内存中,基于文件的持久存储
    file:单个文件,重启后失效,不支持持久机制;所有对象缓存在一个文件中,文件本身有自己的数据结构,形成自己的文件系统,自己识别,独立的自治域,没有key值,所以重启失效。
    malloc:内存中,速度快,空间受限,空间碎片化。
    persistent:基于文件的持久存储,重启后不会丢失;

配置varnish的三种应用:
  1、varnish应用程序的命令行参数,参看上面图片的varnish.service中的ExecStart
    监听的socket,使用的存储类型等,在varnish.params中定义;额外的配置参数
      -p param=value
      -r param,param,...:设定只读参数列表;
  2、-p选项指明的参数:是运行时参数
    可在运行中,通过CLI进行配置;
  3、vcl:配置缓存系统的缓存机制,/etc/varnish/default.vcl
    通过vcl配置文件进行配置:需要先编译,后应用,依赖于c编译器。

修改缓存类型为内存:

vcl配置文件:

其中Backend default定义后端服务器,默认指向自身的8080端口,现在修改其他的服务器:
.host  = "192.168.147.133";
.port = "80";
注意,因为vcl文件是类似C语言语法的,每条语句后面要加分号。

启动varnish
systemctl start varnish.service

服务已经启动,测试访问:

访问成功,已经转发到133上,且内容应该已经缓存到varnish中。

Varnish工具
varnishadmvarnishadm -S /etc/varnish/secret -T 127.0.0.1:6082

不太好的一点是没有提示符。

使用help,查看子命令:

ping命令,探测服务进程状态:

varnishlog:查看共享内存日志
varnishncsa:以另一种格式显示日志
varnishtop:以排序方式显示的信息
varnishstat:状态信息

vcl配置文件
varnish内部处理,有一个状态引擎处理流程,在不同的状态,进行不同的处理。

客户端请求报文request到达varnish,先由vcl_recv()接收,然后判断请求是否是可缓存的,如果不是可缓存的,那么直接转移到vcl_fetch(),由vcl_fetch()重新封装请求报文到后端服务器获取响应报文,然后转发给vcl_deliver(),由vcl_deliver()封装成新的响应报文Response返回给客户端;如果请求是可缓存的,则转移到vcl_hash(),计算key的哈希值,然后判断是否在缓存中命中,即缓存中是否有此请求所需的结果响应报文,如果没有命中,则转移至vcl_miss(),由vcl_miss()转移至vcl_fetch(),到后端服务器请求内容,然后缓存,然后转移至vcl_deliver(),封装成响应报文,返回给客户端;如果缓存命中,转移至vcl_hit(),在缓存中获取相应内容,然后直接转移至vcl_deliver(),封装为响应报文,反馈给客户端。

各引擎之间存在一定程度上的相关性;前一个engine如果有多种下游engine,则上游engine需要用return指明要转移的下游engine;

varnish还有几种状态引擎:vcl_pipe(),当请求无法被varnish所理解时,直接通过vcl_pipe()到后端服务器;vcl_pass(),当请求不能缓存时,直接通过vcl_pass(),再通过vcl_fetch()直接到后端服务器;如果出现错误,通过vcl_error(),再通过vcl_fetch()直接到后端服务器;

客户端请求到达varnish,会出现三种情况:pipe(不能理解的请求)、pass(不能缓存的请求)、lookup(可以缓存的请求)。

VCL用于定义缓存策略,而定义好的策略将由varnish的management进程分析、转换成C代码、编译成二进制程序并连接至child进程。varnish内部的各状态上可以附加通过VCL定义的策略以完成相应的缓存处理机制,因此VCL也经常被称作“域专用”语言或状态引擎,“域专用”指的是有些数据仅出现于特定的状态中。

VCL配置文件的编程语言语法:
1、注释语法://、#或/* comment */用于注释
2、由subroutine组成,即子例程构成,子例程的定义语法如下:
    sub vcl_recv {
    }
3、不支持循环
4、有众多内置的变量,变量的可调用位置与state engine有密切相关性;
5、支持终止语句,return(action);没有返回值;
6、“域”专用;
7、操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)

判断语句:
    if (CONDITION)  {
    } else {
    }
变量赋值:
    set  name=value    ;     unset  name

示例:

内置变量的使用,学过python的web编程,对这里的内置变量及其使用就会感觉很熟悉了。req相当于一个类,类中封装了各种数据,使用时用点号来取数据。req是请求报文相关数据,resp是响应报文相关数据,这两个是客户端的数据,还有一组是bereq和beresp,be是backend的意思。

新版的状态流程图:

vcl_purge()是清理缓存,清理单个目标,vcl_purge()后续是vcl_synth()。有些状态变了,如vcl_fetch()变成了vcl_backend_fetch()、vcl_backend_response()、vcl_backend_error()。

操作vcl配置文件,以/etc/varnish/default.vcl为模版:
拷贝default.vcl为test.vcl,修改:

即如果取得的对象为缓存中的,那么在响应报文首部增加X-Cache,其值为HIT,否则为MISS;
配置文件的加载与使用:

说明第一次缓存没有命中,第二次缓存命中。

Varnish中的内置变量:
变量种类:
   client、   server、  req、   resp、   bereq、   beresp、   obj、   storage

   client:封装有客户端的信息;
   server:封装有varnish服务器本身的信息;
   obj:从缓存或从后端服务器中获取的对象,其相关信息被封装于obj中;
   storage:varnish缓存存储的相关信息;

测试server:

然后vcl.load test2 test.vcl;   vcl.use test2

varnish服务器地址被添加上了。

强制某资源不从缓冲中获取:

url以/test6.html结尾的,不从缓存中获取,测试:

可以看到,多次请求都没有从缓存中获取。示例,对以/login或/admin开头的请求不从缓存中获取,不区分大小写,一般是登录请求:
if (req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {
    return(pass);  }

对特定类型的资源取消其私有的cookie标识,并强行设定其可以在varnish缓存的时长:
  if (beresp.http.cache-control !~ "s-maxage") {
    if (bereq.url ~ "(?i)\.jpg$) {
      set beresp.ttl = 60s;
      unset beresp.http.Set-Cookie;
    }
  }

backend server的定义:
  backend name {
    .attribute = "value";
  }
.host:be主机的IP
.port:be主机监听的端口
.probe:对be做健康状态检测
.max_connections:并发连接的最大数量

后端主机的健康状态检测方式:
.probe中的探测指令常用的有:
(1) .url:探测后端主机健康状态时请求的URL,默认为“/”;
(2) .request: 探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;比如:
    .request =
        "GET /.healthtest.html HTTP/1.1"
        "Host: www.test.com"
        "Connection: close";
(3) .window:设定在判定后端主机健康状态时基于最近多少次的探测进行,默认是8;
(4) .threshold:在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行;默认是3;
(5) .initial:Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;
(6) .expected_response:期望后端主机响应的状态码,默认为200;
(7) .interval:探测请求的发送周期,默认为5秒;
(8) .timeout:每次探测请求的过期时长,默认为2秒;

定义了两个backend server,同时定义了健康检测,并且实现对gif类资源与其他资源请求的分离。

定义后端服务器集群:

此时访问不同的页面,会轮询的在两个服务器中切换,达到轮询的效果,一旦访问了一个页面,再次访问时,因为缓存,都是同一个服务器的页面。

负载均衡算法:
  fallback、random、round_robin、hash

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kaoa000

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值