Web架构:varnish缓存代理服务器超详细剖析

来源:互联网 发布:韩国社交软件排名 编辑:程序博客网 时间:2024/06/05 17:59

Web架构:varnish缓存代理服务器超详细剖析

   小生博客:http://xsboke.blog.51cto.com

   小生 Q Q1770058260

  

 

                             -------谢谢您的参考,如有疑问,欢迎交流


目录

  • varnishi简介

  • varnish配置组成

--------------------------------------  vcl内置预设变量

--------------------------------------  功能语句与对象

--------------------------------------  varnish中内置子程序

--------------------------------------  varnish缓存模式和子程序的关系

  • varnish的安装

  • varnish实例配置解析

  • 启动varnish

  • varnish acl配置解析


一、 Varnish简介

  1. 作用

  • Web应用加速器,同时作为http反向缓存代理

  2. 特点

  • Varnish可以使用内存也可以使用硬盘进行数据缓存

  • 支持虚拟内存的使用

  • 有精确的时间管理机制

  • 状态引擎架构:通过特定的配置语言设计不同的语句

  • 以二叉堆格式管理缓存数据

  3. Varnish的优势

  • Varnish访问速度快,因为采用了“Visual Page Cache”技术,在读取数据时直接从内存中读取

  • Varnish支持更多的并发连接,因为varnishTCP连接比squid

  • Varnish通过管理端口,使用正则表达式批量的清除部分缓存

  4. Varnish的劣势

  • 进程一旦crash或重启,缓存的数据将从内存中完全释放

  • 在多台varnish实现负载均衡时,每次请求都会落到不同的varnish服务器中,造成url请求可能会穿透到后端

    1)劣势解决方案

    A、varnish的后端添加squid/nignx代理,这样防止了当varnish缓存被清空时,瞬间大量的请求发往web服务器

    B、在负载均衡上做url哈西,让单个url请求固定请求到一台varnish服务器上

  5. Varnish的组成

   1)  Management进程(管理进程)

     对child进程进行管理,同时对vcl配置进行编译

   2)  Child进程(子进程)

     生成线程池,负责处理用户请求

  6. Varnish配置组成

l  后端配置:指定后端服务器

l  ACL配置:为varnish添加访问控制列表,用于规则设置

l  Probes配置:实现后端服务器的健康检查

l  Directors配置:为varnish添加集群

l  核心子进程:为后端服务器、缓存、访问控制、错误处理等功能添

一、 arnish配置简介

  1. vcl内置预设变量

    wKiom1kL4KbDahqkAABMkJ2nolI167.jpg

  • 这些变量一般用于设置各个阶段的对象值

  • 预设变量是系统固定的,请求进入vcl子程序后便生成,这些变量可以方便子进程进行提取或者自定义

  • 格式一般为:阶段  .对象运算符值

1)阶段

  • Req:处理客户端发送的请求时使用

  • Bereq:处理varinish向后端服务器发送的请求时使用

  • Beresp:处理后端服务器响应时使用,用于varnish未缓存前

  • Resp:处理返回给客户端的响应时使用

  • Obj:处理存储在内存中的对象时使用

2)对象

     wKioL1kL4TfC3yS6AACT6s10__w253.png

     wKioL1kL4TeB4dYqAADQ4fZ_y0s853.png

     wKioL1kL4TixlNMiAADwoc7RZ6c880.png

     wKioL1kL4TjD3AiXAAB_Zr_ZwLQ697.png

     wKiom1kL4TiTbTTqAABd7s9qHTs668.png

     wKiom1kL4TnCh32nAAA_mHwJUUo104.png

   3)   运算符

     wKiom1kL4WHxG197AABRTTajxRI561.png

  2. 功能语句与对象

l  一般功能语句都用于匹配对象,就是对某个对象实现什么操作

l  格式为:功能语句(对象)

1)功能语句

  • ban():清除指定对象缓存

  • call():调用子程序

  • hash_data():生成hash键值,只能在vcl_hash子程序中使用

  • new():创建一个vcl对象,只能在vcl_init子程序中使用

  • return():结束当前子程序并执行下一步动作

  • rollback():恢复http头到原来的状态,现在使用std.rollback()代替。

  • .synthetic():合成器,用于自定义一个响应内容,只能在vcl_synthvcl_backend_error子程序中使用

  • regsub(待处理字符,正则表达式,替换为的字符):使用正则替换第一次出现的字符串

  • regsuball(待处理字符,正则表达式,替换为的字符):使用正则替换所有字符串

2)return的常用动作

  语法:returnaction

  • abandon:放弃处理,并生成一个错误。

  • deliver:交付处理

  • fetch:从后端取出响应对象

  • hash:哈希缓存处理

  • lookup:从缓存中查找应答数据并返回,如果查找不到,则调用pass函数,从后端服务器调用数据。

  • ok:继续执行

  • pass:绕过缓存,直接向后端服务器调用数据

  • pipe:建立客户端和后端服务器之间的直接连接,从后端服务器调用数据

  • purge:清除缓存对象,构建响应

  • restart:重新开始

  • retry:重试后端处理

  • synth(status code,reason):合成返回客户端状态信息

  3. varnish中内置子程序

  • 子进程也叫状态引擎,每一个状态引擎均有自己限定的返回动作  return (动作);  不同的动作将调用对应下一个状态引擎。

  • 我们可以把一个请求分为多个阶段,每个阶段都会调用不同的状态引擎去操作,这样,我们只要编写出相应的状态引擎,就可以控制每个请求阶段。

  • varnish内置子程序均有自己限定的返回动作  return (动作);  不同的动作将调用对应下一个子程序

  • 每个内置子程序都需要通过关键字sub进行定义

   1) vcl_recv子程序

     wKioL1kL4uCBA0qTAAEUxzFzS5k209.png

   2) vcl_pipe子程序

     wKiom1kL4vHz0--uAADZEDGcLy8177.png

   3) vcl_pass子程序

     wKiom1kL4w_yGr_HAAB-RDSqFdM916.png

   4) vc_hit子程序

     wKiom1kL4x-SYqUyAACZVO3LhpA814.png

   5) vcl_miss子进程

     wKiom1kL4y-xW7Z5AADEHk2i_Dw044.png

   6) vcl_hash子进程

     wKioL1kL40SDuk38AADQJLqIr0Q037.png

    7) acl_purge子进程

     wKiom1kL41XSikkGAACDRw-9Vdk429.png

   8) vcl_deliver子进程

     wKiom1kL426jWlD5AACNDf50A8s138.png

   9) vcl_backend——fetch子程序

     wKioL1kL44zgWNk5AACbED4TstM891.png

   10) vcl_backend_response子程序

     wKioL1kL46TQ7jWrAADG_NkbRD0115.png

   11) vcl_backend_error子程序

     wKiom1kL47agSn3CAADPLgM6N8E304.png

   12) vcl_synth子程序

     wKiom1kL48fxgpXJAACYIMb1FvE189.png

   13) vcl_init子进程

     wKiom1kL49mSkgTGAABr1H3wB4k680.png

   14) acl_fini子进程

     wKiom1kL4_qwL4UlAABrglTWhyg089.png

4. varnish缓存模式和子程序的关系

l  varnish的配置文件,就是通过各种子程序组成的,当varnish运行时,也是通过子程序的配置进行相应的操作

l 子程序的关系如下图

    wKioL1kL5CzyqK2MAAClLpZFocQ684.jpg

   1) 右上角的两个图代表:加载vcl时执行vcl_init子程序,卸载vcl时执行vcl_fini子程序

   2) vcl_recv调用 hash函数时

     进入该状态后,会通过vcl_hash子程序,根据请求的url或其他信息生成hash键值,

     然后查找hash键值相同的缓存数据,若找到,则进入val_hit状态,否则进入vcl_miss状态

     wKioL1kL5H_D7Wx1AAC2XO90AVg696.png

   3) vcl_recv调用pass 函数时

  • vcl_recv调用pass 函数时,pass将当前请求直接转发到后端服务器。而后续的请求仍然通过varnish处理。

  • pass varnish)通常只处理静态页面。即只在GET  HEAD 类型的请求中时才适合调用pass函数。另外,需要注意的一点是,pass模式不能处理POST请求,为什么呢?因为POST请求一般是发送数据给服务器,需要服务器接收数据,并处理数据,反馈数据。是动态的,不作缓存

     wKiom1kL5Kuzw_4UAABODR3SioQ767.jpg

   4) vcl_recv判断需要调用 pipe 函数时

  • vcl_recv判断需要调用 pipe 函数时,varnish会在客户端和服务器之间建立一条直接的连接,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到连接断开。

  • 类型是POST时用pipe,举个例子,当客户端在请求一个视频文件时,或者一个大的文档,如.zip .tar 文件,就需要用pipe模式,这些大的文件是不被缓存在varnish中的。

    wKioL1kL5Nbhh4AzAABL7FUHKOM582.jpg

   5) vcl_recv指定purge模式时

      Purge模式用于清除缓存

  5. 优雅模式garce mode

1) 请求合并

  • 当几个客户端请求同一个页面的时候,varnish只发送一个请求到后端服务器,然后让其他几个请求挂起并等待返回结果

2) 问题

  • 如果数以千计或更多的这种请求同时出现,那么这个等待队列将变得庞大,这将导致2类潜在问题:惊群问题(thundering herd problem),即突然释放大量的线程去复制后端返回的结果,将导致负载急速上升;没有用户喜欢等待;

3) 解决问题

  • 配置varnish在缓存对象因超时失效后再保留一段时间,以给那些等待的请求返回过去的文件内容(stale content)

1
2
3
4
5
6
7
8
9
10
11
12
13
14


案例:
  Sub vcl_recv {
     If (! req.backend.healthy) {        判断如果不健康
       set req.grace = 5m;varnish向前端提供5分钟的过期内容
     }
     else {                            如果健康
       set req.grace = 15s;varnish向前段提供15秒的过期内容
     }
   }
 
   sub vcl_fetch {
       set beresp.grace = 30m;将失效的缓存对象再多保留30分钟
   }

三、 varnish的安装

  1. 下载varnish压缩包

    有两个地方可下载

   1) 通过Varnish的官方网址http://varnish-cache.org,可以在这里下载最新版本的软件。

     但是有时候varnish的官网会被墙

   2) GIT下载:git clone https://github.com/varnish/Varnish-Cache/var/tmp/

     但是在安装时需要先使用./autogen.sh生成configure编译配置文件

  2. Varnish的安装

     首先安装依赖包

     wKioL1kL5pfi_b2XAABJKV1r6Y0634.jpg

     配置varnish

     wKiom1kL5qeg4RUnAABwgyQ8KhE034.jpg

     编译并安装

     wKiom1kL5rawNR_bAAArwbthObo501.jpg

     拷贝vcl文件

     wKioL1kL5sXR0iEuAAA8_Q7DY38120.jpg

     官方提供的vcl配置文件没有提示太多的配置信息,在生产环境中还是需要自己进行配置

四、 Varnish VCL实例配置解析

  拓扑环境

   wKiom1kL5uSwG7j6AAAe-r8v4R8395.png

五、 启动varnish

   wKiom1kL6eDCJvQ1AABodG4aukg512.jpg

六、 varnish vcl配置解析

   Varnish有自己的编程语法vclvarnish启动时,会将配置文件编译为C语言,然后再执行

  1. 后端服务器地址池配置及后端服务器健康检查

   1)   后端服务器定义,用于varnish连接指定的后端服务器

     wKiom1kL6g2w7qVqAAAqQPqVrpY208.png

     wKioL1kL6g3AerM3AACl-tD0CA8672.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


例:将监控块定义在后端服务器中
    backend web{
        .host="192.168.31.83";指定后端服务器的IP
        .port="80";后端服务器的暴露端口
        .probe={    直接追加监控块.probe是一个的参数
            .url="/";
            .timeout=2s;
         }
     }
或:先定义监控块,在定义后端服务器列表
    probe web_probe{    监控必需定义在前面,否则后端调用找不到监控块。
        .url="/";
        .timeout=2s;
    }
 
    backend web{
        .host="192.168.31.83";
        .port="80";
        .probe=web_probe;   调用外部共用监控块
    }

   2)   监视器定义

     wKiom1kL6sCBpf6-AAAngWf-x1c145.png

     wKiom1kL6sGQbZBYAACKRupdgE8165.png

1
2
3
4
5
6
7
8


例:创建健康监测,定义健康检查名称为backend_healthcheck
    probe backend_healthcheck {   创建名为backend_healthcheck的健康检查
       .url = "/";监控入口地址为/的
       .timeout = 1s;请求超时时间
       .interval = 5s;每次轮询间隔5秒
       .window = 5;轮询5次
       .threshold = 3;必须有3次轮询正常才算该节点正常
    }

   3)   负载均衡群集directors

  • 负载均衡群集需要directors模块的支持,import directors

  • Directors负载均衡支持的算法:

      使用randomhash 必须配置权重值,用于提高随机率

      wKioL1kL61mwuuz_AACFnqjVHUc297.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36


例:
 
    加载directors模块
    import directors;
  
    配置后端服务器
    backend web1 {
        .host = "192.168.0.10";
        .port = "80";
        .probe = backend_healthcheck;
    }
    backend web2 {
    .host = "192.168.0.11";
    .port = "80";
    .probe = backend_healthcheck;
    }
  
    初始化处理
    sub vcl_init {           
    调用vcl_init初始化子程序创建后端主机组,即directors
        new  web_cluster =directors.round_robin();
        使用new关键字创建drector对象,使用round_robin算法
        web_cluster.add_backend(web1);
        添加后端服务器节点
        web_cluster.add_backend(web2);
    }
    
    开始处理请求
    sub vcl_recv {
    调用vcl_recv子程序,用于接收和处理请求
        set req.backend_hint = web_cluster.backend();
        选取后端
    }

说明:

  • set命令是设置变量

  • unset命令是删除变量

  • web_cluster.add_backend(backend , real );  添加后端服务器节点,backend 为后端配置别名,real 为权重值,随机率计算公式:100 * (当前权重 / 总权重)

  • req.backend_hintvarnish的预定义变量,作用是指定请求后端节点

  • vcl对象需要使用new关键字创建,所有可创建对象都是内定的,使用前必需import,所有new操作只能在vcl_init子程序中。

  2. 访问控制列表(acl

  • 创建一个地址列表,用于后面的判断

  • 如果列表中包含了无法解析的主机地址,它会匹配任何地址。

  • 不想匹配的IP,在前面加个!即可

      wKioL1kL7Lyw2TTKAAAwaDCKry0843.png

  3. 缓存规则设置

wKiom1kL8MiDYr2zAALFeQrzJjM681.jpg

    说明:

  • X-Forwarded-For 是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段

  • 要想后端服务器记载客户端的真实IP,只在varnish中设置不行,还需要修改后端web服务器的配置(这里是apache做后端web服务器):

      wKioL1kL8RDTN_m8AABzX_sw6WM582.jpg

       修改框中的变量,指定为varnish中设置的变量

七、 varnish将不同的url发送到不同的后端server

 AutoIt Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


import directors;   # load the directors
backend web1 {
.host = "192.168.0.10";
.port = "80";
.probe = backend_healthcheck;
}
backend web2 {
.host = "192.168.0.11";
.port = "80";
.probe = backend_healthcheck;
}
定义后端服务器web1和web2


backend img1 {
    .host = "img1.lnmmp.com";
    .port = "80";
    .probe = backend_healthcheck;
}
backend img2 {
    .host = "img2.lnmmp.com";
    .port = "80";
    .probe = backend_healthcheck;
}
定义后端服务器img1和img2



//初始化处理
sub vcl_init {            
//调用vcl_init初始化子程序创建后端主机组,即directors
    new  web_cluster = directors.round_robin()
    //使用new关键字创建drector对象,使用round_robin算法
      web_cluster.add_backend(web1);
      //添加后端服务器节点
      web_cluster.add_backend(web2);
    new img_cluster = directors.random();
    //创建第二个集群
      img_cluster.add_backend(img1,2)
      添加后端服务器节点,并且设置权重值
      img_cluster.add_backend(img2,5);
}


//根据不同的访问域名,分发至不同的后端主机组
sub vcl_recv {
   if (req.http.host  ~  "(?i)^(www.)?benet.com$") { 
       如果请求头为www.benet.com或benet.com
         set  req.http.host = "www.benet.com";
         set  req.backend_hint = web_cluster.backend();  //选取后端
   } 
   elsif (req.http.host  ~  "(?i)^images.benet.com$") {
        set  req.backend_hint = img_cluster.backend();
    }
}
说明:中的i就是忽略大小写的意思。(?i)表示开启忽略大小写,而(?-i)表示关闭忽略大小写

本文出自 “小生blog” 博客,请务必保留此出处http://xsboke.blog.51cto.com/12096269/1922382

原创粉丝点击