Varnish配置應用

ytwz4919 8年前發布 | 37K 次閱讀 Varnish 緩存服務器

來自: http://wangzhijian.blog.51cto.com/6427016/1745993

一、Varnish簡介

Varnish是一款高性能的開源緩存代理服務器。Varnish分為Master(management)進程和Child(worker,也叫cache進程)進程。

Master 進程讀入存儲配置文件,調用合適的存儲類型,然后創建/讀入相應大小的緩存文件,接著 master 初始化管理該存儲空間的結構體,然后 fork 并監控 child 進程。

Child 進程在主線程的初始化的過程中,將前面打開的存儲文件整個 mmap 到內存中,此時創建并初始化空閑結構體,掛到存儲管理結構體,以待分配。

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

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

Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,如果在指定的時長內未得到Child進程的回應,Management將會重啟此Child進程。

Child 進程分配若干線程進行工作,主要包括一些管理線程和很多worker線程,可分為:

Accept線程:接受請求,將請求掛在overflow隊列上;

Work線程:有多個,負責從overflow隊列上摘除請求,對請求進行處理,直到完成,然后處理下一個請求;

Epoll線程:一個請求處理稱為一個session,在session周期內,處理完請求后,會交給Epoll處理,監聽是否還有事件發生;

Expire線程:對于緩存的object,根據過期時間,組織成二叉堆,該線程周期檢查該堆的根,處理過期的文件,對過期的數據進行刪除或重取操作。

二、Varnish安裝

# yum install epel-release

rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-4.1.el7.rpm

yum install varnish</pre>

三、Varnish配置

①VCL介紹

Varnish Configuration Language(VCL)是varnish配置緩存策略的工具,它是一種基于“域”(domain specific)的簡單編程語言,它支持有限的算術運算和邏輯運算操作、允許使用正則表達式進行字符串匹配、允許用戶使用set自定義變量、支持if判斷語句,也有內置的函數和變量等.使用VCL編寫的緩存策略通常保存至.vcl文件中,其需要編譯成二進制的格式后才能由varnish調用。事實上,整個緩存策略就是由幾個特定的子例程如vcl_recv、vcl_fetch等組成,它們分別在不同的位置(或時間)執行,如果沒有事先為某個位置自定義子例程,varnish將會執行默認的定義。

VCL策略在啟用前,會由management進程將其轉換為C代碼,而后再由gcc編譯器將C代碼編譯成二進制程序。編譯完成后,management負責將其連接至varnish實例,即child進程。正是由于編譯工作在child進程之外完成,它避免了裝載錯誤格式VCL的風險。因此,varnish修改配置的開銷非常小,其可以同時保有幾份尚在引用的舊版本配置,也能夠讓新的配置即刻生效。編譯后的舊版本配置通常在varnish重啟時才會被丟棄,如果需要手動清理,則可以使用varnishadm的vcl.discard命令完成。

②VCL使用

主要有以下幾點:

a. 塊是由花括號分隔,語句以分號結束,使用‘ # ’符號可以添加注釋。

b. VCL 使用指定運算符“=”、比較運算符“==”、邏輯運算符“!,&&,!!”等形式,還支持正則表達式和用“~”進行 ACL 匹配運算。

c. VCL 沒有用戶自己定義的變量,你可以在 backend、request 或 object 上設置變量值,采用 set 關鍵字進行設置。例如 set req.backend_hint = cluster1.backend();

d. 兩個字符串的連接,他們之間沒有任何運算符。例如 set resp.http.X-Cache = "HIT via" + " " + server.hostname;

e. \”字符在 VCL 里沒有特別的含義,這點與其他語言略有不同。

f. VCL 可以使用 set 關鍵字設置任何 HTTP 頭,可以使用 remove 或是 unset 關鍵字移除 HTTP 頭。

g. VCL 有 if/else 的判斷語句,但是沒有循環語句。

③設置Varnish參數

# cat /etc/varnish/varnish.params |grep -v "#"
RELOAD_VCL=1              ##重新啟動服務時是否重新讀取VCL并重新編譯
VARNISH_VCL_CONF=/etc/varnish/default.vcl       ##默認讀取的VCL文件
VARNISH_LISTEN_PORT=80                    ##設置監聽的端口(默認監聽6081端口)
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1       ##管理接口監聽的地址
VARNISH_ADMIN_LISTEN_PORT=6082               ##管理接口監聽的端口
VARNISH_SECRET_FILE=/etc/varnish/secret          ##使用的密鑰文件
VARNISH_STORAGE="malloc,256M"                ##存儲文件的大小
VARNISH_USER=varnish                        ##varnish默認用戶
VARNISH_GROUP=varnish                        ##varnish默認組

④定義VCL backend

# cp /etc/varnish/default.vcl /etc/varnish/default.vcl.bak

cat /etc/varnish/default.vcl |grep -v "#"

vcl 4.0; ##指明varnish版本 backend web1 { ##創建后端主機 .host = "192.168.10.132"; ##注:可使用域名,須添加hosts .port = "80"; }

systemctl start varnish ##啟動服務

varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 ##varnish命令操作

200

Varnish Cache CLI 1.0

Linux,3.10.0-229.el7.x86_64,x86_64,-junix,-smalloc,-smalloc,-hcritbit varnish-4.1.0 revision 3041728 Type 'help' for command list. Type 'quit' to close CLI session. help 200
help [<command>] ping [<timestamp>] auth <response> quit banner status start stop vcl.load <configname> <filename> [auto|cold|warm] vcl.inline <configname> <quoted_VCLstring> [auto|cold|warm] vcl.use <configname> vcl.state <configname> [auto|cold|warm] vcl.discard <configname> vcl.list param.show [-l] [<param>] param.set <param> <value> panic.show panic.clear [-z] storage.list vcl.show [-v] <configname> backend.list [-p] [<backend_expression>] backend.set_health <backend_expression> <state> ban <field> <operator> <arg> [&& <field> <oper> <arg> ...] ban.list</pre>

⑤定義 VCL 后端的集合 director

VCL 可以把多個 backends 聚合成一個組,這些組被叫做 director,這樣可以增強性能和彈力,當組里一個 backend 掛掉后,可以選擇另一個健康的 backend。VCL 有多種 director,不同的 director 采用不同的算法選擇 backend,主要有以下幾種:

a. The random director

Random director 會根據所設置的權值(weight)來選擇 backend,.retries 參數表示嘗試找到一個 backend 的最大次數,.weight 參數表示權值

b. The round-robin director

Round-robin director 在選擇 backend 時,會采用循環的方式依次選擇。

c.  The client director

Client director 根據 client.identity 來選擇 backend,您可以設置 client.identity 的值為 session cookie 來標識 backend。

# vi /etc/varnish/default.vcl
vcl 4.0;                                      ##指明varnish版本
backend server1 {                              ##定義后端服務器1
    .host = "192.168.10.132";        
    .port = "80";
}
backend server2 {                              ##定義后端服務器2
    .host = "192.168.10.133";
    .port = "80";
}
import directors;                            ##定義directors
sub vcl_init {                                      ##定義vcl_init子例程
    new cluster1 = directors.round_robin();    ##創建一個輪叫調度的directors
    cluster1.add_backend(server1);
    cluster1.add_backend(server2);
}
sub vcl_recv {                       ##定義vcl_recv子例程
    set req.backend_hint = cluster1.backend();        ##指定后端directors
}

⑥設置響應是否命中

sub vcl_deliver {                   ##定義子例程
        if (obj.hits > 0) {      
                set resp.http.X-Cache = "HIT via" + " " + server.ip;
        } else {
                set resp.http.X-Cache = "MISS via" + " " + server.ip;
        }             ##判斷如果命中就在http響應首部設置X-Cache為HIT,否則
                就在http響應首部設置X-Cache為MISS。
}

⑦指定某些文件不能查緩存

sub vcl_recv {
        if (req.url ~ "^/test.html$") {
                return(pass);
        }            ##定義請求的文件中如果匹配test.html就pass,不查緩存
}

⑧進行健康檢查

backend server1 {
    .host = "192.168.10.132";
    .probe = {
        .url = "/";         ##指定哪個url需要varnish請求
        .timeout = 1s;         ##指定超時等待時間
        .interval = 5s;         ##指定檢查時間間隔
        .window = 5;            ##最多嘗試5次
        .threshold = 3;          ##至少有3次成功就宣告backend健康
    }
}
backend server2 {
    .host = "192.168.10.133";
    .probe = {
        .url = "/";
        .timeout = 1s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

⑨設定緩存時長

sub vcl_backend_response {
    if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") {
        set beresp.ttl = 2h;
    }                 ##如果url是以圖片格式結尾的緩存2小時
    if (bereq.url ~ "\.(html|css|js|jsp)$") {
        set beresp.ttl = 30m;
    }                  ##如果url是以html|css|js|jsp結尾的緩存30分鐘
}

⑩優雅模式(Grace mode)

sub vcl_backend_response {
  set beresp.grace = 2m;
}             ##指定保持緩存對象超出TTL值2分鐘(就是該過期的緩存不讓它過期)
sub vcl_hit {
   if (obj.ttl >= 0s) {
       // A pure unadultered hit, deliver it
       return (deliver);   ##如果TTL值大于等于0秒,將已獲取的請求內容直接

                     ##發送給客戶端

} if (obj.ttl + obj.grace > 0s) { // Object is in grace, deliver it // Automatically triggers a background fetch return (deliver); } ##如果TTL值加上優雅模式設定值大于0秒,將已獲取

                    ##的請求內容直接發送給客戶端

// fetch & deliver once we get the result return (fetch); ##否則從后端獲取請求的內容 }</pre>

四、VCL相關

注:varnish4.0后版本所使用參數和以前版本有所改變,詳見:

https://www.varnish-cache.org/docs/4.0/whats-new/index.html

https://www.varnish-cache.org/docs/4.1/whats-new/index.html

①VCL主要內置函數

a. vcl_recv 函數

用于接收和處理請求。當請求到達并成功接收后被調用,通過判斷請求的數據來決定如何處理請求。例如如何響應、怎么響應、使用哪個后端服務器等。

此函數一般以如下關鍵字結束:

1). pass:表示進入 pass 模式,把請求控制權交給 vcl_pass 函數;

2). pipe:表示進入 pipe 模式,把請求控制權交給 vcl_pipe 函數;

3). lookup:表示進入 lookup 模式,把請求控制權交給 lookup 指令處理,在緩存中查找被請求的對象,并且根據查找的結果把控制權交給函數 vcl_hit 或函數 vcl_miss;

4). synth code [reason]:表示返回“code”給客戶端,并放棄處理該請求。“code”是錯誤標識,例如 200 和 405 等。“reason”是錯誤提示信息。

b. vcl_pipe 函數

此函數在進入 pipe 模式時被調用,用于將請求直接傳遞至后端主機,在請求和返回的內容沒有改變的情況下,將不變的內容返回給客戶端,直到這個連接被關閉。

此函數一般以 如下關鍵字結束:

1). synth code [reason]

2).pipe 

c. vcl_pass 函數

此函數在進入 pass 模式時被調用,用于將請求直接傳遞至后端主機。后端主機在應答數據后將應答數據發送給客戶端,但不進行任何緩存,在當前連接下每次都返回最新的內容。

此函數一般以如下關鍵字結束:

1).  synth code [reason];

2).  pass;

3).  restart 重新啟動流程,增加啟動次數,如果重新啟動次數高于 max_restarts 發出一個錯誤警告

d. vcl_hash函數

如果想把一個數據添加到 hash 上時,調用此函數。

此函數一般以 Hash 該關鍵字結束。

e. vcl_hit 函數

在執行 lookup 指令后,在緩存中找到請求的內容后將自動調用該函數。

此函數一般以如下關鍵字結束:

1).deliver:表示將找到的內容發送給客戶端,并把控制權交給函數 vcl_deliver;

2).synth code [reason];

3).pass;

4).restart 重新啟動流程,增加啟動次數,如果重新啟動次數高于 max_restarts 發出一個錯誤警告

f. vcl_miss 函數

在執行 lookup 指令后,在緩存中沒有找到請求的內容時自動調用該方法。此函數可用于判斷是否需要從后端服務器獲取內容。

此函數一般以如下關鍵字結束:

1).fetch:表示從后端獲取請求的內容,并把控制權交給 vcl_backend_response 函數;

2).synth code [reason];

3).pass。

g. vcl_backend_response 函數

在后端主機更新緩存并且獲取內容后調用該方法,接著,通過判斷獲取的內容來決定是將內容放入緩存,還是直接返回給客戶端。

此函數一般以如下關鍵字結束:

1).synth code [reason]

2).pass

3).deliver

4).esi

5).restart 

h.vcl_deliver函數

將在緩存中找到請求的內容發送給客戶端前調用此方法。

此函數一般以如下關鍵字結束:

1).synth code [reason]

2).deliver

3).restart 

i.vcl_backend_error函數

出現錯誤時調用此函數。

此函數一般以如下關鍵字結束:

1).deliver

2).restart

②varnish處理HTTP請求的過程

Varnish 處理 HTTP 請求的過程如下:

1. Receive狀態(vd_recv):請求處理的入口狀態,根據VCL規則判斷該請求應該pass(vd_pass)或是pipe(vd_pipe),還是進入lookup(本地查詢)

2. Lookup狀態:進入該狀態后,會在hash表中查詢數據,若找到,則進入hit狀態(vcl_hit),否則進入miss狀態(vcl_miss)

3. Pass狀態(vcl_pass):在此狀態下,會直接進入后端請求,即進入fetch狀態(vcl_backend_response)

4.Backend_response狀態:由原來的vcl_fetch獨立為vcl_backend_fetch和vcl_backend_response2個函數,在該狀態下,對請求進行后端獲取,發送請求,獲得數據,并根據設置進行本地存儲

5. Deliver狀態(vcl_deliver):將獲取到的數據發送給客戶端,然后完成本次請求

內置函數(也叫子例程):

1.vcl_recv:用于接收和處理請求,當請求到達并成功接收后被調用,通過判斷請求的數據

來決定如何處理請求;

2.vcl_pipe:此函數在進入pipe模式時被調用,用于將請求直接傳遞至后端主機,并將后端響應原樣返回客戶端;

3.vcl_pass:此函數在進入pass模式時被調用,用于將請求直接傳遞至后端主機,但后端主機的響應并不緩存直接返回客戶端;

4.vcl_hit:在執行lookup指令后,在緩存中找到請求的內容后將自動調用該函數;

5.vcl_miss:在執行lookup 指令后,在緩存中沒有找到請求的內容時 自動調用該方法,此函數可用于判斷是否需要從后端服務器獲取內容;

6.vcl_hash:在vcl_recv調用后為請求創建一個hash值時,調用此函數,此hash值將作為varnish中搜索緩存對象的key;

7.vcl_purge:pruge操作執行后調用此函數,可用于構建一個響應;

8.vcl_deliver:將在緩存中找到請求的內容發送給客戶端前調用此方法;

9.vcl_backend_fetch:向后端主機發送請求前,調用此函數,可修改發往后端的請求;

10.vcl_backend_response:獲得后端主機的響應后,可調用此函數;

11.vcl_backend_error:當從后端主機獲取源文件失敗時,調用此函數;

12.vcl_init:VCL加載時調用此函數,經常用于初始化varnish模塊(VMODs);

13.vcl_fini:當所有請求都離開當前VCL,且當前VCL被棄用時,調用此函數,經常用于清理varnish模塊.

詳情: https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html

③varnish變量解釋

VCL 內置的公共變量(變量也叫object)可以用在不同的 VCL 函數中:

req:The request object,請求到達時可用的變量

bereq:The backend request object,向后端主機請求時可用的變量

beresp:The backend response object,從后端主機獲取內容時可用的變量

resp:The HTTP response object,對客戶端響應時可用的變量

obj:存儲在內存中時對象屬性相關的可用的變量

a. 請求到達時可用公共變量

req.backend_hint: 指定對應的后端主機

server.ip: 表示服務器 IP

client.ip: 表示客戶端 IP

req.method: 只是請求的類型,例如 GET、HEAD 等

req.url: 指定請求的地址

req.proto: 表示客戶端發起請求的 HTTP 協議版本

req.http.header: 表示對應請求中的 HTTP 頭部信息

req.restarts: 表示重啟次數,默認最大值為4

b. 向后端主機請求時可用公共變量

beresp.requset: 指定請求類型,例如 GET、HEAD 等

beresp.url: 表示請求地址

beresp.proto: 表示客戶端發起請求的 HTTP 協議版本

beresp.http.header: 表示對應請求中 HTTP 頭部信息

beresp.ttl: 表示緩存的生存周期,cache 保留時間(單位秒)

c. 后端主機獲取內容時可使用公共變量

obj.status: 返回內容的請求狀態碼,例如 200、302、504 等

obj.cacheable: 返回的內容是否可以緩存

obj.valid: 是否有效的 HTTP 請求

obj.response: 返回內容的請求狀態信息

obj.proto: 返回內容的 HTTP 版本

obj.ttl: 返回內容的生存周期,也就是緩存時間(單位秒)

obj.lastuse: 返回上一次請求到現在的時間間隔(單位秒)

d.對客戶端相應時可使用公共變量

resp.status: 返回給客戶端的 HTTP 代碼狀態

resp.proto: 返回給客戶端的 HTTP 協議版本

resp.http.header: 返回給客戶端的 HTTP 頭部消息

resp.response: 返回給客戶端的 HTTP 頭部狀態

</div>

 本文由用戶 ytwz4919 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!