• varnish缓存代理配置


    一、varnish 原理:

    1)Varnish 简介:

    varnish 缓存是 web 应用加速器,同时也作为 http 反向缓存代理。你可以安装 varnish 在任何 http 的前端,同时配置它缓存内容。与传统的 squid 相比,varnish 具有性能更高、速度更 快、管理更加方便等诸多优点。有一部分企业已经在生产环境中使用其作为旧版本的 squid 的替代方案,以在相同的服务器成本下提供更好的缓存效果,Varnish 更是作为 CDN 缓存服 务器的可选服务之一。

    根据官网的介绍,Varnish 的主要特性如下:https://www.varnish-cache.org/

    1.缓存位置:可以使用内存也可以使用磁盘。如果要使用磁盘的话推荐 SSD 做 RAID1

    2.日志存储:日志也存储在内存中。存储策略:固定大小,循环使用

    3.支持虚拟内存的使用。

    4.有精确的时间管理机制,即缓存的时间属性控制。

    5.状态引擎架构:在不同的引擎上完成对不同的缓存和代理数据进行处理。可以通过特定的 配置语言设计不同的控制语句,以决定数据在不同位置以不同方式缓存,在特定的地方对经 过的报文进行特定规则的处理。

    6.缓存管理:以二叉堆格式管理缓存数据,做到数据的及时清理。

    2)Varnish 与 Squid 的对比

    相同点:

    都是一个反向代理服务器;

    都是开源软件;

    Varnish 的优势:

    1、Varnish 的稳定性很高,两者在完成相同负荷的工作时,Squid 服务器发生故障的几率要 高于 Varnish,因为使用 Squid 要经常重启;

    2、Varnish 访问速度更快,因为采用了“Visual Page Cache”技术,所有缓存数据都直接从内存 读取,而 squid 是从硬盘读取,因而 Varnish 在访问速度方面会更快;

    3、Varnish 可以支持更多的并发连接,因为 Varnish 的 TCP 连接释放要比 Squid 快,因而在 高并发连接情况下可以支持更多 TCP 连接;

    4、Varnish 可以通过管理端口,使用正则表达式批量的清除部分缓存,而 Squid 是做不到的; squid 属于是单进程使用单核 CPU,但 Varnish 是通过 fork 形式打开多进程来做处理,所以可 以合理的使用所有核来处理相应的请求;

    Varnish 的劣势:

    1、varnish 进程一旦 Crash 或者重启,缓存数据都会从内存中完全释放,此时所有请求都会 发送到后端服务器,在高并发情况下,会给后端服务器造成很大压力; 2、在 varnish 使用中如果单个 url 的请求通过 HA/F5 等负载均衡,则每次请求落在不同的 varnish 服务器中,造成请求都会被穿透到后端;而且同样的请求在多台服务器上缓存,也 会造成 varnish 的缓存的资源浪费,造成性能下降;

    Varnish 劣势的解决方案:

    针对劣势一:在访问量很大的情况下推荐使用 varnish 的内存缓存方式启动,而且后面需要 跟多台 squid/nginx 服务器。主要为了防止前面的 varnish 服 务、服务器被重启的情况下, 大量请求穿透 varnish,这样 squid/nginx 可以就担当第二层 CACHE,而且也弥补了 varnish 缓 存在内存中重启都会释放的问题;

    针对劣势二:可以在负载均衡上做 url 哈希,让单个 url 请求固定请求到一台 varnish 服务器 上;

    3)使用 varnish 作为 web 代理缓存的原理 :

    varnish 是一个 http 反向代理的缓存。它从客户端接收请求然后尝试从缓存中获取数据来响 应客户端的请求,如果 varnish 不能从缓存中获得数据来响应客户端,它将转发请求到后端 (backend servers),获取响应同时存储,最后交付给客户端。 如果 varnish 已经缓存了某个响应,它比你传统的后端服务器的响应要快很多,所以你需要 尽可能是更多的请求直接从 varnish 的缓存中获取响应。 varnish 决定是缓存内容或者是从后端服务器获取响应。后端服务器能通过 http 响应头中的 Cache-Control 来同步 varnish 缓存内容。在某些条件下 varnish 将不缓存内容,最常见的是使 用 cookie。当一个被标记有 cookie 的客户端 web 请求,varnish 默认是不缓存。这些众多的 varnish 功能特点都是可以通过写 vcl 来改变的。

    5)简单架构:

    Varnish 分为 management 进程和 child 进程;

    Management 进程:对子进程进行管理,同时对 VCL 配置进行编译,并应用到不同的状态引 擎。

    Child 进程:生成线程池,负责对用户请求进行处理,并通过 hash 查找返回用户结果。

    6)varnish 主要配置部分:

    varnish 配置主要分为:后端配置,ACL 配置,probes 配置,directors 配置,核心子程序配置 几大块。

    其中后端配置是必要的,在多台服务器中还会用到 directors 配置,核心子程序配 置。

    后端配置:即给 varnish 添加反代服务器节点,最少配置一个。

    ACL 配置:即给 varnish 添加访问控制列表,可以指定这些列表访问或禁止访问。

    probes 配置:即给 varnish 添加探测后端服务器是否正常的规则,方便切换或禁止对应后端 服务器。

    directors 配置:即给 varnish 添加负载均衡模式管理多个后端服务器。

    核心子程序配置:即给 varnish 添加后端服务器切换,请求缓存,访问控制,错误处理等规 则。

    7)VCL 中内置预设变量:变量(也叫 object):

    req:The request object,请求到达时可用的变量(客户端发送的请求对象)

    bereq:The backend request object,向后端主机请求时可用的变量

    beresp:The backend response object,从后端主机获取内容时可用的变量(后端响应请求对象)

    resp:The HTTP response object,对客户端响应时可用的变量(返回给客户端的响应对象) obj:存储在内存中时对象属性相关的可用的变量(高速缓存对象,缓存后端响应请求内容)

    预设变量是系统固定的,请求进入对应的 vcl 子程序后便生成,这些变量可以方便子程序提 取,当然也可以自定义一些全局变量。

    当前时间:

    now :作用:返回当前时间戳。

    服务器:(服务器基本信息)

    注:原 server.port 已经弃用,如果要取服务器端口号使用 std.port(server.ip),需要 import std; 才可以使用 std

    server.hostname:服务器主机名。

    server.identity:服务器身份标识。

    server.ip:返回服务器端 IP 地址。

    varnish 子程序调用流程图,通过大部分子程序的 return 返回值进入下一步行动:

    11)优雅模式(Garce mode)

    Varnish 中的请求合并 当几个客户端请求同一个页面的时候,varnish 只发送一个请求到后端服务器,然后让其他 几个请求挂起并等待返回结果;获得结果后,其它请求再复制后端的结果发送给客户端; 但如果同时有数以千计的请求,那么这个等待队列将变得庞大,这将导致 2 类潜在问题: 惊群问题(thundering herd problem),即突然释放大量的线程去复制后端返回的结果,将导致 负载急速上升;没有用户喜欢等待; 故为了解决这类问题,可以配置 varnish 在缓存对象因超时失效后再保留一段时间,以给那 些等待的请求返回过去的文件内容(stale content),配置案例如下:

    二、安装 varnish

    1、安装依赖关系的软件包(注:使用 centos 在线 yum 源)

    [root@varnish ~]# yum -y install autoconf automake libedit-devel libtool ncurses-devel pcre-devel pkgconfig python-docutils python-sphinx

    2、安装 varnish Varnish 的官方网址为 http://varnish-cache.org,可以在这里下载最新版本的软件。

    下载地址:https://www.varnish-cache.org/content/varnish-cache-403

    解压,进入解压目录编译安装:

    [root@varnish ~]# tar zxf varnish-4.0.3.tar.gz

    [root@varnish ~]# cd varnish-4.0.3/

    [root@varnish varnish-4.0.3]# ./configure

    :不指定安装路径,默认是安装在/usr/local 目录下

    编译、安装

    [root@varnish varnish-4.0.3]# make && make install

    复制 vcl 文件(在编译安装目录下),如果安装目录里没有 default.vcl 文件。

    复制到安装目录的/usr/local/var/varnish/目录下(当然并无必需要求在哪个目录,因为正式 启动时还得指定这个文件的目录)

    [root@varnish varnish-4.0.3]# cp etc/example.vcl /usr/local/var/varnish/default.vcl

    编写配置文件 把原来的配置cp下来

    #使用 varnish 版本 4 的格式.
    vcl 4.0;
    #加载后端负载均衡模块
    import directors;
    #加载 std 模块
    import std;
    #创建名为 backend_healthcheck 的健康检查策略
    probe backend_healthcheck {
      .url="/";
      .interval = 5s;
      .timeout = 1s;
      .window = 5;
      .threshold = 3;
    }
    #定义后端服务器
    backend web_app_01 {
      .host = "192.168.239.134";   (定义第一台webip)
      .port = "80";
      .first_byte_timeout = 9s;
      .connect_timeout = 3s;
      .between_bytes_timeout = 1s;
      .probe = backend_healthcheck;
    }
    backend web_app_02 {
      .host = "192.168.239.141";    (定义第二台webip)
      .port = "80";
      .first_byte_timeout = 9s;
      .connect_timeout = 3s;
      .between_bytes_timeout = 1s;
      .probe = backend_healthcheck;
    }
    #定义允许清理缓存的 IP
    acl purgers {
      "127.0.0.1";
      "localhost";
      "192.168.239.0/24"; (本网段)
    }
    #vcl_init 初始化子程序创建后端主机组
    sub vcl_init {
      new web = directors.round_robin();
      web.add_backend(web_app_01);
      web.add_backend(web_app_02);
    }
    #请求入口,用于接收和处理请求。这里一般用作路由处理,判断是否读取缓存和指定该请
    求使用哪个后端
    sub vcl_recv {
      #将请求指定使用 web 后端集群 .在集群名后加上 .backend()
      set req.backend_hint = web.backend();
      # 匹配清理缓存的请求
      if (req.method == "PURGE") {
        if (!client.ip ~ purgers) {
          return (synth(405, "Not Allowed."));
        }
        # 是的话就执行清理
        return (purge);
      }
      # 如果不是正常请求 就直接穿透没商量
      if (req.method != "GET" &&
      req.method != "HEAD" &&
      req.method != "PUT" &&
      req.method != "POST" &&
      req.method != "TRACE" &&
      req.method != "OPTIONS" &&
      req.method != "PATCH" &&
      req.method != "DELETE") {
      return (pipe);
    }
    # 如果不是 GET 和 HEAD 就跳到 pass
    if (req.method != "GET" && req.method != "HEAD") {
      return (pass);
    }
    #如果匹配动态内容访问请求就跳到 pass
    if (req.url ~ ".(php|asp|aspx|jsp|do|ashx|shtml)($|?)") {
      return (pass);
    }
    #具有身份验证的请求跳到 pass
    if (req.http.Authorization) {
      return (pass);
    }

    if (req.http.Accept-Encoding) {
    if (req.url ~
    ".(bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)$") {
          unset req.http.Accept-Encoding;
      } elseif (req.http.Accept-Encoding ~ "gzip") {
          set req.http.Accept-Encoding = "gzip";
      } elseif (req.http.Accept-Encoding ~ "deflate") {
          set req.http.Accept-Encoding = "deflate";
      } else {
          unset req.http.Accept-Encoding;
      }
    }
    if (req.url ~
    ".(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)
    ($|?)") {
      unset req.http.cookie;
      return (hash);
    }
    # 把真实客户端 IP 传递给后端服务器 后端服务器日志使用 X-Forwarded-For 来接收
    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;
      }
    }
      return (hash);
    }
    # hash 事件(缓存事件)
    sub vcl_hash {
      hash_data(req.url);
      if (req.http.host) {
        hash_data(req.http.host);
      } else {
        hash_data(server.ip);
      }
      return (lookup);
    }
    # 缓存命中事件
    sub vcl_hit {
      if (req.method == "PURGE") {
        return (synth(200, "Purged."));
      }
      return (deliver);
    }
    # 缓存不命中事件
    sub vcl_miss {
      if (req.method == "PURGE") {
        return (synth(404, "Purged."));
      }
      return (fetch);
    }
    # 返回给用户的前一个事件 通常用于添加或删除 header 头
    sub vcl_deliver {
      if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
      } else {
        set resp.http.X-Cache = "MISS";
      }
      #取消显示 php 框架版本的 header 头
      unset resp.http.X-Powered-By;
      #取消显示 web 软件版本、Via(来自 varnish)等 header 头 为了安全
      unset resp.http.Server;
      unset resp.http.X-Drupal-Cache;
      unset resp.http.Via;
      unset resp.http.Link;
      unset resp.http.X-Varnish;
      #显示请求经历 restarts 事件的次数
      set resp.http.xx_restarts_count = req.restarts;
      #显示该资源缓存的时间单位秒
      set resp.http.xx_Age = resp.http.Age;
      #显示该资源命中的次数
      set resp.http.hit_count = obj.hits;
      #取消显示 Age 为了不和 CDN 冲突
      unset resp.http.Age;
      #返回给用户
      return (deliver);
    }
    # pass 事件
    sub vcl_pass {
      return (fetch);
    }
    #处理对后端返回结果的事件(设置缓存、移除 cookie 信息、设置 header 头等) 在 fetch 事件后自动调用
    sub vcl_backend_response {
      #开启 grace 模式 表示当后端全挂掉后 即使缓存资源已过期(超过缓存时间) 也会把该
    资源返回给用户 资源最大有效时间为 5 分钟
      set beresp.grace = 5m;
      #后端返回如下错误状态码 则不缓存
      if (beresp.status == 499 || beresp.status == 404 || beresp.status == 502) {
      set beresp.uncacheable = true;
      }
      #如请求 php 或 jsp 则不缓存
      if (bereq.url ~ ".(php|jsp)(?|$)") {
        set beresp.uncacheable = true;
      } else { //自定义缓存文件的缓存时长,即 TTL 值
        if (bereq.url ~ ".(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico)($|?)") {
          set beresp.ttl = 15m;
          unset beresp.http.Set-Cookie;
        } elseif (bereq.url ~ ".(gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|?)") {
          set beresp.ttl = 30m;
          unset beresp.http.Set-Cookie;
        } else {
          set beresp.ttl = 10m;
          unset beresp.http.Set-Cookie;
        }
      }
    #返回给用户
      return (deliver);
    }
    sub vcl_purge {
      return (synth(200,"success"));
    }
    sub vcl_backend_error {
      if (beresp.status == 500 ||
        beresp.status == 501 ||
        beresp.status == 502 ||
        beresp.status == 503 ||
        beresp.status == 504) {
        return (retry);
      }
    }
    sub vcl_fini {
      return (ok);
    }

    其他两台web安装nginx:

    启动命令

    会报错往里追加uuid就行

  • 相关阅读:
    解决adb的"more than one device and emulator"错误
    Swoole实现简单的http服务器
    Unity实现物体位置变换
    Unity实现放大或缩小某个物体
    如何使用WEBSOCKET实现前后端通信
    实体类接收Date类型
    easyExce输出Excel只有表头没有数据问题解决
    报餐统计
    使用 EasyExcel 写Excel数据(表头动态)
    bladex分页
  • 原文地址:https://www.cnblogs.com/ljl1366136/p/9547023.html
Copyright © 2020-2023  润新知