varnish

緩存

  • 緩存之所以能夠生效是程序的運行具有局部性特征:

    • 時間局部性:一個數據被訪問過之后,可能很快會被再次訪問到;
    • 空間局部性:一個數據被訪問時,其周邊的數據也有可能被訪問到
  • 緩存的是熱區數據

    • 時效性:

      • 緩存空間耗盡:LRU,最近最少使用;
      • 過期:緩存清理
  • 緩存命中率:hit/(hit+miss)

    • 頁面命中率:基于頁面數量進行衡量
    • 字節命中率:基于頁面的體積進行衡量
  • 緩存的數據類型

    • 私有數據:private,private cache;
    • 公共數據:public, public or private cache;
  • Cache-related Headers Fields

    The most important caching header fields are:
    
          Expires:過期時間;
              Expires:Thu, 22 Oct 2026 06:34:30 GMT
          Cache-Control:max-age=
    
          Etag
          If-None-Match
    
          Last-Modified
          If-Modified-Since
    
          Vary
          Age
    • 緩存有效性判斷機制:

      • 過期時間:Expires

        • HTTP/1.0
          Expires:過期時間
        • HTTP/1.1
          Cache-Control: maxage= 控制公共和私有緩存
          Cache-Control: s-maxage= 控制公共緩存
      • 條件式請求:

        • Last-Modified/If-Modified-Since:基于文件的修改時間戳來判別;
        • Etag/If-None-Match:基于文件的校驗碼來判別;
      • 示例:

        Expires:Thu, 13 Aug 2026 02:05:12 GMT
          Cache-Control:max-age=315360000
          ETag:"1ec5-502264e2ae4c0"
          Last-Modified:Wed, 03 Sep 2014 10:00:27 GMT
    • 緩存層級:

      • 私有緩存:用戶代理附帶的本地緩存機制;
      • 公共緩存:反向代理服務器的緩存功能;

        User-Agent <–> private cache <–> public cache <–> public cache 2 <–> Original Server

  • 請求報文用于通知緩存服務如何使用緩存響應請求:

    cache-request-directive = 
          "no-cache",                        
          | "no-store"                         
          | "max-age" "=" delta-seconds        
          | "max-stale" [ "=" delta-seconds ]  
          | "min-fresh" "=" delta-seconds      
          | "no-transform"                    
          | "only-if-cached"                  
          | cache-extension
  • 響應報文用于通知緩存服務器如何存儲上級服務器響應的內容:

    cache-response-directive =
          "public"                               
          | "private" [ "=" <"> 1#field-name <"> ] ,僅私有緩存可以響應
          | "no-cache" [ "=" <"> 1#field-name <"> ],可緩存,但響應給客戶端之前需要revalidation,即必須發出條件式請求進行緩存有效性驗正;
          | "no-store" ,不允許存儲響應內容于緩存中;                           
          | "no-transform"                        
          | "must-revalidate"                     
          | "proxy-revalidate"                  
          | "max-age" "=" delta-seconds           
          | "s-maxage" "=" delta-seconds          
          | cache-extension
  • 開源解決方案:

    • squid
      varnish

varnish

  • varnish的配置:

    • 定義進程配置
    • 緩存系統的配置
  • 程序架構:

    • Manager進程
    • Cacher進程,包含多種類型的線程:accept, worker, expiry, …
    • shared memory log:

      • 統計數據:計數器;
      • 日志區域:日志記錄;
        varnishlog, varnishncsa, varnishstat…
    • 配置接口:VCL:Varnish Configuration Language,
      vcl complier –> c complier –> shared object

  • varnish的程序環境:

    • /etc/varnish/varnish.params: 配置varnish服務進程的工作特性,例如監聽的地址和端口,緩存機制;
    • /etc/varnish/default.vcl:配置各Child/Cache線程的緩存策略;
    • 主程序:/usr/sbin/varnishd
    • CLI interface:/usr/bin/varnishadm
    • Shared Memory Log交互工具:

      • /usr/bin/varnishhist
        /usr/bin/varnishlog
        /usr/bin/varnishncsa
        /usr/bin/varnishstat
        /usr/bin/varnishtop
    • 測試工具程序:/usr/bin/varnishtest
    • VCL配置文件重載程序:/usr/sbin/varnish_reload_vcl
    • Systemd Unit File:

      • varnish服務:
        /usr/lib/systemd/system/varnish.service
      • 日志持久的服務:
        /usr/lib/systemd/system/varnishlog.service
        /usr/lib/systemd/system/varnishncsa.service
  • varnish的緩存存儲機制( Storage Types):
    -s [name=]type[,options]

    · malloc[,size]
      內存存儲,[,size]用于定義空間大?。恢貑⒑笏芯彺骓検?;
      · file[,path[,size[,granularity]]]
          磁盤文件存儲,黑盒;重啟后所有緩存項失效;
      · persistent,path,size
          文件存儲,黑盒;重啟后所有緩存項有效;實驗;
  • varnish程序的選項:

    • 程序選項:/etc/varnish/varnish.params文件
      -a address[:port][,address[:port][…],默認為6081端口;
      -T address[:port],默認為6082端口;
      -s [name=]type[,options],定義緩存存儲機制;
      -u user
      -g group
      -f config:VCL配置文件;
      -F:運行于前臺;
    • 運行時參數:/etc/varnish/varnish.params文件, DEAMON_OPTS
      DAEMON_OPTS=”-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300″

      -p param=value:設定運行參數及其值; 可重復使用多次;
      -r param[,param…]: 設定指定的參數為只讀狀態;

  • 重載vcl配置文件:
    ~ ]# varnish_reload_vcl

  • varnish的命令行:varnishadm

    ~]# varnishadm -S /etc/varnish/secret -T [ADDRESS:]PORT 
    
      help [<command>]
      ping [<timestamp>]
      auth <response>
      quit
      banner
      status
      start
      stop
      vcl.load <configname> <filename>    
      vcl.inline <configname> <quoted_VCLstring>
      vcl.use <configname>            
      vcl.discard <configname>
      vcl.list                    
      param.show [-l] [<param>]    
      param.set <param> <value>    
      panic.show
      panic.clear
      storage.list
      vcl.show [-v] <configname>        
      backend.list [<backend_expression>]        
      backend.set_health <backend_expression> <state>
      ban <field> <operator> <arg> [&& <field> <oper> <arg>]...
      ban.list
    • 配置文件相關:

      vcl.list :列出配置文件的版本
        vcl.load:裝載,加載并編譯;
        vcl.use:激活;切換使用配置文件
        vcl.discard:刪除;
        vcl.show [-v] <configname>:查看指定的配置文件的詳細信息;
    • 運行時參數:

      param.show -l:顯示內部可調的參數所有列表;
        param.show <PARAM>
        param.set <PARAM> <VALUE>    設置參數
    • 緩存存儲:

      storage.list:存儲類型
    • 后端服務器:

      backend.list :列出后端主機
        backend.set_health <backend_expression> <state>        #指定后端主機是健康還是不健康的
  • VCL

    • ”域“專有類型的配置語言;

    • state engine:狀態引擎;

    • VCL有多個狀態引擎,狀態之間存在相關性,但狀態引擎彼此間互相隔離;每個狀態引擎可使用return(x)指明關聯至哪個下一級引擎;每個狀態引擎對應于vcl文件中的一個配置段,即為subroutine

      • Client Side

        vcl_recv, vcl_pass, vcl_hit, vcl_miss, vcl_pipe, vcl_purge, vcl_synth, vcl_deliver
        
        vcl_recv:
          hash:vcl_hash
          pass: vcl_pass 
          pipe: vcl_pipe
          synth: vcl_synth
          purge: vcl_hash --> vcl_purge
        
        vcl_hash:
          lookup:
              hit: vcl_hit
              miss: vcl_miss
              pass, hit_for_pass: vcl_pass
              purge: vcl_purge
      • Backend Side:

        vcl_backend_fetch, vcl_backend_response, vcl_backend_error
      • 兩個特殊的引擎:Housekeeping

        vcl_init:在處理任何請求之前要執行的vcl代碼:主要用于初始化VMODs;
        vcl_fini:所有的請求都已經結束,在vcl配置被丟棄時調用;主要用于清理VMODs;
      • vcl_recv的默認配置:

        sub vcl_recv {
          if (req.method == "PRI") {
              /* We do not support SPDY or HTTP/2.0 */
              return (synth(405));
          }
          if (req.method != "GET" &&
          req.method != "HEAD" &&
          req.method != "PUT" &&
          req.method != "POST" &&
          req.method != "TRACE" &&
          req.method != "OPTIONS" &&
          req.method != "DELETE") {
              /* Non-RFC2616 or CONNECT which is weird. */
              return (pipe);
          }
        
          if (req.method != "GET" && req.method != "HEAD") {
              /* We only deal with GET and HEAD by default */
              return (pass);
          }
          if (req.http.Authorization || req.http.Cookie) {
              /* Not cacheable by default */
              return (pass);
          }
              return (hash);
          }
        }
    • vcl的語法格式:

      (1) VCL files start with vcl 4.0;
      (2) //, # and /* foo */ for comments;
      (3) Subroutines are declared with the sub keyword; 例如sub vcl_recv { ...};
      (4) No loops, state-limited variables(受限于引擎的內建變量);
      (5) Terminating statements with a keyword for next action as argument of the return() function, i.e.: return(action);用于實現狀態引擎轉換; 
      (6) Domain-specific;
    • The VCL Finite State Machine

      (1) Each request is processed separately;
      (2) Each request is independent from others at any given time;
      (3) States are related, but isolated;
      (4) return(action); exits one state and instructs Varnish to proceed to the next state;
      (5) Built-in VCL code is always present and appended below your own VCL;
    • 三類主要語法:

      sub subroutine {
        ...
      }
      if CONDITION {
        ...
      } else {    
        ...
      }
      return(), hash_data()
    • VCL Built-in Functions and Keywords

      • 內建函數:

        • hash_data():指明哈希計算的數據;減少差異,以提升命中率;
        • regsub(str,regex,sub):把str中被regex第一次匹配到字符串替換為sub;主要用于URL Rewrite
        • regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替換為sub;
        • return()
        • ban(expression)
        • ban_url(regex):Bans所有的其URL可以被此處的regex匹配到的緩存對象;
        • synth(status,”STRING”):purge操作;
      • Keywords:

        • call subroutine, return(action),new,set,unset
      • 操作符:

        • ==, !=, ~, >, >=, <, <=
          邏輯操作符:&&, ||, !
          變量賦值:=
      • 標志位:

        • (?i):模式匹配時不區分字符大小寫
      • 舉例:
        obj.hits是內建變量,用于保存某緩存項的從緩存中命中的次數;發送響應報文的過程中,在sub vcl_deliver中定義;

        if (obj.hits>0) {
          set resp.http.X-Cache = "HIT via " + server.ip;
        } else {
          set resp.http.X-Cache = "MISS via " + server.ip;
        }
    • 變量類型:

      • 內建變量:

        req.*:request,表示由客戶端發來的請求報文相關;
          req.http.*
              req.http.User-Agent, 
              req.http.Referer, ...
        bereq.*:由varnish發往BE主機的httpd請求相關;
          bereq.http.*
        beresp.*:由BE主機響應給varnish的響應報文相關;
          beresp.http.*
        resp.*:由varnish響應給client相關;
          resp.http.*
        obj.*:存儲在緩存空間中的緩存對象的屬性;只讀;
        • 常用變量:

          bereq.*, req.*:
            bereq.http.HEADERS
            bereq.request:請求方法;
            bereq.url:請求的url;
            bereq.proto:請求的協議版本;
            bereq.backend:指明要調用的后端主機;
          
            req.http.Cookie:客戶端的請求報文中Cookie首部的值; 
            req.http.User-Agent ~ "chrome"
          
          beresp.*, resp.*:
            beresp.http.HEADERS
            beresp.status:響應的狀態碼;
            reresp.proto:協議版本;
            beresp.backend.name:BE主機的主機名;
            beresp.ttl:BE主機響應的內容的余下的可緩存時長;
          
          obj.*
            obj.hits:此對象從緩存中命中的次數;
            obj.ttl:對象的ttl值
          
          server.*
            server.ip
            server.hostname
          client.*
            client.ip
      • 用戶自定義:

        • set
          unset
    • 示例1:強制對某類資源的請求不檢查緩存:

      vcl_recv {
        if (req.url ~ "(?i)^/(login|admin)") {
            return(pass);
        }
      }
    • 示例2:對于特定類型的資源,例如公開的圖片等,取消其私有標識,并強行設定其可以由varnish緩存的時長; 定義在vcl_backend_response中;

      if (beresp.http.cache-control !~ "s-maxage") {
        if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") {
            unset beresp.http.Set-Cookie;
            set beresp.ttl = 3600s;
        }
      }
    • 示例3:將客戶端的IP地址傳遞到后端主機,定義在vcl_recv中;

      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;
        }
      }        
      
      當只有一個變量
        變量為字符串:非空為真,空則為假;
        變量為數值型:非0為真,0則為假
    • 緩存對象的修剪:purge, ban

      • purge

        1. 能執行purge操作

          sub vcl_purge {
               return (synth(200,"Purged"));
           }
        2. 何時執行purge操作

          sub vcl_recv {
               if (req.method == "PURGE") {
                   return(purge);
               }
               ...
           }
        • 添加此類請求的訪問控制法則:

          acl purgers {
                "127.0.0.0"/8;
                "192.168.10.0"/24;
            }
          
            sub vcl_recv {
                if (req.method == "PURGE") {
                    if (!client.ip ~ purgers) {
                        return(synth(405,"Purging not allowed for " + client.ip));
                    }
                    return(purge);
                }
                ...
            }
      • Banning:

        1. varnishadm:

          ban <field> <operator> <arg>
          
           示例:
               ban req.url ~ ^/javascripts
        2. 在配置文件中定義,使用ban()函數;

          示例:
           if (req.method == "BAN") {
               ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
               # Throw a synthetic page so the request won't go to the backend.
               return(synth(200, "Ban added"));
           }
  • 如何設定使用多個后端主機:

    backend default {
          .host = "172.16.100.6";
          .port = "80";
      }
    
      backend appsrv {
          .host = "172.16.100.7";
          .port = "80";
      }
    
      sub vcl_recv {                
          if (req.url ~ "(?i)\.php$") {
              set req.backend_hint = appsrv;
          } else {
              set req.backend_hint = default;
          }    
    
          ...
      }
    • Director:

      • varnish module;
        使用前需要導入:import directors;

      • 示例:

        import directors;    # load the directors
        
        backend server1 {
          .host = 
          .port = 
        }
        backend server2 {
          .host = 
          .port = 
        }
        
        sub vcl_init {
          new GROUP_NAME = directors.round_robin();
          GROUP_NAME.add_backend(server1);
          GROUP_NAME.add_backend(server2);
        }
        
        sub vcl_recv {
          # send all traffic to the bar director:
          set req.backend_hint = GROUP_NAME.backend();
        }
      • 示例:
        設置使用多個后端主機,采用動靜分離的方式,反代至backend server

        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);
          }
        }
    • 基于cookie的session sticky:
      把來自同一用戶的信息發往同一個客戶端主機

      sub vcl_init {
        new h = directors.hash();
        h.add_backend(one, 1);   // backend 'one' with weight '1'
        h.add_backend(two, 1);   // backend 'two' with weight '1'
      }
      
      sub vcl_recv {
        // pick a backend based on the cookie header of the client
        set req.backend_hint = h.backend(req.http.cookie);
      }
  • BE Health Check:

    backend BE_NAME {
          .host =  
          .port = 
          .probe = {
              .url= 
              .timeout= 
              .interval= 
              .window=
              .threshold=
          }
      }
    • .probe:定義健康狀態檢測方法;
      .url:檢測時要請求的URL,默認為”/”;
      .request:發出的具體請求;

      .request = 
            "GET /.healthtest.html HTTP/1.1"
            "Host: www.magedu.com"
            "Connection: close"

      .window:基于最近的多少次檢查來判斷其健康狀態;
      .threshold:最近.window中定義的這么次檢查中至有.threshhold定義的次數是成功的;
      .interval:檢測頻度;
      .timeout:超時時長;
      .expected_response:期望的響應碼,默認為200;

    • 健康狀態檢測的配置方式:

      1. probe PB_NAME { }

        backend NAME = {
             .probe = PB_NAME;
             ...
         }
      2. backend NAME {.probe = {}}

        backend NAME  {
             .probe = {
                 ...
             }
         }
    • 示例(1):

      probe check {
            .url = "/.healthcheck.html";
            .window = 5;
            .threshold = 4;
            .interval = 2s;
            .timeout = 1s;
        }
      
        backend default {
            .host = "10.1.0.68";
            .port = "80";
            .probe = check;
        }
    • 示例(2):

      backend appsrv {
            .host = "10.1.0.69";
            .port = "80";
            .probe check {
                .url = "/.healthcheck.html";
                .window = 5;
                .threshold = 4;
                .interval = 2s;
                .timeout = 1s;
            }
        }
    • 設置后端的主機屬性:

      backend BE_NAME {
        ...
        .connect_timeout = 0.5s;
        .first_byte_timeout = 20s;
        .between_bytes_timeout = 5s;
        .max_connections = 50;
      }
  • varnish的運行時參數:

    • 線程模型:

      cache-worker
        cache-main
        ban lurker
        acceptor:
        epoll/kqueue:
        ...
    • 線程相關的參數:
      在線程池內部,其每一個請求由一個線程來處理; 其worker線程的最大數決定了varnish的并發響應能力;

      • thread_pools:Number of worker thread pools. 線程池數量最好小于或等于CPU核心數量;
      • thread_pool_max:The maximum number of worker threads in each pool. 每線程池的最大線程數;
      • thread_pool_min:The minimum number of worker threads in each pool. 最少線程數;額外意義為“最大空閑線程數”;

        最大并發連接數=thread_pools * thread_pool_max

      • thread_pool_timeout:Thread idle threshold. Threads in excess of thread_pool_min, which have been idle for at least this long, will be destroyed.空閑線程的超時時長,

      • thread_pool_add_delay:Wait at least this long after creating a thread.

      • thread_pool_destroy_delay:Wait this long after destroying a thread.

    • Timer相關的參數:

      • send_timeout:Send timeout for client connections. If the HTTP response hasn’t been transmitted in this many seconds the session is closed.
      • timeout_idle:Idle timeout for client connections.
      • timeout_req: Max time to receive clients request headers, measured from first non-white-space character to double CRNL.
      • cli_timeout:Timeout for the childs replies to CLI requests from the mgt_param.
    • 設置方式:

      • vcl.param
        param.set
    • 永久有效的方法:

      /etc/varnish/varnish.params
            DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"
  • varnish日志區域:

    • shared memory log

      • 計數器
        日志信息
    1. varnishstat – Varnish Cache statistics

      • -1
        -1 -f FILED_NAME
        -l:可用于-f選項指定的字段名稱列表;

        MAIN.cache_hit 
        MAIN.cache_miss
        
        # varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
        # varnishstat -l -f MAIN -f MEMPOOL
    2. varnishtop – Varnish log entry ranking

      • -1 Instead of a continously updated display, print the statistics once and exit.
        -i taglist,可以同時使用多個-i選項,也可以一個選項跟上多個標簽;
        -I <[taglist:]regex>
        -x taglist:排除列表
        -X <[taglist:]regex>
    3. varnishlog – Display Varnish logs

    4. varnishncsa – Display Varnish logs in Apache / NCSA combined log format

      開啟varnish的日志記錄:
           systemctl start varnishncsa.service
           systemctl enable varnishncsa.service
           tail /var/log/varnish/varnishncsa.log

原創文章,作者:s,如若轉載,請注明出處:http://www.www58058.com/79368

(0)
ss
上一篇 2017-07-03 21:07
下一篇 2017-07-03 21:10

相關推薦

  • 如何在CentOS 6上安裝配置Samba

    Samba主要用于windows與Linux之間的文件共享,使用SMB/CIFS協議。CentOS 6默認安裝不包括samba軟件包,所以需要我們手動進行安裝。 Step 1 >> 安裝samba [root@localhost ~]# yum install samba -y Step 2 >> 創建一個共享用戶名和密碼 [root…

    Linux干貨 2016-03-22
  • DHCP服務介紹及搭建

    DHCP服務介紹及搭建

    2018-01-16
  • 集群基本介紹

    Linux Cluster: Cluster:計算機集合,為解決某個特定問題組合起來形成的單個系統; Linux Cluster類型: LB:Load Balancing,負載均衡;主機來平均訪問的壓力。由負載均衡器和多個后端主機分擔主。 HA:High Availiablity,高可用,靠冗余節點實現;提高服務的可用性,有多個負載均衡器(和備份)來接收來自…

    Linux干貨 2016-10-30
  • 常見的單機虛擬網絡類型

    前言:   無論是互聯網還是物聯網,他們的網絡模型都是可以見的,而虛擬化和云計算中的網絡模型 要比這些模型要復雜的多,有些設備你是可以到也有一些設備你是看不到的,這給我們運維人員帶來的技術挑戰。通過學習Xen、KVM虛擬化技術,對單機虛擬網絡模型有了初步的認識,以下是我對單機虛擬網絡模型的認識。 一、NAT模型    …

    Linux干貨 2015-09-01
  • test

    test

    Linux干貨 2017-02-14
  • C語言結構體里的成員數組和指針

    單看這文章的標題,你可能會覺得好像沒什么意思。你先別下這個結論,相信這篇文章會對你理解C語言有幫助。這篇文章產生的背景是在微博上,看到@Laruence同學出了一個關于C語言的題,微博鏈接。微博截圖如下。我覺得好多人對這段代碼的理解還不夠深入,所以寫下了這篇文章。 為了方便你把代碼copy過去編譯和調試,我把代碼列在下面: final void&n…

    Linux干貨 2016-05-29
欧美性久久久久