前文咱們聊了下http協議裏的緩存控制機制以及varnish架構組件介紹,回顧請參考http://www.javashuo.com/article/p-qdsszhfu-kn.html;今天咱們來聊一下怎樣配置使用varnish;html
前邊咱們說到過varnish有兩個配置文件,一個是/etc/varnish/varnish.params,這個配置文件主要是定義varnishd主控進程的一些運行時參數以及定義varnishd監聽在那個套接字上,以及鏈接varnish使用的密鑰文件;另一個配置文件是/etc/varnish/default.vcl這個配置文件實際上是varnish.params文件中指定的默認緩存策略配置文件,這個裏面主要是配置緩存相關策略,用varnish專有配置語言vcl寫的配置文件;咱們先來了解下varnish.params配置文件吧前端
[root@test_node1-centos7 ~]# vim /etc/varnish/varnish.params # Varnish environment configuration description. This was derived from # the old style sysconfig/defaults settings # Set this to 1 to make systemd reload try to switch VCL without restart. RELOAD_VCL=1 # Main configuration file. You probably want to change it. VARNISH_VCL_CONF=/etc/varnish/default.vcl # Default address and port to bind to. Blank address means all IPv4 # and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted # quad, or an IPv6 address in brackets. # VARNISH_LISTEN_ADDRESS=192.168.1.5 VARNISH_LISTEN_PORT=6081 # Admin interface listen address and port VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 # Shared secret file for admin interface VARNISH_SECRET_FILE=/etc/varnish/secret # Backend storage specification, see Storage Types in the varnishd(5) # man page for details. VARNISH_STORAGE="malloc,256M" # User and group for the varnishd worker processes VARNISH_USER=varnish VARNISH_GROUP=varnish # Other options, see the man page varnishd(1) #DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
提示:RELOAD_VCL這個參數主要是指定varnish是否支持不重啓切換VCL配置文件,1表示支持,0表示不支持;這裏通常都是設置成1,在工做中千萬不要隨意重啓varnish,一旦重啓好多緩存項都將失效,頗有可能由於緩存失效,前端訪問壓力壓到後端真正的服務器上,致使服務器崩潰的狀況;VARNISH_VCL_CONF該參數指定緩存策略配置文件,默認是default.vcl,咱們能夠直接編輯這個文件,而後經過VCL編譯編譯成不一樣的配置名稱的vcl;VARNISH_LISTEN_PORT該參數指定varnishd對外提供訪問的端口,一般狀況在前面沒有代理的狀況,咱們須要把這個端口改爲80或者443;VARNISH_ADMIN_LISTEN_ADDRESS該參數是指定varnish的管理接口接聽地址,爲了安全一般使用本機迴環地址,防止遠程鏈接;VARNISH_ADMIN_LISTEN_PORT該參數指定varnish的管理接口監聽的端口,一般這個端口能夠不用更改,由於管理接口通常都只有管理員使用;VARNISH_SECRET_FILE該參數指定varnish的管理接口鏈接所用到認證文件,一般不須要更改;VARNISH_STORAGE該參數指定varnish的緩存存儲方式,varnish的緩存存儲方式有三種,第一種是malloc內存存儲,其配置語法是malloc[,size],這種存儲方式重啓後全部緩存項都將失效;第二種是file文件,配置語法file[,path[,size[,granularity]]],一般咱們只須要指定文件的路徑及文件大小,這種磁盤文件存儲的方式是黑盒,重啓後全部緩存項都將失效;第三種也是磁盤文件的方式存儲,和第二種不一樣的是這種存儲方式重啓後全部緩存項都有效,可是這種存儲方式在varnish4.0還處於試驗階段,因此咱們能用的就兩種,一種是內存存儲,一種是文件黑盒存儲,這兩種方式都是重啓後全部緩存項失效,因此varnish緩存服務器上不能隨意重啓的;VARNISH_USER和VARNISH_GROUP這兩個參數是指定varnishd進程的啓動用戶和組;DAEMON_OPTS是指定varnish運行時參數,每一個參數都須要用-p來加以指定,可重複屢次使用來指定不一樣的參數;-r表示死定指定參數爲只讀狀態;這裏提示下varnish重載VCL配置文件是直接使用varnish的專用重載命令varnish_reload_vcl命令;瞭解了varnishd的vcl配置文件,接下來咱們修改下對外提供服務端端口,而後嘗試啓動varnish看看;node
提示:由於本機上運行的有httpd把80端口給佔用了,我這裏以8000端口爲例對外提供服務;同時咱們也給定了varnish的緩存是基於文件黑盒存儲方式,並指定其文件大小爲500M;mysql
提示:能夠看到varnish對外提供服務的端口已經起來了,可是用瀏覽器訪問8000端口提示503,說後端server沒有找到,這是由於默認狀況下varnish指定的後端server是127.0.0.1:8080,咱們要配置後端主機server能夠在defalult.vcl中配置;以下所示web
提示:以上配置表示默認後端提供web服務的主機地址是127.0.0.1,端口是8080;一般狀況咱們是須要更改這個配置文件來指定後端主機和端口的,而後從新編譯該配置文件而後加載使用;算法
提示::這樣修改配置文件後,須要用varnishadm這個工具鏈接到varnish提供的命令行接口上去編譯配置文件,而後再加載使用;首先咱們來講說varnishadm這個工具怎麼使用吧sql
[root@test_node1-centos7 ~]# varnishadm --help varnishadm: invalid option -- '-' usage: varnishadm [-n ident] [-t timeout] [-S secretfile] -T [address]:port command [...] -n is mutually exlusive with -S and -T [root@test_node1-centos7 ~]#
提示:以上是varnishadm命令的使用幫助,其實這個命令很好使用,咱們只須要用-S(大寫)來指定secret文件,而後用-T來指定varnish主機管理接口監聽的地址和端口便可,固然這樣去鏈接就是交互式鏈接,會給咱們一個交互式界面輸入命令操做varnish,若是不想交互式使用,在後面能夠給命令,有點相似mysql這個工具的用法;接下來咱們用varinshadm這個工具來鏈接下varnish的管理接口;chrome
[root@test_node1-centos7 ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 200 ----------------------------- Varnish Cache CLI 1.0 ----------------------------- Linux,3.10.0-693.el7.x86_64,x86_64,-sfile,-smalloc,-hcritbit varnish-4.0.5 revision 07eff4c29 Type 'help' for command list. Type 'quit' to close CLI session. quit 500 Closing CLI connection [root@test_node1-centos7 ~]#
提示:看到以上界面就表示用varinshadm工具成功鏈接到varinsh的管理接口上了,輸入quit表示推出管理界面,輸入help表示參看命令列表shell
[root@test_node1-centos7 ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 200 ----------------------------- Varnish Cache CLI 1.0 ----------------------------- Linux,3.10.0-693.el7.x86_64,x86_64,-sfile,-smalloc,-hcritbit varnish-4.0.5 revision 07eff4c29 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> vcl.inline <configname> <quoted_VCLstring> vcl.use <configname> vcl.discard <configname> vcl.list param.show [-l] [<param>] param.set <param> <value> panic.show panic.clear storage.list vcl.show [-v] <configname> backend.list [<backend_expression>] backend.set_health <backend_expression> <state> ban <field> <operator> <arg> [&& <field> <oper> <arg>]... ban.list
提示:用varnishadm工具鏈接varnish後每執行一個命令就會返回相似http協議中的狀態碼的數字,其中200就表示命令成功執行並返回相應的內容,這個狀態的意思有點相似http裏的狀態碼意思;從上面的help列出命令列表來看,它列出了各個命令的基本使用方法,好比hep命令能夠直接使用help表示類出命令列表及命令使用格式,help 某個命令表示查看某個命令的使用方法;以下,咱們要查看下ping命令的用法能夠在命令行接口上敲help ping express
提示:從上面的幫助信息,咱們能夠了解到ping命令的主要做用是看看varnish是否存活,咱們在varnish shell中敲ping命令返回200 和PONG 1585892735 1.0就表示varnish主機上存活的;
繼續上面的話題,咱們修改了default.vcl配置文件,咱們須要怎麼樣去編譯呢?接續查看命令幫助
提示:以上表示vcl.load命令的用法和說明,該命令主要是編譯和加載VCL文件,使用方法是vcl.load +配置名稱(這個名稱是咱們自定義的,能夠說任何合法名稱)+配置文件名稱;以下
提示:以上就表示編譯default.vcl配置文件,並起名叫test1,咱們能夠在varnish shell 中敲 vcl.list來查看當前有幾個vcl配置
提示:能夠看到有兩個配置,一個是名字爲boot的,其狀態是active表示當前正在使用的,另外一個是咱們剛纔編譯指定的名稱test1,狀態是available表示有效的,能夠用的,意思就是咱們可使用vcl.use來切換使用的;接下來咱們來看看vcl.use的用法,並嘗試切換咱們新編譯的配置;
提示:vcl.use命令主要用來切換至指定配置名稱的配置;從上面的返回結果看,test1如今處於active的狀態,表示如今varnish應用的是test1的配置;接下來咱們就能夠在瀏覽器在嘗試訪問varnish對外提供訪問的端口;
提示:能夠看到咱們如今訪問8000端口能夠正常獲得後端httpd服務器的響應;說明咱們配置的後端主機ip和端口沒有問題;同時上面的結果來看,varnish也是一款反向代理服務軟件,一般varnish能夠作反向代理,可是它裏面的調度算法很簡單隻有輪詢和加權輪詢,之因此算法少是由於它的強項不是作反向代理服務器來用,它的強項是作緩存服務器來用,響應客戶端的請求,不多經過反向代理到後端取資源;
配置好varnish的後端web主機後,接下來咱們來了解下varnish的配置語言VCL的語法
VCL(varnish configuration lanuage)是「域」專有類型的配置語言,主要用於編寫緩存策略的,VCL有多個狀態引擎,狀態之間存在相關性,但狀態引擎彼此互相隔離;每一個狀態引擎可以使用return(X)指明至那個下一級引擎;每一個狀態引擎對應於vcl文件中的一個配置端,即爲subroutine,大概處理流程是這樣的,例如vcl_hash --> return(hit) -->vcl_hit;處理過程要看return是什麼,return(hit)就表示下一級處理的subroutine是vcl_hit;
varnish4.0VCL語法有以下幾點:
1)VCL文件必須是vcl 4.0;開始
示例:
提示:以上除了#號開頭的表示現有配置生效的指令;「#」表示註釋
2)//和#號和/**/都表示註釋,前二者表示單行註釋,最後一個表示多行註釋;
3)subroutines必需要有sub關鍵字指定
示例:
提示:這就表示一個subroutine 名字爲vcl_recv
4)沒有循環,受限於引擎的內建變量
5)用return()函數的參數做爲下一個操做的關鍵字來結束語句;用return來實現狀態引擎切換;
VCL有限狀態機特定:
1)每項請求分別處理;
2)每一個請求在任何給定時間都是獨立於其餘請求的;
3)狀態是有相關性,但又各自隔離;
4)return(action);退出一種狀態並指定varnish進入下一種狀態;
5)內置的VCL代碼始終存在,並附加在你本身的VCL下面;也就說咱們不寫任何VCL代碼,它默認都有本身內置的VCL代碼,且這個代碼始終不變;咱們能夠用在varnish shell中使用vcl.show -v 指定配置名稱來查看當前生效的配置詳情(默認VCL代碼+本身寫的VCL配置代碼),以下
[root@test_node1-centos7 ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 200 ----------------------------- Varnish Cache CLI 1.0 ----------------------------- Linux,3.10.0-693.el7.x86_64,x86_64,-sfile,-smalloc,-hcritbit varnish-4.0.5 revision 07eff4c29 Type 'help' for command list. Type 'quit' to close CLI session. varnish> vcl.list 200 active 0 boot varnish> vcl.show -v boot 200 // VCL.SHOW 0 1221 input # # This is an example VCL file for Varnish. # # It does not do anything by default, delegating control to the # builtin VCL. The builtin VCL is called when there is no explicit # return statement. # # See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/ # and http://varnish-cache.org/trac/wiki/VCLExamples for more examples. # Marker to tell the VCL compiler that this VCL has been adapted to the # new 4.0 format. vcl 4.0; # Default backend definition. Set this to point to your content server. backend default { .host = "192.168.0.99"; .port = "80"; } sub vcl_recv { # Happens before we check if we have this in cache already. # # Typically you clean up the request here, removing cookies you don't need, # rewriting the request, etc. } sub vcl_backend_response { # Happens after we have read the response headers from the backend. # # Here you clean the response headers, removing silly Set-Cookie headers # and other mistakes your backend does. } sub vcl_deliver { # Happens when we have all the pieces we need, and are about to send the # response to the client. # # You can do accounting or modifying the final object here. } // VCL.SHOW 1 5479 Builtin /*- * Copyright (c) 2006 Verdens Gang AS * Copyright (c) 2006-2014 Varnish Software AS * All rights reserved. * * Author: Poul-Henning Kamp <phk@phk.freebsd.dk> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * The built-in (previously called default) VCL code. * * NB! You do NOT need to copy & paste all of these functions into your * own vcl code, if you do not provide a definition of one of these * functions, the compiler will automatically fall back to the default * code from this file. * * This code will be prefixed with a backend declaration built from the * -b argument. */ vcl 4.0; ####################################################################### # Client side sub vcl_recv { if (req.method == "PRI") { /* We do not support SPDY or HTTP/2.0 */ return (synth(405)); } if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "DELETE") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } if (req.method != "GET" && req.method != "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 (hash); } sub vcl_pipe { # By default Connection: close is set on all piped requests, to stop # connection reuse from sending future requests directly to the # (potentially) wrong backend. If you do want this to happen, you can undo # it here. # unset bereq.http.connection; return (pipe); } sub vcl_pass { return (fetch); } sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } return (lookup); } sub vcl_purge { return (synth(200, "Purged")); } sub vcl_hit { if (obj.ttl >= 0s) { // A pure unadultered hit, deliver it return (deliver); } if (obj.ttl + obj.grace > 0s) { // Object is in grace, deliver it // Automatically triggers a background fetch return (deliver); } // fetch & deliver once we get the result return (fetch); } sub vcl_miss { return (fetch); } sub vcl_deliver { return (deliver); } /* * We can come here "invisibly" with the following errors: 413, 417 & 503 */ sub vcl_synth { set resp.http.Content-Type = "text/html; charset=utf-8"; set resp.http.Retry-After = "5"; synthetic( {"<!DOCTYPE html> <html> <head> <title>"} + resp.status + " " + resp.reason + {"</title> </head> <body> <h1>Error "} + resp.status + " " + resp.reason + {"</h1> <p>"} + resp.reason + {"</p> <h3>Guru Meditation:</h3> <p>XID: "} + req.xid + {"</p> <hr> <p>Varnish cache server</p> </body> </html> "} ); return (deliver); } ####################################################################### # Backend Fetch sub vcl_backend_fetch { return (fetch); } sub vcl_backend_response { if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Surrogate-control ~ "no-store" || (!beresp.http.Surrogate-Control && beresp.http.Cache-Control ~ "no-cache|no-store|private") || beresp.http.Vary == "*") { /* * Mark as "Hit-For-Pass" for the next 2 minutes */ set beresp.ttl = 120s; set beresp.uncacheable = true; } return (deliver); } sub vcl_backend_error { set beresp.http.Content-Type = "text/html; charset=utf-8"; set beresp.http.Retry-After = "5"; synthetic( {"<!DOCTYPE html> <html> <head> <title>"} + beresp.status + " " + beresp.reason + {"</title> </head> <body> <h1>Error "} + beresp.status + " " + beresp.reason + {"</h1> <p>"} + beresp.reason + {"</p> <h3>Guru Meditation:</h3> <p>XID: "} + bereq.xid + {"</p> <hr> <p>Varnish cache server</p> </body> </html> "} ); return (deliver); } ####################################################################### # Housekeeping sub vcl_init { return (ok); } sub vcl_fini { return (ok); } varnish>
提示:以上就是咱們沒有寫任何VCL配置代碼,默認就有的VCL配置代碼;從上面的配置來看,VCL配置語言主要有三類主要語法
第一類定義subroutine,主要格式是
sub subroutine { ... }
第二類是if else條件判斷分支,格式以下
if CONDITION { ... } else { ... }
第三類就是每一個subroutine都是須要由return語句結尾,指定下一跳subroutine
瞭解了上面的基本語法,咱們再來看看VCL的內建函數和關鍵字
首先說函數吧,regsub(str,regex,sub)這個函數是VCL內置查找替換字串的一個函數,這個函數只會替換第一次匹配的字串,若是後面有多個字串匹配不予處理;regsuball(str,regex,sub)這個函數和上面的那個函數只有一個區別,這個函數是替換全部匹配的字串;ban(boolean expression)該函數用於清理緩存項的; hash_data(input)對input作hash計算;synthetic(str)該函數用戶合成字符串,一般用於嵌入其餘代碼用;
關鍵字:call subroutine,return(action),new,set,unset
操做符:==, !=, ~, >, >=, <, <=,邏輯操做符&&,||,!,變量賦值=
內建變量大概有5類,分別是req.*表示由客戶端發來的請求報文相關;如req.http.*就表示請求首部的變量,如req.http.User-Agent就表示引用http請求報文中的User-Agent首部的值;req.http.Referer就表示應用http請求首部Referer的值;bereq.*是有varnish發日後端主機的http請求相關;如bereq.http.*就表示引用發日後端主機的http請求首部的值,同req.http.*的邏輯上同樣的;beresp.*:由BE主機響應給varnish的響應報文相關;resp.*:由varnish響應給client相關;這四類變量都是同一種邏輯,.http.*就表示引用http對應首部的值;obj.*是存儲在緩存空間中的緩存對象的屬性;
經常使用的變量:
bereq.*, req.*: bereq.http.HEADERS bereq.request:請求方法; bereq.url:請求的url; bereq.proto:請求的協議版本; bereq.backend:指明要調用的後端主機; req.http.Cookie:客戶端的請求報文中Cookie首部的值; req.http.User-Agent ~ "chrome" beresp.*, resp.*: beresp.http.HEADERS beresp.status:響應的狀態碼; reresp.proto:協議版本; beresp.backend.name:BE主機的主機名; beresp.ttl:BE主機響應的內容的餘下的可緩存時長; obj.* obj.hits:此對象從緩存中命中的次數; obj.ttl:對象的ttl值 server.* server.ip server.hostname client.* client.ip
用戶指定變量用set指令來設置,unset表示刪除之意;
示例:指定響應首部,若是命中緩存就把對應首部的值設置成「HIT via 」+服務端ip地址,沒有命中對應首部的值就是「MISS via」 +服務端ip地址
提示:以上這段配置須要寫在vcl_deliver中,vcl_deliver主要是varnish響應客戶端報文都要經由它處理;有點相似iptables裏的postrouting;
測試,在瀏覽器中訪問,看看響應首部X-Cache的值就能夠判斷該此請求是否被緩存命中;
第一次訪問,確定是不會被緩存命中,由於壓根就沒有緩存,談不上命中,因此第一次訪問X-Cache首部的值應該是"MISS via 192.168.0.99"
提示:能夠看到第一次訪問的確是MISS的,那麼第二次和後面的訪問會不會是miss的呢?
提示:第二次訪問X-Cache響應首部的值就變成了hit via 192.168.0.99 說明第二次訪問被緩存命中了;