最近在折騰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
工做流程後端
Varnish 分爲 master 進程和 child 進程:
Master 進程讀入存儲配置文件,調用合適的存儲類型,而後建立 / 讀入相應大小的緩存文件,接着 master 初始化管理該存儲空間的結構體,而後 fork 並監控 child 進程;緩存
Child 進程在主線程的初始化的過程當中,將前面打開的存儲文件整個 mmap 到內存中,此時建立並初始化空閒結構體,掛到存儲管理結構體,以待分配;安全
對外管理接口分爲3種,分別是命令行接口、Telnet接口和Web接口;服務器
同時在運行過程當中修改的配置,能夠由VCL編譯器編譯成C語言,並組織成共享對象(Shared Object)交由Child進程加載使用;websocket
Child 進程分配若干線程進行工做,主要包括一些管理線程和不少 worker 線程,可分爲:
Accept線程:接受請求,將請求掛在overflow隊列上;
Work線程:有多個,負責從overflow隊列上摘除請求,對請求進行處理,直到完成,而後處理下一個請求;
Epoll線程:一個請求處理稱爲一個session,在session週期內,處理完請求後,會交給Epoll處理,監聽是否還有事件發生;
Expire線程:對於緩存的object,根據過時時間,組織成二叉堆,該線程週期檢查該堆的根,處理過時的文件,對過時的數據進行刪除或重取操做;
請求處理流程
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"