Varnish詳解與實戰

1、簡介:css

Varnish 是一款高性能且開源的反向代理服務器和 HTTP 加速器,其採用全新的軟件體系機構,和如今的硬件體系緊密配合,與傳統的 squid 相比,varnish 具備穩定,且效率更高,資源佔用更少等優勢。html

Varnish的官網爲https://www.varnish-cache.org,rpm,rpm包的下載位置爲:http://repo.varnish-cache.orgweb

2、varnish結構特色:vim

一、varnish結構後端

三大部分,客戶端,varnish處理,varnish日誌。如圖緩存

 

二、varnish特色:bash

     varnish主要運行兩個進程:Management進程和Child進程(也叫Cache進程)。wKiom1QkHiqQmP9lAAM-l795Mp8500.jpg服務器

     Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔一段時間探測一下Child進程以判斷其是否正常運行,若是在指定的時長內未獲得Child進程的迴應,Mangagement將會重啓此Child進程。cookie

     Child進程包含多種類型的線程,關鍵點有:session

          Acceptor進程:接受新的鏈接請求並響應

          worker進程:child進程會爲每一個用戶啓動一個worker進程,所以,在高併發的場景中可能會出現數百個worker進程甚至更多

          Object Expiry進程:從緩存中清理過時內容

     Varnish依賴「工做區(workspace)」以下降線程在申請或修改內存時出現競爭的可能性。在varnish內部有多種不一樣的工做區,其中最關鍵的當屬用於管理會話數據的session工做區。

三、varnish日誌:

   varnish共享內存大小通常爲90M,其分爲兩部分,計數器和爲客戶端請求的數據。varnish經過varnishlog、varnishncsa、varnishstst等來分析共享內存日誌中的信息並可以以指定的方式進行顯示

四、varnish缺點:

    varnish在高併發狀態下,CPU、I/O和內存等資源的開銷高於Squid。Varnish的進程一旦掛起、崩潰或者重啓,緩存的數據都會從內存中釋放出來。此時的全部請求都會被髮送到後端應用服務器上,在高併發的狀況下,就會給後端服務器形成很大壓力。

3、varnish的工做原理及工做流程

工做原理:

    一、Varnish 與通常服務器軟件同樣,分爲master 進程和child 進程。master進程讀入存儲配置文件,調用合適的存儲類型,而後建立/ 讀入相應大小的緩存文件,接着master 初始化管理該存儲空間的結構體,而後fork 並監控child 進程。child進程在主線程的初始化的過程當中,將前面打開的存儲文件整個mmap 到內存中,此時建立並初始化空閒結構體,掛到存儲管理結構體,以待分配。child進程分配若干線程進行工做,主要包括一些管理線程和不少worker 線程。

    二、開始真正的工做,varnish的某個負責接收新HTTP 鏈接線程開始等待用戶,若是有新的HTTP鏈接過來,它總負責接收,而後喚醒某個等待中的線程,並把具體的處理過程交給它。Worker線程讀入HTTP 請求的URI,查找已有的object,若是命中則直接返回並回複用戶。若是沒有命中,則須要將所請求的內容,從後端服務器中取過來,存到緩存中,而後再回復。

    三、分配緩存的過程是這樣的:它根據所讀到object 的大小,建立相應大小的緩存文件。爲了讀寫方便,程序會把每一個object的大小變爲最接近其大小的內存頁面倍數。而後從現有的空閒存儲結構體中查找,找到最合適的大小的空閒存儲塊,分配給它。若是空閒塊沒有用完,就把多餘的內存另外組成一個空閒存儲塊,掛到管理結構體上。若是緩存已滿,就根據LRU 機制,把最舊的object 釋放掉。

    四、釋放緩存的過程是這樣的:有一個超時線程,檢測緩存中全部object 的生存期,若是超初設定的TTL(Time To Live)沒有被訪問,就刪除之,而且釋放相應的結構體及存儲內存。注意釋放時會檢查該存儲內存塊前面或後面的空閒內存塊,若是前面或後面的空閒內存和該釋放內存是連續的,就將它們合併成更大一塊內存。

    五、整個文件緩存的管理,沒有考慮文件與內存的關係,其實是將全部的object 都考慮是在內存中,若是系統內存不足,系統會自動將其換到swap 空間,而不須要varnish 程序去控制。

    官方提供的工做流程圖:

wKiom1QkHf6z7JFgAAK9XEjvvqs865.jpg

4、varnish實戰:

一、拓撲圖:

wKioL1QkHj2x31deAACFPh5Wq7A334.jpg

二、安裝配置:    
# 安裝包下載地址:
http://repo.varnish-cache.org/redhat/varnish-4.0/el6/

yum -y install varnish-3.0.5-1.el6.x86_64.rpm varnish-docs-3.0.5-1.el6.x86_64.rpm varnish-libs-3.0.5-1.el6.x86_64.rpm     
vim /etc/sysconfig/varnish # 編輯配置文件,修改以下項
VARNISH_LISTEN_PORT=80 # varnish監聽端口改成80端口
VARNISH_STORAGE_SIZE=64M # 此值根據自身狀況調整,測試環境可調低此值
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}" #使用malloc(即內存)做爲緩存對象存儲方式;
service varnish start # 啓動varnish
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 # 登陸管理命令行
varnish> vcl.list                 # 列出全部的配置
varnish> vcl.load test1 ./test.vcl  # 加載編譯新配置,test1是配置名,test.vcl是配置文件
varnish> vcl.use test1            # 使用配置,需指定配置名,當前使用的配置以最後一次vcl.use爲準
varnish> vcl.show test1           # 顯示配置內容,需指定配置名

 

三、主配置文件分析

vim /etc/varnish/default.vcl
# This is a basic VCL configuration file for varnish. See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition. Set this to point to your content
# server.
#      
import directors;    # 導入directors模塊;
probe backend_healthcheck {    # 建立健康監測機制;
    .url = "/health.html";
    .window = 5;
    .threshold = 2;
    .interval = 3s;
}
backend web1 {    # 建立後端主機;
    .host = "192.168.1.4";
    .port = "80";
    .probe = backend_healthcheck;
}
backend web2 {
    .host = "192.168.1.5";
    .port = "80";
    .probe = backend_healthcheck;
}
backend img1 {
    .host = "192.168.1.4";
    .port = "4040";
    .probe = backend_healthcheck;
}
backend img2 {
    .host = "192.168.1.5";
    .port = "4040";
    .probe = backend_healthcheck;
}
sub vcl_init {    # 建立後端主機組,即directors;
    new web_cluster = directors.random();
    web_cluster.add_backend(web1,1.0);
    web_cluster.add_backend(web2,1.0);
    new img_cluster = directors.random();
    img_cluster.add_backend(img1,1.0);
    img_cluster.add_backend(img2,1.0);
}
acl purgers {    # 定義可訪問來源IP;
        "127.0.0.1";
        "192.168.0.0"/24;
}
sub vcl_recv {
    if (req.method == "GET" && req.http.cookie) {    # 帶cookie首部的GET請求也緩存;
        return(hash);
    }
    if (req.url ~ "test.html") {    # test.html文件禁止緩存;
        return(pass);
    }
    if (req.method == "PURGE") {    # PURGE請求的處理;
        if (!client.ip ~ purgers) {
            return(synth(405,"Method not allowed"));
        }
        return(hash);
    }
    if (req.http.X-Forward-For) {    # 爲發日後端主機的請求添加X-Forward-For首部;
        set req.http.X-Forward-For = req.http.X-Forward-For + "," + client.ip;
    } else {
        set req.http.X-Forward-For = client.ip;
    }
    if (req.http.host ~ "(?i)^(www.)?lnmmp.com$") {    # 根據不一樣的訪問域名,分發至不一樣的後端主機組;
            set req.http.host = "www.lnmmp.com";
            set req.backend_hint = web_cluster.backend();
    } elsif (req.http.host ~ "(?i)^p_w_picpaths.lnmmp.com$") {
            set req.backend_hint = img_cluster.backend();
    }
    return(hash);
}
sub vcl_hit {
    if (req.method == "PURGE") {    # PURGE請求的處理;
        purge;
        return(synth(200,"Purged"));
    }
}
sub vcl_miss {
    if (req.method == "PURGE") {    # PURGE請求的處理;
        purge;
        return(synth(404,"Not in cache"));
    }
}
sub vcl_pass {
    if (req.method == "PURGE") {    # PURGE請求的處理;
        return(synth(502,"PURGE on a passed object"));
    }
}
sub vcl_backend_response {     # 自定義緩存文件的緩存時長,即TTL值;
        if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") {
                set beresp.ttl = 7200s;
        }
        if (bereq.url ~ "\.(html|css|js)$") {
                set beresp.ttl = 1200s;
        }
    if (beresp.http.Set-Cookie) {    # 定義帶Set-Cookie首部的後端響應不緩存,直接返回給客戶端;
        return(deliver);
    }
}
sub vcl_deliver {
    if (obj.hits > 0) {    # 爲響應添加X-Cache首部,顯示緩存是否命中;
        set resp.http.X-Cache = "HIT from " + server.ip;
    } else {
        set resp.http.X-Cache = "MISS";
    }
}

 

四、測試結果:

wKioL1QkHpWTA-cDAAEbftskjis556.jpg

相關文章
相關標籤/搜索