Varnish 4.0.3詳細配置

最近在折騰varnish 4.0,話說從3.0到4.0變化挺大的,許多配置作了調整php

對比Varnish 3.x的主要改進點
(1)、徹底支持流對象;
(2)、可後臺獲取失效的對象,即Client/backend分離;
(3)、新的vanishlog查詢語言,容許對請求進行自動分組;
(4)、複雜的請求時間戳和字節計數;
(5)、安全方面的提高;
css


涉及VCL語法的改變點
(1)、vcl配置文件需明確指定版本:即在vcl文件的第一行寫上 vcl 4.0;
(2)、vcl_fetch函數被vcl_backend_response代替,且req.*再也不適用vcl_backend_response;
(3)、後端源服務器組director成爲varnish模塊,需import directors後再在vcl_init子例程中定義;
(4)、自定義的子例程(即一個sub)不能以vcl_開頭,調用使用call sub_name;
(5)、error()函數被synth()替代;
(6)、return(lookup)被return(hash)替代;
(7)、使用beresp.uncacheable建立hit_for_pss對象;
(8)、變量req.backend.healty被std.healthy(req.backend)替代;
(9)、變量req.backend被req.backend_hint替代;
(10)、關鍵字remove被unset替代;

html

詳細能夠參考:web

https://www.varnish-cache.org/docs/4.0/whats-new/upgrading.htmlvim


工做流程後端

wKioL1VeCY-DPKO0AAJMe9Ky6sI343.jpg

Varnish 分爲 master 進程和 child 進程:
Master 進程讀入存儲配置文件,調用合適的存儲類型,而後建立 / 讀入相應大小的緩存文件,接着 master 初始化管理該存儲空間的結構體,而後 fork 並監控 child 進程;
緩存

Child 進程在主線程的初始化的過程當中,將前面打開的存儲文件整個 mmap 到內存中,此時建立並初始化空閒結構體,掛到存儲管理結構體,以待分配;安全

對外管理接口分爲3種,分別是命令行接口、Telnet接口和Web接口;服務器

同時在運行過程當中修改的配置,能夠由VCL編譯器編譯成C語言,並組織成共享對象(Shared Object)交由Child進程加載使用;websocket

wKioL1VeCjXQzfqpAAGwhfW_hms381.jpg

Child 進程分配若干線程進行工做,主要包括一些管理線程和不少 worker 線程,可分爲:
Accept線程:接受請求,將請求掛在overflow隊列上;
Work線程:有多個,負責從overflow隊列上摘除請求,對請求進行處理,直到完成,而後處理下一個請求;
Epoll線程:一個請求處理稱爲一個session,在session週期內,處理完請求後,會交給Epoll處理,監聽是否還有事件發生;
Expire線程:對於緩存的object,根據過時時間,組織成二叉堆,該線程週期檢查該堆的根,處理過時的文件,對過時的數據進行刪除或重取操做;


請求處理流程

wKioL1VeC6nTO12hAALZCRVU5rE198.jpg

 

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_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模塊;


以上內容爲在他人基礎上學習總結而來,並不是所有原創,望多多指教

廢話就很少說了,如下是我目前整理出來的配置,有些參數還須要進一優化調整:

一、後端服務器健康檢查

# vim /etc/varnish/health_check.vcl

probe backend_healthcheck {
    .interval = 5s;
    .timeout = 3s;
    .window = 10;
    .threshold = 8;
    
    .request =
    "GET /favicon.ico HTTP/1.1"
    "Host: www.xxx.com"
    "Connection: close"
    "Accept-Encoding: foo/bar";
}

二、後端服務器地址池配置

# vim /etc/varnish/backends.vcl

import directors;
include "health_check.vcl";

backend d102_app_07 {
    .host = "10.0.11.145";
    .port = "80";
    
    .first_byte_timeout = 9s;
    .connect_timeout = 3s;
    .between_bytes_timeout = 1s;
    
    .probe = backend_healthcheck;
}

backend d102_app_08 {
    .host = "10.0.11.146";
    .port = "80";
    
    .first_byte_timeout = 9s;
    .connect_timeout = 3s;
    .between_bytes_timeout = 1s;
    
    .probe = backend_healthcheck;
}

sub vcl_init {
    new web = directors.random();
    
    web.add_backend(d102_app_07, 1);
    web.add_backend(d102_app_08, 1);
}

三、緩存規則主配置

# vim /etc/varnish/default.vcl

vcl 4.0;

import std;
include "backends.vcl";

acl allow_purge_cache {
    "127.0.0.1";
    "10.0.0.0"/8;
    "172.0.0.0"/8;
}

sub vcl_recv {
    if (req.method == "PURGE") {
        if (!client.ip ~ allow_purge_cache) {
            return (synth(405, "Not Allowed."));
        }
        
        return (purge);
    }
    
    set req.backend_hint = web.backend();
    
    if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") {
        return (pass);
    }
    
    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);
    }
    
    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;
        }
    }
    
    if (req.http.Cache-Control ~ "(?i)no-cache") {
        if (!(req.http.Via || req.http.User-Agent ~ "(?i)bot" || req.http.X-Purge)) {
            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);
    }
    
    if (req.method != "GET" && req.method != "HEAD") {
        return (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.http.Upgrade ~ "(?i)websocket") {
        return (pipe);
    }
    
    if (!std.healthy(req.backend_hint)) {
        unset req.http.Cookie;
    }
    
    if (req.http.x-pipe && req.restarts > 0) {
        unset req.http.x-pipe;
        return (pipe);
    }
    
    return (hash);
}

sub vcl_pipe {
    if (req.http.upgrade) {
        set bereq.http.upgrade = req.http.upgrade;
    }
    
    return (pipe);
}

sub vcl_pass {
    if (req.method == "PURGE") {
        return (synth(502, "PURGE on a passed object."));
    }
}

sub vcl_hash {
    hash_data(req.url);
    
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    
    if (req.http.Cookie) {
        hash_data(req.http.Cookie);
    }
    
    if (req.http.Accept-Encoding ~ "gzip") {
        hash_data("gzip");
    } elseif (req.http.Accept-Encoding ~ "deflate") {
        hash_data("deflate");
    }
}

sub vcl_hit {
    if (req.method == "PURGE") {
        return (synth(200, "Purged."));
    }
    
    if (obj.ttl >= 0s) {
        return (deliver);
    }
    
    if (std.healthy(req.backend_hint)) {
        if (obj.ttl + 10s > 0s) {
            return (deliver);
        } else {
            return(fetch);
        }
    } else {
        if (obj.ttl + obj.grace > 0s) {
            return (deliver);
        } else {
            return (fetch);
        }
    }
    
    return (deliver);
}

sub vcl_miss {
    if (req.method == "PURGE") {
        return (synth(404, "Purged."));
    }
    
    return (fetch);
}

sub vcl_backend_response {
    set beresp.grace = 5m;
    
    set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, ".*s-maxage=([0-9]+).*", "\1") + "s", 0s);
    if (beresp.ttl > 0s) {
        unset beresp.http.Set-Cookie;
    }
    
    if (beresp.http.Set-Cookie) {
        set beresp.uncacheable = true;
        return (deliver);
    }
    
    if (beresp.http.Cache-Control && beresp.ttl > 0s) {
        set beresp.grace = 1m;
        unset beresp.http.Set-Cookie;
    }
    
    if (beresp.http.Content-Length ~ "[0-9]{8,}") {
        set bereq.http.x-pipe = "1";
        return (retry);
    }
    
    if (bereq.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") {
        set beresp.uncacheable = true;
        return (deliver);
    }
    
    if (bereq.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {
        unset beresp.http.set-cookie;
    }
    
    if (bereq.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip|bz2|xz|7z|avi|mov|ogm|mpe?g|mk[av])(\?.*)?$") {
        unset beresp.http.set-cookie;
        set beresp.do_stream = true;
        set beresp.do_gzip = false;
    }
    
    if ((!beresp.http.Cache-Control && !beresp.http.Expires) || 
         beresp.http.Pragma ~ "no-cache" || 
         beresp.http.Cache-Control ~ "(no-cache|no-store|private)") {
        set beresp.ttl = 120s;
        set beresp.uncacheable = true;
        return (deliver);
    }
    
    if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
        set beresp.ttl = 120s;
        set beresp.uncacheable = true;
        return (deliver);
    }
    
    if (bereq.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico)($|\?)") {
        set beresp.ttl = 15m;
    } elseif (bereq.url ~ "\.(gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {
        set beresp.ttl = 30m;
    } else {
        set beresp.ttl = 10m;
    }
    
    return (deliver);
}

sub vcl_purge {
    if (req.method != "PURGE") {
        set req.http.X-Purge = "Yes";
        return (restart);
    }
}

sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT from " + req.http.host;
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
        set resp.http.X-Cache = "MISS from " + req.http.host;
    }
    
    unset resp.http.X-Powered-By;
    unset resp.http.Server;
    
    unset resp.http.Via;
    unset resp.http.X-Varnish;
    
    unset resp.http.Age;
}

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);
}

四、啓動參數配置

# vim /etc/sysconfig/varnish

NFILES=131072
MEMLOCK=25165824
NPROCS="unlimited"

RELOAD_VCL=1
VARNISH_VCL_CONF=/etc/varnish/default.vcl

VARNISH_LISTEN_ADDRESS=0.0.0.0
VARNISH_LISTEN_PORT=6081

VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082

VARNISH_SECRET_FILE=/etc/varnish/secret

VARNISH_MIN_THREADS=240
VARNISH_MAX_THREADS=4800
VARNISH_THREAD_TIMEOUT=120

VARNISH_STORAGE_SIZE=24G
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}"

VARNISH_TTL=120

DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
        -f ${VARNISH_VCL_CONF} \
        -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
        -t ${VARNISH_TTL} \
        -p thread_pools=24 \
        -p thread_pool_min=${VARNISH_MIN_THREADS} \
        -p thread_pool_max=${VARNISH_MAX_THREADS} \
        -p thread_pool_timeout=${VARNISH_THREAD_TIMEOUT} \
        -u varnish -g varnish \
        -S ${VARNISH_SECRET_FILE} \
        -s ${VARNISH_STORAGE} \
        -p timeout_idle=60 \
        -p timeout_linger=1 \
        -p http_resp_hdr_len=16k \
        -p http_max_hdr=256 \
        -p http_req_hdr_len=16k \
        -p lru_interval=120 \
        -p listen_depth=8192"

五、啓動腳本調整

# vim /etc/init.d/varnish


exec="/usr/sbin/varnishd"
修改成
exec="/usr/bin/numactl --interleave all /usr/sbin/varnishd"

相關文章
相關標籤/搜索