varnish構建高速緩存

os:
php

[root@aliyun_test html]# cat /etc/system-releasehtml

CentOS release 6.5 (Final)java

首先安裝varnish:
linux

配置好varnish源nginx

[root@aliyun_test yum.repos.d]# cat >> varnish.repo << EOFweb

> [varnish]算法

> name=varnish for enterprise linux 6vim

> baseurl=https://repo.varnish-cache.org/redhat/varnish-4.0/el6/後端

> enabled=1瀏覽器

> gpgcheck=0

> cost=500

> EOF

安裝varnish

yum -y install varnish

[root@aliyun_test html]# varnishd -V

varnishd (varnish-4.0.3 revision b8c4a34)

Copyright (c) 2006 Verdens Gang AS

Copyright (c) 2006-2014 Varnish Software AS


Built in subroutines

Varnish 處理 HTTP 請求的過程以下

Receive 狀態(vcl_recv):也就是請求處理的入口狀態,根據 VCL 規則判斷該請求應該 pass(vcl_pass)或是 pipe(vcl_pipe),仍是進入 lookup(本地查詢);

Lookup 狀態:進入該狀態後,會在 hash 表中查找數據,若找到,則進入 hit(vcl_hit)狀態,不然進入 miss(vcl_miss)狀態;

Pass(vcl_pass)狀態:在此狀態下,會直接進入後端請求,即進入 fetch(vcl_fetch)狀態;

Fetch(vcl_backend_fetch)狀態:在 fetch 狀態下,對請求進行後端獲取,發送請求,得到數據,並根據設置進行本地存儲;

Deliver(vcl_deliver)狀態:將獲取到的數據發給客戶端,而後完成本次請求;

注:Varnish4中在vcl_fetch部分略有出入,已獨立爲vcl_backend_fetch和vcl_backend_response 2個函數;

內置函數(也叫子例程)

vcl_recv:用於接收和處理請求;當請求到達併成功接收後被調用,經過判斷請求的數據來決定如何處理請求;

vcl_pipe:此函數在進入pipe模式時被調用,用於將請求直接傳遞至後端主機,並將後端響應原樣返回客戶端;

vcl_pass:此函數在進入pass模式時被調用,用於將請求直接傳遞至後端主機,但後端主機的響應並不緩存直接返回客戶端;

vcl_hit:在執行 lookup 指令後,在緩存中找到請求的內容後將自動調用該函數;

vcl_miss:在執行 lookup 指令後,在緩存中沒有找到請求的內容時自動調用該方法,此函數可用於判斷是否須要從後端服務器獲取內容;

vcl_hash:在vcl_recv調用後爲請求建立一個hash值時,調用此函數;此hash值將做爲varnish中搜索緩存對象的key;

vcl_purge:pruge操做執行後調用此函數,可用於構建一個響應;

vcl_deliver:將在緩存中找到請求的內容發送給客戶端前調用此方法;

vcl_backend_fetch:向後端主機發送請求前,調用此函數,可修改發日後端的請求;

vcl_backend_response:得到後端主機的響應後,可調用此函數;

vcl_backend_error:當從後端主機獲取源文件失敗時,調用此函數;

vcl_init:VCL加載時調用此函數,常常用於初始化varnish模塊(VMODs)

vcl_fini:當全部請求都離開當前VCL,且當前VCL被棄用時,調用此函數,常常用於清理varnish模塊;

vcl_pass:請求後端,但不進入到cache中


client---------->varnish-------------->backend severs

client------>varnish:req請求報文

varnish----->backend:bereq向後端請求

backend----->varnish:beresp後端響應給緩存服務器

varnish----->client:resp緩存響應給client

緩存處理的具體步驟:

    接受客戶端請求

    解析請求(具備代理的功能)

    查詢緩存(檢測本地緩存中是否存在對方請求的內容的副本)

    副本的新鮮度檢測(檢查本地的緩存副本是否爲最新版本)

    構建響應(代理的功能)

    發送響應

    記錄日誌


首部:

  通用首部

    Connection:close|keep-alive

    Date:日期時間

    host:請求的主機

    Pragma:no-cache

    Via:請求或響應在客戶端和服務器之間傳遞時所通過的代理

    Transfer-Encoding:消息主體的傳輸編碼方式,chunked表示採用塊編碼的方式

  請求首部

    if-modified-since

    if-none-match

    Referer:跳轉

    User-Agent:用戶的瀏覽器類型

    Host:請求的主機

    Accept-Encoding:接受的編碼方式

    Accept-Language:接受的天然語言

    Authorization:服務器發送www-authenticate時,客戶端經過此首部提供認證信息

    Accept-Charset:接受的字符集

  響應首部

    ETag:內容的擴展標籤

    Location:重定向後的新位置

    Server:服務器軟件信息

    www-authenticate:要求對客戶端進行認證

  實體首部

    Content-Encoding:內容編碼

    Content-Language:內容語言

    Content-Length:內容長度

    Content-Type:內容的MIME格式

    Expires:內容的過時時間

    Last-Modified:最後一次修改的時間


配置文件:

vi /etc/sysconfig/varnish

NFILES=131072:打開的最大文件數

NFILES=131072:默認日誌內存大小

NPROCS="unlimited":最大線程數(ulimit -u)

RELOAD_VCL=1:直接加載,不用重啓

VARNISH_LISTEN_PORT=6081:varnish服務監聽的端口,通常改成與後端web服務同樣的端口

VARNISH_ADMIN_LISTEN_PORT=6082:遠程管理接口監聽的端口

VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1:遠程管理端監聽的ip(本機varnish服務)

VARNISH_SECRET_FILE=/etc/varnish/secret:對管理接口祕鑰文件

VARNISH_MIN_THREADS=50:varnish服務開啓的最小線程

VARNISH_MAX_THREADS=1000:varnish服務開啓的最大線程

VARNISH_STORAGE_SIZE=256M:varnish服務存儲的內存大小

VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}":varnish緩存存儲的方式,malloc內存

VARNISH_TTL=120

vi /etc/varnish/default.vcl

backend default {:後端web服務器以及名稱

    .host = "127.0.0.1";:後端web服務器主機

    .port = "8080";:後端web服務器監聽的端口

}

varnish存儲緩存內容的方法:      

    一、file:自管理的文件系統,黑盒,只對當前進程有效,不支持持久機制;

    二、malloc:使用內存分配函數malloc()庫調用varnish啓動時向內存申請指定大小的空間;

    三、persisent:與file功能相同;仍處於測試期,基於文件的持久存儲。


開始配置varnish並啓動:

後端服務器:120.26.68.152端口爲8080,爲nginx

varnish服務器:120.26.68.152端口爲7480

echo "<h1> test </h1>" > /usr/share/nginx/html/index.html

配置:vim /etc/varnish/test.vcl

    設置響應是否命中

    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;

        }             ##判斷若是命中就在http響應首部設置X-Cache爲HIT,不然

                就在http響應首部設置X-Cache爲MISS。

    }

以下結果:

wKiom1e4Z-Gzki_lAAA2qTSNIHM744.jpg

Age:表示緩存的時長(這裏設置一個小時),當超過這個時長以後,請求報文會再次miss,以後的1個小時纔是hit

sub vcl_backend_response {

  set beresp.ttl = 1h;

}

vcl_backend_response:子程序爲後端響應給varnish


一些動態解析的程序文件都不可以緩存:

backend default {     ----》先定義後端服務器

    .host = "192.168.1.112";

    .port = "80";

}

sub vcl_recv {

    set req.backend_hint = default;     ---》設置使用的backend爲default

    unset req.http.Cookie;     -----》不設置客戶端請求的cookie信息

    if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)$") {   ----》匹配的是默認後端主機

      return(pass);     ----》請求的是默認後端主機,若是不先設置主機將會網頁訪問不存在

    }

}

設置默認後端效果圖:

wKioL1e5prPx0HhwAAEmfiV4IGk716.jpg

若是不先設置默認主機,效果以下:

wKioL1e5pzqBM_CyAAB9fnm18c8340.jpg-wh_50


不正常的請求不緩存   -----》在vcl_rcv子程序中

   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,不緩存

   if (req.method != "GET" && req.method !="HEAD") {

       return (pass);

    }


若是請求包含Authorization受權或Cookie認證,不緩存

   if (req.http.Authorization || req.http.Cookie) {

       return (pass);

    }


啓用壓縮,但排除一些流文件壓縮

   if (req.http.Accept-Encoding) {

           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;

       }

    }

       return (hash);

}


定義vcl_pipe函數段

sub vcl_pipe {

   return (pipe);

}

sub vcl_miss {

   return (fetch);

}


定義vcl_hash函數段

sub vcl_hash {

   hash_data(req.url);

   if (req.http.host) {      -----》若是請求host首部,利用has算法返回host首部信息

       hash_data(req.http.host);

    }else {

       hash_data(server.ip);

    }

   if (req.http.Accept-Encoding ~ "gzip") {

       hash_data ("gzip");

    }elseif (req.http.Accept-Encoding ~ "deflate") {

       hash_data ("deflate");

    }

}


sub vcl_recv {

    if (req.restarts ==0) {:剛接收到請求,或者再一次請求時,記錄客戶端首部及ip

       if (req.http.x-forwad-for) {

  set req.http.X-Forward-For = set req.http.X-Forward-For + " " client.ip;

       } else {

  set req.http.X-Forward-For = client.ip;

       }

    }

}

這裏我已經改用虛擬機測試了

varnish:192.168.1.155

nginx:192.168.1.11

隱藏後端Server系統及版本

if (resp.http.Server) {

  unset resp.http.Server;

}屬於sub vcl_deliver子程序

wKiom1e4eEugI16KAAA2KeGdMzk812.jpg

能夠看見響應報文沒有Server段了


定義兩個後端:

backend default {

    .host = "192.168.1.11";

    .port = "80";

}


backend java {

    .host = "192.168.1.12";

    .port = "80";

}

當匹配java時,選擇java後端,其餘默認選擇默認端

sub vcl_recv {

    if (req.url ~ "^/java/") {

        set req.backend_hint = java;-----》hint暗示、示意

    } else {

        set req.backend_hint = default;

    }

}

根據請求報文的主機來判斷:

sub vcl_recv {

    if (req.http.host ~ "foo.com") {

        set req.backend_hint = foo;

    } elsif (req.http.host ~ "bar.com") {

        set req.backend_hint = bar;

    }

}

sub vcl_recv {

    if (req.http.host == "foo.com" || req.http.host == "www.foo.com") {

        set req.backend_hint = foo;

    }

}


定義後端組,而且採用round robin算法和後端服務器監控檢測機制

import directors;    # load the directors

backend web1 {

  .host = "192.168.1.11";

  .port = "80";

  .probe = {

    .url = "/";

    .interval = 5s;

    .window = 5;

    .timeout = 1s;

    .threshold = 3;

  }

}


backend web2 {

  .host = "192.168.1.12";

  .port = "80";

  .probe = {

    .url = "/";

    .interval = 5s;

    .timeout = 1s;

    .window = 5;

    .threshold = 3;

  }

}


sub vcl_init {

  new nginx = directors.round_robin();  -----》nginx就是後端組的組名稱,進行輪訓

  nginx.add_backend(web1);

  nginx.add_backend(web2);

}

sub vcl_recv {

    # send all traffic to the bar director:

    set req.backend_hint = nginx.backend();

}


ACL控制列表

# Who is allowed to purge....

acl local {

    "localhost";

    "192.168.1.0"/24; /* and everyone on the local network */

    ! "192.168.1.13"; /* except for the dialin router */

}


sub vcl_recv {

  if (req.method == "PURGE") {

    if (client.ip ~ local) {

       return(purge);

    } else {

       return(synth(403, "Access denied."));

    }

  }

}

不設置請求報文的cookie信息

sub vcl_recv {

  unset req.http.Cookie;

}


不設置響應報文的cookie信息

sub vcl_backend_response {

   if (bereq.url ~ "\.(png|gif|jpg)$") {

     unset beresp.http.set-cookie;

     set beresp.ttl = 1h;

  }

}

更多信息參考:https://www.varnish-cache.org/docs/4.0

http://my.oschina.net/monkeyzhu/blog/482051

相關文章
相關標籤/搜索