1. 程式人生 > >高性能HTTP加速器Varnish安裝與配置(包含常見錯誤)

高性能HTTP加速器Varnish安裝與配置(包含常見錯誤)

人員 準備 版本 狀態碼 port pop 沒有 gis for

Varnish是一款高性能的開源HTTP加速器。挪威最大的在線報紙Verdens Gang使用3臺Varnish取代了原來的12臺Squid,性能竟然比曾經更好。Varnish 的作者Poul-Henning Kamp是FreeBSD的內核開發人員之中的一個。他覺得如今的計算機比起1975年已經復雜很多。在1975年時。儲存媒介僅僅有兩種:內存與硬盤。但如今計算機系統的內存除了主存外,還包含了cpu內的L1、L2,甚至有L3快取。

硬盤上也有自己的快取裝置。因此Squid cache自行處理物件替換的架構不可能得知這些情況而做到最佳化。但操作系統能夠得知這些情況。所以這部份的工作應該交給操作系統處理。這就是Varnish cache設計架構。眼下非常多互聯網公司在使用Varnish。當中包含Facebook。

特性:

  • VCL(Varnish Configuration Language):差別於其它系統。Varnish採用了自身的配置語言來配置,很easy上手,這些配置會被編譯成二進制機器碼,明顯加快了運行速度。
  • Health checks:完好的健康檢查機制。
  • ESI(Edge Side Includes):在HTML中嵌入動態腳本文件。
  • Directors:後端server的調度方式:random,round-robin。client,hash,DNS。
  • Purging and banning:強大的緩存清除功能。能夠以正則表達式的形式清除緩存。
  • Logging in Varnish:Varnish的log不是記錄在文件裏的,而是記錄在共享內存中。

    當日誌大小達到分配的共享內存容量,覆蓋掉舊的日誌。以這樣的方式記錄日誌比文件的形式要快非常多,而且不須要磁盤空間。

  • 豐富的管理程序:varnishadm,varnishtop,varnishhist,varnishstat以及varnishlog等。

環境:CentOS 6.5


首先安裝ncurses-devel,否則varnishstat,varnishtop都無法編譯完畢
yum install ncurses-devel
安裝Varnish
wget https://repo.varnish-cache.org/source/varnish-4.0.1.tar.gz
tar -zxvf varnish-4.0.1.tar.gz
cd varnish-4.0.1
./configure --prefix=/usr/local/varnish
make && make install
可能會報的錯: No package ‘libpcre‘ found 錯誤 解決的方法:export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig。然後繼續編譯
開啟Varnish
/usr/local/varnish-2.1.5/sbin/varnishd -f /usr/local/varnish-2.1.5/etc/varnish/default.vcl -T 127.0.0.1:2000 -a 0.0.0.0:80 -s file,/tmp,200M
當中-f用來指定配置文件,-T指定管理臺的訪問地址。-a指定Varnish監聽地址,-s指定Varnish以文件方式來緩存資源,地址為/tmp,大小200MB。
可能會報的錯:
Message from VCC-compiler:
No backends or directors found in VCL program, at least one is necessary.
Running VCC-compiler failed, exit 1
VCL compilation failed
解決的方法:沒有設置varnish配置文件
配置文件(能夠配置多個後端處理器,以輪詢方式實現負載均衡)
backend default {
	.host = "127.0.0.1";
	.port = "8080";
	.connect_timeout = 5s;
	.first_byte_timeout= 5s;
	.probe = {
        #health check
        .url = "/check.txt";
        .interval = 5s;
        .timeout = 5s;
        .window = 5;
        .threshold = 3;
    }
}

sub vcl_recv {
    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.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }
    if (req.request != "GET" && req.request != "HEAD") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }
    if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }
    return (lookup);
}

sub vcl_pipe {
    # Note that only the first request to the backend will have
    # X-Forwarded-For set.  If you use X-Forwarded-For and want to
    # have it set for all requests, make sure to have:
    # set bereq.http.connection = "close";
    # here.  It is not set by default as it might break some broken web
    # applications, like IIS with NTLM authentication.
    return (pipe);
}

sub vcl_pass {
    return (pass);
}

sub vcl_hash {
    set req.hash += req.url;
    if (req.http.host) {
        set req.hash += req.http.host;
    } else {
        set req.hash += server.ip;
    }
    return (hash);
}

sub vcl_hit {
    if (!obj.cacheable) {
        return (pass);
    }
    return (deliver);
}

sub vcl_miss {
    return (fetch);
}

sub vcl_fetch {
    if (!beresp.cacheable) {
        return (pass);
    }
    if (beresp.http.Set-Cookie) {
        return (pass);
    }
    return (deliver);
}

sub vcl_deliver {
    return (deliver);
}

sub vcl_error {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>"} obj.status " " obj.response {"</title>
  </head>
  <body>
    <h1>Error "} obj.status " " obj.response {"</h1>
    <p>"} obj.response {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} req.xid {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};
    return (deliver);
}

啟動腳本
wget -O varnishd https://raw.github.com/gist/3671408/3a51578bbd60a4cf8317bdc9508527b81eb23da5/varnishd
cp varnishd /etc/init.d/varnishd
chmod +x /etc/init.d/varnishd
/etc/init.d/varnishd start

Subroutine列表

  • vcl_recv 在請求開始時候被調用,在請求已經被接收到而且解析後調用。

    目的就是決定是否處理這個請求,怎麽處理,使用哪個後端。vcl_recv以return結束,參數能夠為例如以下keyword:
    error code [reason]:返回錯誤碼給client,丟棄請求。


    pass:轉換到pass模式。

    控制權最後會轉移到vcl_pass
    pipe:轉換到pipe模式。控制權最後會轉移到vcl_pipe
    lookup:在緩存中尋找請求對象。

    控制權最後會轉移到vcl_hit或者vcl_miss。決定於對象是否在緩存中。

  • vcl_pipe 當進入pipe模式的時候被調用。

    在這個模式中,請求會被轉移到後端。興許的數據無論是從client還是後端來的都會以不變的方式傳送,直到連接關閉為止。vcl_pipe以return結束,參數能夠為例如以下keyword:
    error code [reason]:返回錯誤碼給client,丟棄請求。
    pipe:以pipe模式運行。

  • vcl_pass 當進入pass模式的時候會被調用。在這個模式中,請求會被傳送到後端,然後後端的響應會被傳送回client,可是響應不會進入緩存中。接下來通過同樣client連接發起的請求會以普通的方式來處理。vcl_pass以return結束。參數能夠為例如以下keyword:
    error code [reason]:返回錯誤碼給client。丟棄請求。
    pass:以pass模式運行。
    restart:又一次啟動這個事務。添加了重新啟動計數。

    假設重新啟動的次數高於max_restarts,varnish會引起一個錯誤。

  • vcl_hash 你假設把想把數據增加到hash中,那麽調用hash_data()。vcl_hash以return結束,參數能夠為例如以下keyword:
    hash:運行hash邏輯。

  • vcl_hit 假設請求的對象在緩存中被找到了,那麽在緩存查找結束後被調用。vcl_hit以return結束。參數能夠為例如以下keyword:
    deliver:deliver緩存對象到client。控制權最後會轉移到vcl_deliver


    error code [reason]:返回錯誤碼給client,丟棄請求。
    pass:切換到pass模式。

    控制權最後會轉移到vcl_pass
    restart:又一次啟動這個事務。添加了重新啟動計數。

    假設重新啟動的次數高於max_restarts,varnish會引起一個錯誤。

  • vcl_miss 假設請求的對象在緩存中沒有被找到,那麽在緩存查找結束後被調用。

    目的是為了決定是否去後端獲取這個請求對象,而且要選擇哪個後端。vcl_miss以return結束,參數能夠為例如以下keyword:
    error code [reason]:返回錯誤碼給client,丟棄請求。
    pass:切換到pass模式。

    控制權最後會轉移到vcl_pass
    fetch:去後端獲取請求對象。控制權最後會轉移到vcl_fetch

  • vcl_fetch 當一個對象被成功從後端獲取的時候此方法會被調用。

    vcl_fetch以return結束,參數能夠為例如以下keyword:
    deliver:可能把對象放入緩存中,然後再deliver到client。

    控制權最後會轉移到vcl_deliver
    error code [reason]:返回錯誤碼給client,丟棄請求。
    esi:以ESI形式來處理剛剛被獲取到的對象。
    pass:切換到pass模式。控制權最後會轉移到vcl_pass


    restart:又一次啟動這個事務。

    添加了重新啟動計數。假設重新啟動的次數高於max_restarts。varnish會引起一個錯誤。

  • vcl_deliver當一個緩存的對象被deliver到client的時候,此方法會被調用。vcl_deliver以return結束,參數能夠為例如以下keyword:
    deliver:發送對象到client。
    error code [reason]:返回錯誤碼給client,丟棄請求。
    restart:又一次啟動這個事務,添加重新啟動計數。假設重新啟動的次數高於max_restarts,varnish會引起一個錯誤。

  • vcl_error 當遇見一個錯誤的時候會被調用,錯誤可能是跟後端有關系或者內部錯誤。vcl_error以return結束,參數能夠為例如以下keyword:
    deliver:發送對象到client。


    restart:又一次啟動這個事務,添加重新啟動計數。假設重新啟動的次數高於max_restarts。varnish會引起一個錯誤。

重要變量

subroutine不帶參數,一般通過全局變量來實現信息的傳遞。

例如以下變量在backend中有效:

  • .host:backend的主機名或者IP。

  • .port:backend的端口。

例如以下變量在處理一個請求(比如vcl_recv)的時候可用:

  • client.ip:客戶端IP地址。
  • server.hostname:server的主機名。
  • server.identity:server標示,當啟動varnish的時候用-i參數來指定。

    假設varnish啟動時候沒有指定-i參數,那麽server.identity會被設置為用-n參數所指定的實例名稱。

  • server.ip:serverIP地址。
  • server.port:server端口。
  • req.request:請求類型(比如GETHEAD)。
  • req.url:請求的URL。

  • req.proto:HTTP協議版本號。
  • req.backend:處理請求的後端server。

  • req.backend.healthy:後端是否健康。

    health check須要在backendprobe中進行設置。

  • req.http.header:相關的HTTP頭。
  • req.hash_always_miss:強迫對於本次請求的緩存查找結果為miss。假設設置為true,那麽varnish將會忽略不論什麽存在的緩存對象,一直從後端又一次獲取資源。

  • req.hash_ignore_busy:在緩存查找時候忽略不論什麽忙的對象。

    假設有兩個server,彼此互相查找緩存內容,那麽能夠使用這個變量來避免潛在的死鎖。

例如以下變量在準備一個後端請求(比方在cache miss或者passpipe模式)的時候可用:

  • bereq.request:請求的類型(比方GETHEAD)。
  • bereq.url:請求的URL。
  • bereq.proto:與後端server交互的HTTP協議版本號。

  • bereq.http.header:相關的HTTP頭。
  • bereq.connect_timeout:與後端連接的超時時間。
  • bereq.first_byte_timeout:從後端返回第一個字節所需等待的秒數,在pipe模式中不可用。
  • bereq.between_bytes_timeout:從後端返回的每一個字節之間的時間間隔,以秒計。

    pipe模式中不可用。

例如以下的變量在請求對象從後端返回之後,在其被放入緩存之前可用。換句話說,也就是在vcl_fetch中可用。

  • beresp.proto:HTTP協議版本號。
  • beresp.status:後端返回的HTTP狀態碼(比如200,302等)。
  • beresp.response:後端返回的狀態內容(比如OKFound)。
  • beresp.cacheable:假設請求的結果是能夠被緩存的,那麽此變量為true。假設HTTP狀態碼為200, 203, 300, 301, 302, 404,410之中的一個而且pass沒有在vcl_recv中被調用。那麽這個結果就是能夠被緩存的。

    假設response的TTLgrace time都為0,那麽beresp.cacheable將會為0。beresp.cacheable是可寫的。

  • beresp.ttl:緩存對象的生存時間,以秒為單位。這個變量是可寫的。

在對象已經存在於緩存中並被查詢到的時候。一般在vcl_hitvcl_deliver中。例如以下的變量(大部分是read-only)可用:

  • obj.proto:與後端交互的HTTP版本號協議。

  • obj.status:後端返回的HTTP狀態碼。
  • obj.response:後端返回的HTTP狀態內容。

  • obj.cacheable:假設對象的beresp.cacheable為true。那麽此變量的值為true。除非你強制delivery,否則obj.cacheable一直為true
  • obj.ttl:緩存對象的生存時間。以秒為單位。這個變量是可寫的。
  • obj.lastuse:從如今到對象近期一次訪問所間隔的時間。以秒為單位。

  • obj.hits:對象被發送到client的次數,0表示緩存查詢miss了。

例如以下變量在決定對象hash key的時候可用:

  • req.hash:hash key被用來關聯一個緩存中的對象。

    在讀寫緩存的時候都會被用到。

例如以下變量在準備把一個響應發送給client時候可用:

  • resp.proto:響應使用的HTTP協議版本號。
  • resp.status:將要返回的HTTP狀態碼。
  • resp.response:將要返回的HTTP狀態內容。
  • resp.http.header:相關的HTTP頭。




高性能HTTP加速器Varnish安裝與配置(包含常見錯誤)