varnish和squid比較:
優點
varnish 採用了visual page cache技術,所有緩存的數據都是直接從內存讀取,而squid從硬盤讀取緩存的數據,所以varnish在訪問速度方面會更快一些。varnish可以支持更多的併發連接,因爲varnish的TCP連接和釋放比squid快。varnish可以通過管理端口來整理緩存,使用正則表達式就可以批量清除部分緩存。
缺點:
varnish在高併發狀態下,CPU,I/O和內存等資源的開銷高於squid。varnish的進程一旦掛起、崩潰或者重啓,緩存的數據就會從內存中釋放出來,此時的所有請求都會被髮送到後端應用程序上,在高併發的情況下,就會給後端服務器造成很大的壓力。
1、下載安裝
wget https://repo.varnish-cache.org/source/varnish-4.0.3.tar.gz
2、安裝依賴包
yum install -y python-docutils ncurses-devel pcre-devel libedit-devel libtool
3、解壓,編譯安裝
tar xf varnish-4.0.3.tar.gz
cd varnish-4.0.3
./configure --prefix=/usr/local/services/varnish -enable-debugging-symbols -enable-deve loper-warnings
-enable-dependency-tracking
make && make install
cp ./redhat/varnish.initrc /etc/init.d/varnish //啓動腳本
cp ./redhat/varnish.sysconfig /etc/sysconfig/varnish //配置文件
cp ./etc/example.vcl /usr/local/services/varnish/var/varnish/default.vcl
cat /usr/local/services/varnish/var/varnish/default.vcl
backend default { //定義後端的ip和port
.host = "192.168.1.2";
.port = "80";
}
啓動:
/usr/local/services/varnish/sbin/varnishd -f /usr/local/services/varnish/var/varnish/default.vcl -a 192.168.1.3:80 -T 192.168.224.30:2000 -S secret_file
通過訪問192.168.1.3:80,轉向後端服務上192.168.1.2:80
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模塊;
命令使用:
varnishadm
(varnishadm -T 192.168.224.30:2000 -S secret_file (遠程使用加密登錄))
load/use/discard VCL programs
ban (invalidate) cache content
change parameters
start/stop worker process
varnishhist
showing the distribution of the last N requests by their processing
Hits are marked with a pipe character ("|"), and misses are marked with a hash character ("#")
varnishncsa
The Request transaction is then scanned for the relevant parts in order to output one log line(請求log)
varnishlog
./varnishlog -g raw -i Backend_health
varnish相關日誌
varnishstat
displays statistics from a running varnishd(1) instance
varnishtest
simulate a transaction to provoke a specific behavior
varnishtop
display a ranking of requested documents, clients, user agents, or any other information which is recorded in the log
[root@master varnish]# pwd
/usr/local/services/varnish/var/varnish
[root@master varnish]# cat health_check.vcl
probe backend_healthcheck {
.url = "/";
.interval = 5s;
.timeout = 3s;
.window = 10;
.threshold = 8;
#.request =
#"GET /favicon.ico HTTP/1.1"
#"Host: www.xingyaohudong.com"
#"Connection: close"
#"Accept-Encoding: foo/bar";
}
[root@master varnish]# cat backends.vcl
import directors;
include "/usr/local/services/varnish/var/varnish/health_check.vcl";
backend d102_app_07 {
.host = "192.168.224.30";
.port = "80";
#.first_byte_timeout = 9s;
#.connect_timeout = 3s;
#.between_bytes_timeout = 1s;
.probe = backend_healthcheck;
}
sub vcl_init {
new web = directors.random(); //round-robin,fallback
web.add_backend(d102_app_07, 1);
}
[root@master varnish]# cat default.vcl
vcl 4.0;
import std;
include "/usr/local/services/varnish/var/varnish/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);
}