第一章 http緩存的基礎概念
1、程序運行時具有局部性特征
-
時間局部性
緩存的數據往往被打有時間綴,具有定期失效的特征,過期后會從源服務器檢驗請求驗證是否需要重新拉取數據,某數據被訪問后,該數據往往會再次在短時間內被訪問到。 -
空間局部性
被訪問數據的周邊數據被訪問的概率會比其它常規數據訪問大很多,所以這些訪問數據和其它周邊有可能被訪問的數據通過某種方式集中在一起,以提高數據的被訪問速度,減少數據查找時長。
完成這類功能的工具往往稱為Cache -
熱區:內容具有熱區效應,也就是部分數據的訪問頻率很高,而有些數據的訪問頻率相對較低,只有存在熱區效應服務數據才應該會有緩存,因為如果所有資源訪問量都很大,那么就應該對所有內容的訪問速率提速
2、緩存命中率:hit/(hit+miss)
-
文檔命中率:從文檔個數進行衡量
-
字節命中率:從內容的大小進行衡量
3、緩存的生命周期:
-
重啟后失效
4、緩存清理:
-
緩存項過期:惰性清理或其他方式清理,惰性清理是指將緩存條目標記為失效,然后其占用的空間標記為可用,這樣后續的緩存項可以直接覆蓋其占用的空間
-
緩存空間耗盡:LRU最近最少使用
5、數據能否緩存的依據,取決于數據是私有的還是公開的
-
私有數據:不可緩存,可以緩存在私有緩存上(如用戶的瀏覽器本身的緩存就是私有緩存)
-
公共緩存:可公開的一些數據,可緩存在公共緩存上(如用戶端的正向代理服務器,CDN服務器,服務器端的反向代理服務器…)
6、http緩存處理的步驟:
-
接受請求–>解析請求(提取請求的URL及各種首部)–>查詢緩存–>判斷緩存的有效性–>構建響應報文–>發送響應–>記錄日志
7、緩存相關的http的首部信息
-
expire:緩存的有效期限,是一個絕對時間,如2016-11-11 08:08:08類似
-
if-modified-since:表示基于last-modified機制,緩存服務器到后端真實服務器上判斷緩存有效性時,判斷自從某個絕對時間點后,緩存內容是否發生過更改
-
if-none-match:基于Etag機制,用于緩存服務器向后端服務器驗證緩存有效性
-
public:可被所有公共緩存緩存,盡可以在響應報文中
-
private
-
no-store:在響應報文中表示該內容不可緩存,在請求報文中表示不能從緩存中進行響應
-
no-cache:
-
在響應報文中表示可以緩存,但是客戶端端請求的內容緩存命中后,不能直接用緩存直接響應,而是要先到原始服務器上進行校驗緩存有效性。
-
在請求報文中表示要先到原始服務器上進行校驗有效性后才能用緩存的內容進行響應
-
max-age:以秒為單位指定的相對時長(300000),表示緩存的最大有效期,是一個相對時長,與expire類似,但是expire給明的有效期是絕對日期(2016-11-11 08:08:08類似)
-
s-maxage:與max-age類似,但是僅僅作用于公共緩存
8、http cache解決方案:
-
squid&varnish
squid、varnish
squid和varnish的關系類似于httpd與nginx的關系
早期的緩存服務器的常見方案是Squid
在中小規模的應用場景中,Varnish比Squid輕量級,但是單個Varnish所能承載的并發訪問量在5000個左右
在較大規模的應用場景中,仍然可能看到Squid -
varnish是一款專業的http cache:
其可以接受http請求,并解析http請求,根據請求來查找緩存,如果沒有緩存項,則將請求轉發到后端真實服務器上,真實服務器響應后,判斷響應的報文是否可緩存,如果可緩存,則緩存后,再響應給用戶
緩存控制機制
1、通過過期日期來控制:
-
HTTP/1.0響應報文首部中的過期日期機制:
Expires:Mon, 25 Sep 2017 01 :00 :31 GMT 指明了具體過期的時間和日期 -
HTTP/1.1響應報文首部中的過期日志機制:
Cache-Control:max-age=31104000 max-age指明了一個相對時長,可緩存多少秒
2、通過Cache-Control,緩存控制相關的首部,請求報文可和響應報文都可以有該首部,其可容納的參數不一樣
-
對請求首部可接受的參數:(用于客戶端向服務器端傳遞其接受的緩存的方式)
-
no-cache:通知緩存服務器,必須要進行驗證緩存的新鮮性,否則不會接受任何緩存文檔(在瀏覽器中用Ctrl+F5就是實現了此種功能)
-
no-strore:告知緩存服務器,必須盡快刪除緩存中的文檔(可能是因為其包含用戶的敏感信息)
-
max-age:相對的時間,類似于Expires首部的效果一樣,只是相對時長,如300000之類的數字,默認單位為秒
-
max-stale:告知緩存服務器,可以使用任意緩存文件(包括過期的文件進行響應)
-
min-fresh:
-
對響應首部可接受的參數:
-
public:可以放在公共緩存上,公共緩存是指除了客戶端的自身瀏覽器的緩存,其他任何位置都是公共緩存
-
private:可以放在私有緩存上進行緩存
-
no-cache:表示能緩存,但是當客戶端下次請求同樣的資源時,不能直接用緩存的內容響應給客戶端,而是要到原始服務器驗證緩存的有效性
-
no-store:不可緩存,表示響應的內容不允許緩存
-
must-revalidate:必須重新校驗,表示內容緩存下來后,當用戶請求同樣的內容時,必須要原始服務器上進行校驗緩存有效性
-
max-age:可緩存的時長,相對時長,也就是從此刻開始,可以緩存多少秒
-
s-max-age:公共緩存服務器的緩存,可緩存的時長??刂乒簿彺孀畲笥行?,如果沒有公共緩存的定義,也能使用私有緩存中的數據(也就是s-max-age可以不用指明,但是如果沒有指明,如果公共緩存中的數據需要緩存,緩存的有效時長就取決于max-age)
3、新鮮度檢測的機制(緩存有效性)的概述
-
有效性再驗證
-
如果原始內容未改變,則僅響應首部(不需要附帶body部分);響應碼為304(not modified)
-
如果原始內容發生了改變,則用新的內容正常響應,響應碼為200
-
如果原始內容消失,則響應碼為404,此時緩存中的緩存項也應該被刪除
-
條件式請求首部
-
if-Modified-Since:自從某時間后是否發生過改變,基于原始內容的最近一個修改的時間戳進行有效性再驗證;
-
if-Unmodified-Since:自動某時間后是否沒有發生過改變
-
if-none-match/if-match:基于Etag機制的條件式請求的首部
4、如何保證緩存的新鮮度的(新鮮度驗證的詳細說明):取決于緩存的管理機制
-
(1)文檔過期機制:
在有效期內,利用的都是緩存的內容,此種方式有可能造成,當緩存有效,但實際服務器上的數據已經發生變化,而用戶看到的內容依然是緩存的內容 -
在HTTP/1.0版本中,有個首部叫Expires(過期時間),使用的是絕對時間,如2016-10-18 18 :28 :58類似這種指明具體的絕對的過期時間
-
在HTTP/1.1版本中,有個首部叫Cache-Control字段中有一個叫max-age=XX的字段用來控制,使用的是相對時長,如可以使用2000秒
-
(2)條件式請求:
-
基于時間的條件式請求:mtime: if-modified-since|if-Unmodified-Since
相當于客戶端發送請求,緩存服務器收到請求后,如果緩存服務器緩存有請求的資源,不會直接使用該資源響應用戶請求,而是緩存服務器去向原始服務器詢問,是否有該資源,如果沒有資源,則證明緩存的已經沒用了,就返回給客戶端沒有對應的資源;如果實際服務器上有對應的資源,緩存服務就將自己緩存的資源的時間戳提供給原始服務器,詢問原始服務器上資源在此時間戳之后有沒有發生過修改,如果沒有發生過修改,原始服務器則返回304,Not Modified給緩存服務器,證明緩存服務器上的資源與原始服務器的資源是一致的,如果在時間戳之后發生過修改,則原始服務器將修改后的資源重新發送給緩存服務器,緩存服務器重新緩存,然后發送給客戶端 -
基于擴展標簽的條件式請求 :ETag : if-none-match|if-Match
想象此類情況:當請求的資源的時間戳發生了改變,但是文件內容卻沒有發生改變(如touch現有的文件);或者有些文件的內容修改的速度非???,在毫秒級別,但是文件的時間戳只能精確到秒級別,此時就會發現文件的時間戳沒變,但是文件內容已經發生改變
此種情況下,我們給每個文件一個版本號(專業稱呼為:擴展標記ETag),一旦文件內容發生改變,擴展標記就會發生改變,內容不變,擴展標記也不變,當緩存服務器與后端服務器進行比對時,就是比對擴展標記,如果擴展標記不一致,就重新緩存,這樣就實現了基于文件內容的判斷機制 -
(3)文件有效期機制和條件式請求機制的結合使用:
-
在文檔有效期內,用緩存的內容去響應,但是當文檔有效期到期后,不是立即到后端服務器上請求新內容來覆蓋緩存服務器上的原有緩存內容,而是通過條件式請求機制(if-modified-since或if-none-match)去向后端真實服務器,判斷當前緩存服務器上的緩存與后端服務器上的真實數據是否一致,如果一致,則繼續使用
注意:文檔過期機制(Expires和Cache-Control:max-age=)一般是在響應首部中,而條件式請求機制(if-modified-since或if-none-match)一般出現在請求首部中
http相關首部的回顧
1、通用首部:響應報文和請求報文都可用到的一些首部
-
Connection:close|keep-alive 表示使用短連接機制或長連接機制,HTTP1.1默認是keep-alive,HTTP1.0默認是close
-
Date:日期時間,請求(響應)報文產生時的時間點
-
Host:請求的主機信息
-
Pagram: no-cache 如果在請求報文中,則表示客戶端請求時,如果中間有緩存服務器,則必須要到原始服務器上做新鮮度驗證。如果在響應報文中,則表示緩存服務器可以緩存該報文內容,但不能直接用該緩存去響應客戶端請求,而是要在響應客戶端請求時先到后端服務器上驗證數據的新鮮性
-
Via: 請求或響應消息在客戶端與服務器之間傳遞時,所經過的代理
-
Transfer-Encoding:消息主體的傳輸編碼方式,用于保障數據在客戶端和服務器端傳遞時的安全機制,常用值為chunked,表示采用塊編碼的方式
2、請求首部:只能用在請求報文部分的首部
-
if-modified-since:向后端服務器驗證所緩存的數據是否是最新(基于修改時間戳的驗證方式)
-
if-none-match:向后端服務器驗證所緩存的數據是否是最新的(基于驗證資源的ETag擴展標記)
-
Referer:通過點擊那個頁面的跳轉鏈接跳轉過來的
-
User-Agent:用戶代理,也就是用戶瀏覽器類型
-
Host:請求的主機,必要時包括端口號
-
Accept-Encoding:表示接受的編碼方式,是否支持壓縮等
-
Accept-Language:接受的自然語言,中文,英文等
-
Accept-Charset:支持的字符集編碼
-
Autorization:服務端發送www-authenticate時,客戶端通過此首部提供認證信息
3、響應首部:只能用在響應報文部分的首部
-
ETag:內容的擴展標簽,提供給前端緩存,用于驗證緩存的內容與實際服務器上的內容是否一致
-
Location:重定向后的新的資源位置
-
Server:服務器軟件信息版本號等
-
WWW-Authenticate:要求對客戶端進行驗證,通常此時的狀態碼為401
4、實體首部:也就是響應報文BODY部分用到的相關首部
-
Content-Encoding:內容編碼
-
Content-Language:內容語言
-
Content-Length:響應內容本身的長度
-
Content-Type:當前內容的MIME類型
-
Expires:內容的過期期限
-
Last-Modified:最后一次的修改時間
-
Cache-Control相關的定義
第二章 varnish基礎理論簡介
1、varnish的程序結構
-
varnish主要運行兩個進程:Management進程和Child進程(也叫Cache進程)。
-
Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,如果在指定的時長內未得到Child進程的回應,Management將會重啟此Child進程。
-
Child進程包含多種類型的線程,常見的如:
Varnish依賴“工作區(workspace)”以降低線程在申請或修改內存時出現競爭的可能性。在varnish內部有多種不同的工作區,其中最關鍵的當屬用于管理會話數據的session工作區。
-
Acceptor線程:接收新的連接請求并響應;
-
Worker線程:child進程會為每個會話啟動一個worker線程,此worker線程真正來管理緩存,構建響應報文,因此,在高并發的場景中可能會出現數百個worker線程甚至更多;
-
Expiry線程:從緩存中清理過期內容;
2、varnish日志
-
varnish通過可以基于文件系統接口進行訪問的共享內存區域來記錄日志,為了與系統的其它部分進行交互,Child進程使用了可以通過文件系統接口進行訪問的共享內存日志(shared memory log),因此,如果某線程需要記錄信息,其僅需要持有一個鎖,而后向共享內存中的某內存區域寫入數據,再釋放持有的鎖即可。而為了減少競爭,每個worker線程都使用了日志數據緩存。
-
共享內存日志大小一般為90M,其分為兩部分,前一部分為計數器,后半部分為客戶端請求的數據。varnish提供了多個不同的工具如varnishlog、varnishncsa或varnishstat等來分析共享內存日志中的信息并能夠以指定的方式進行顯示。
-
當日志區域超過90M后,默認情況下前面的日志將會被后面的日志覆蓋,如果希望保存超出90M空間限制的日志,可以開啟varnishncsa服務
3、varnish的緩存存儲機制(也就是緩存存儲在哪)
-
varnish支持多種不同類型的后端存儲,這可以在varnishd啟動時使用-s選項指定。后端存儲的類型包括:
-
<1>file:自管理的文件系統,使用特定的一個文件存儲全部的緩存數據,并通過操作系統的mmap()系統調用將整個緩存文件映射至內存區域(如果內存大小條件允許);varnish重啟時,所有緩存對象都將被清除
-
<2>malloc:使用malloc()庫調用在varnish啟動時向操作系統申請指定大小的內存空間以存儲緩存對象;varnish重啟時,所有緩存對象都將被清除
-
<3>persistent:與file的功能相同,但可以持久存儲數據(即重啟varnish數據時不會被清除);仍處于測試期;
-
varnish無法追蹤某緩存對象是否存入了緩存文件,從而也就無從得知磁盤上的緩存文件是否可用,因此,file存儲方法在varnish停止或重啟時會清除數據。而persistent方法的出現對此有了一個彌補,但persistent仍處于測試階段,例如目前尚無法有效處理要緩存對象總體大小超出緩存空間的情況,所以,其僅適用于有著巨大緩存空間的場景。
-
選擇使用合適的存儲方式有助于提升系統性,從經驗的角度來看,建議在內存空間足以存儲所有的緩存對象時使用malloc的方法,反之,file存儲將有著更好的性能的表現。然而,需要注意的是,varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,一般說來,其需要為每個緩存對象多使用差不多1K左右的存儲空間,這意味著,對于100萬個緩存對象的場景來說,其使用的緩存空間將超出指定大小1G左右。另外,為了保存數據結構等,varnish自身也會占去不小的內存空間。
-
各種存儲方式的參數格式:
file中的granularity用于設定緩存空間分配單位,也就是當我們size假設設置為20G,這20G的空間不是一次性分配的,而是初始時比方說分配1G,用完后,逐步增加,一次增加的多大(此即為granularity),默認單位是字節,一次次的增加,直到達到size大小
-
malloc[,size]
-
file[,path[,size[,granularity]]]
-
persistent,path,size
vcl簡介
varnish的緩存策略相關配置,需要借助vcl來實現,系統上默認的vcl的配置文件為/etc/varnish/default.vcl
1、VCL是什么
-
VCL,Varnish Configuration Language 是varnish配置緩存策略的工具,它是一種基于“域”(domain specific,可想象與iptables的幾個鏈,也就是類似鉤子函數)的簡單編程語言,它支持有限的算術運算和邏輯運算操作、允許使用正則表達式進行字符串匹配、允許用戶使用set自定義變量、支持if判斷語句,也有內置的函數和變量等。
-
使用VCL編寫的緩存策略通常保存至.vcl文件中,其需要編譯成二進制的格式后才能由varnish調用。事實上,整個緩存策略就是由幾個特定的子例程如vcl_recv、vcl_hash等組成,它們分別在不同的位置(或時間)執行,如果沒有事先為某個位置自定義子例程,varnish將會執行默認的定義。
-
VCL策略在啟用前,會由management進程將其轉換為C代碼,而后再由gcc編譯器將C代碼編譯成二進制程序。編譯完成后,management負責將其連接至varnish實例,即child進程。正是由于編譯工作在child進程之外完成,它避免了裝載錯誤格式VCL的風險。因此,varnish修改配置的開銷非常小,其可以同時保有幾份尚在引用的舊版本配置,也能夠讓新的配置即刻生效。編譯后的舊版本配置通常在varnish重啟時才會被丟棄,如果需要手動清理,則可以使用varnishadm的vcl.discard命令完成。
2、vcl的狀態引擎
-
vcl_recv:接受用戶請求進varnish的入口的引擎,接受到結果之后,利用return(lookup),將請求轉交給vcl_hash引擎進行處理
-
vcl_hash:接受到用戶請求后,對用戶請求的URL進行hash計算,根據請求的首部信息,以及hash結果進行下一步處理的引擎
-
vcl_hit:經過vcl_hash引擎處理后,發現用戶請求的資源本地有緩存,則vcl_hash引擎通過return(hit)將請求交給vcl_hit引擎進行處理,vcl_hit引擎處理后將請求交給vcl_deliver引擎,vcl_deliver引擎構建響應報文,響應給用戶
-
vcl_miss:經過vcl_hash引擎處理后,發現用戶請求的資源本地沒有緩存,則vcl_hash引擎通過return(miss)將請求交給vcl_miss引擎進行處理
-
vcl_purge:經過vcl_hash引擎處理后,發現請求是對緩存的內容進行修剪時,則通過return(purge)交給vcl_purge引擎進行處理,vcl_purge引擎處理后,利用vcl_synth引擎將處理的結果告知給用戶
-
vcl_pipe:經過vcl_hash引擎處理后,發現用戶請求的報文varnish無法理解,則通過return(pipe),將請求交給vcl_pipe引擎,pipe引擎直接將請求交給后端真實服務器
-
vcl_pass:當請求經過vcl_hash處理后,發現請求報文不讓從緩存中進行響應或其他原因沒辦法查詢緩存,則由return(pass)或return(hit-for-pass)交由vcl_pass引擎進行處理
-
vcl_backend_fetch:當發現緩存未命中或由vcl_pass傳遞過來的某些不能查詢緩存的請求,交由vcl_backend_fetch引擎處理,vcl_backend_fetch引擎會向后端真實web服務器發送請求報文,請求對應的資源
-
vcl_backend_response:當后端發送響應報文到varnish后,會由vcl_backend_resonse引擎進行處理,如:判斷響應的內容是否可緩存,如果能緩存,則緩存下來后,交給vcl_deliver引擎,如果不能緩存,則直接交給vcl_deliver引擎,vcl_deliver引擎構建響應報文給客戶端
-
varnish4.0版本的兩個特殊的引擎
-
vcl_init:在處理任何請求之前要執行的vcl的代碼,主要用于初始化VMODS,可用在后端主機有多臺時,借助此引擎完成多臺主機的負載均衡效果
-
vcl_fini:所有的請求都已經結束,在vcl配置被丟棄時調用;主要用于清理VMODS
因此,常見的狀態引擎之間的處理流程為:
如果緩存命中:
用戶請求–>vcl_recv–>vcl_hash–>vcl_hit–>vcl_deliver–>響應給用戶如果緩存未命中:
用戶請求–>vcl_recv–>vcl_hash–>vcl_miss–>vcl_backend_fetch–>后端服務器接受請求發送響應報文–>vcl_backend_response–>vcl_deliver
或:
用戶請求–>vcl_recv–>vcl_hash–>vcl_miss–>vcl_pass–>vcl_backend_fetch–>后端服務器接受請求發送響應報文–>vcl_backend_response–>vcl_deliver–>響應給用戶如果不能從緩存中進行響應
用戶請求–>vcl_recv–>vcl_hash–>vcl_pass–>vcl_backend_fetch–>后端服務器接受請求發送響應報文–>vcl_backend_response–>vcl_deliver–>響應給用戶如果進行緩存修剪
用戶請求–>vcl_recv–>vcl_hash–>vcl_purge–>vcl_synth–>返回給用戶如果請求報文無法理解
用戶請求–>vcl_recv–>vcl_hash–>vcl_pipe–>交給后端服務器
3、vcl語法格式
-
<1>配置文件第一個非注釋行必須是vcl 4.0,標明此vcl配置文件是基于vcl4.0版本
-
<2>//、#或/ comment /用于單行或多行注釋
-
<3>sub $NAME 定義函數,子例程
-
<4>不支持循環,支持條件判斷,有內置變量
-
<5>使用終止語句return(XXX),沒有返回值,僅僅是標明下一步交給哪個狀態引擎
-
<6>域專用,語句用{ }括起來,用sub聲明,指明為哪一段的專用代碼,如:sub vcl_recv{…},可理解為一個配置段
-
<7> 每個語句必須以;分號結尾
-
<8> 每個變量有其能使用的引擎的位置,可理解為變量由其可用的配置段
-
<9>操作符:=(賦值)、==(等值比較)、~(模式匹配)、!(取反)、&&(邏輯與)、||(邏輯或)、>(大于)、>=(大于等于)、<(小于)、<=(小于等于)
注意,各個狀態引擎有其默認的配置,無論各個vcl引擎內的配置如何修改,該狀態引擎的默認的配置都會自動附加在修改的配置之后生效
查看默認的配置可以用:varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 –> vcl.show -v 配置名稱
4、vcl常見內建的函數
VCL提供了幾個函數來實現字符串的修改,添加bans,重啟VCL狀態引擎以及將控制權轉回Varnish等。
-
regsub(str,regex,sub)和regsuball(str,regex,sub):
這兩個用于基于正則表達式搜索指定的字符串并將其替換為指定的字符串;但regsuball()可以將str中能夠被regex匹配到的字符串統統替換為sub,regsub()只替換一次; -
ban(expression):清除能被表達式匹配的所有緩存對象
-
ban_url(regex):清除所有其URL能夠由regex匹配的緩存對象;
-
hash_data(str):對指定的字符串做hash計算后的結果
-
return():
當某VCL域運行結束時將控制權返回給Varnish,并指示Varnish如何進行后續的動作;其可以返回的指令包括:lookup、hash、hit、miss、pass、pipe、hit_for_pass、purge等;但某特定域可能僅能返回某些特定的指令,而非前面列出的全部指令; -
return(restart):
重新運行整個VCL,即重新從vcl_recv開始進行處理;每一次重啟都會增加req.restarts變量中的值,而max_restarts參數則用于限定最大重啟次數。
VCL的函數不接受參數并且沒有返回值,因此,其并非真正意義上的函數,這也限定了VCL內部的數據傳遞只能隱藏在HTTP首部內部進行。
VCL的return語句用于將控制權從VCL狀態引擎返回給Varnish進程,而非默認函數,這就是為什么VCL只有終止語句而沒有返回值的原因。同時,對于每個“域”來說,可以定義一個或多個終止語句,以告訴Varnish下一步采取何種操作,如查詢緩存或不查詢緩存等。
5、vcl的內建變量的分類
-
req.*:req.開頭的變量,由客戶端發來的http請求相關的變量
如: req.method 表示客戶端的請求方法 req.url 表示客戶端請求的url req.http.host 表示客戶端請求報文的主機 req.http.* *可以是http請求報文的任意首部的名稱,代表引用http的某個請求首部
-
bereq.* :bereq.開頭的變量,varnish主機在向后端真實服務器發送http請求報文時的相關變量
如: 可以將真實的客戶端地址傳遞給后端真實web服務器,以便于后端真實服務器記錄客戶端的真實IP,而不是varnish的IP
-
breq.http.* 代表varnish發往后端的真實的web服務器的相關的請求報文中的首部
-
beresp.*:beresp.開頭的變量,由后端真實服務器發來的http響應報文中的某些首部信息相關的變量,一般是在vcl_backend_response或vcl_backend_fenth引擎中調用
-
resp.*:resp.開頭的變量,由varnish響應給客戶端的響應報文相關的變量
-
一般用在vcl_deliver引擎中進行調用,因為deliver引擎是用于給客戶端構建響應報文,發送響應報文
-
resp.http.: 可以是響應報文中的任意首部的名稱,代表引用某個響應報文的值,可用于設定、添加、修改響應給客戶端的響應報文中的響應首部的值
-
obj.* :obj.開頭的變量,對存儲在緩存空間中的緩存對象屬性的引用變量。obj開頭的變量都是只讀的
如: obj.hits: 某個緩存對象的緩存的命中次數
-
client.,server.,storage.*:可用在所有面向客戶端一側的引擎中,也就是vcl_recv、vcl_pipe、vcl_hash、vcl_pass、vcl_purge、vcl_miss、vcl_hit、vcl_deliver、vcl_synth中
如: client.ip 代表客戶端的IP地址 server.ip 代表當前varnish的IP地址 client.port 代表客戶端的端口 server.port 代表當前varnish的端口
-
用戶自定義變量
-
可用set,來設定某個用戶自定義變量或現有變量的值
-
可用unset,來取消某個用戶自定義變量,或刪除現有變量
6、vcl內建變量的可用在哪些vcl引擎配置段和相應的讀寫權限
7、vcl常見的內置變量的說明
-
bereq.*
-
bereq.http.HEADERS: 表示varnish發往后端真實web服務器的請求報文中的某個首部
-
bereq.request: 表示varnish發往后端真實web服務器的請求報文的請求方法(4.0版本的varnish改為了bereq.method)
-
bereq.url:表示varnish發往后端真實web服務器的請求報文的請求的url
-
bereq.proto:表示varnish發往后端真實web服務器的請求報文的http協議的協議版本
-
bereq.backend:表示要varnish發送請求到后端真實web服務器時,后端服務器不止一臺時,所調用的后端主機
-
beresp.*
-
beresp.http.HEADERS:表示后端真實web服務器發給varnish的http響應報文的某個首部的信息
-
beresp.proto:表示后端真實web服務器發給varnish的http響應報文的http協議版本
-
beresp.status:表示后端真實web服務器發給varnish的http響應報文的響應狀態碼
-
beresp.backend.name:表示后端真實web服務器發給varnish的http響應報文的后端主機的名稱
-
beresp.ttl:后端服務器響應中的內容的余下的生存時長
-
obj.*
-
obj.hit 此對象在緩存中命中的次數
-
obj.ttl 此對象的ttl值,也就是其緩存時長
-
server.*
-
server.ip 當前varnish的IP
-
server.hostname 當前varnish的主機名
-
req.*
-
req.http.HEADERS: 表示客戶端發送給varnish的請求報文中的某個首部
-
req.request: 表示客戶端發送給varnish的請求報文的請求方法(4.0版本的varnish改為了req.method)
-
req.url:表示客戶端發送給varnish的請求報文的請求的url
-
req.proto:表示客戶端發送給varnish的請求報文的http協議的協議版本
-
resp.*
-
resp.http.HEADERS:表示varnish發送給客戶端的響應報文的某個首部的信息
-
resp.proto:表示varnish發送給客戶端的http響應報文的http協議版本
-
resp.status:表示varnish發送給客戶端的http響應報文的響應狀態碼
-
自定義變量:可用set 變量名= 值 來設定變量
如:set resp.http.X-Cache = "HIT" 表示設定響應給客戶端的響應報文中設定X-Cache首部的值為HIT 如:set resp.http.IS-Cache = "YES"+" "server.ip 表示設定響應給客戶端的響應報文中的IS-Cache首部的值為"YES varnish服務器IP",多個元素之間要用+加號連接,如果要輸出空格,需要用""引號引起來
-
取消某變量:用unset 變量名
如: unset req.http.cookie 表示取消客戶端請求報文中http的cookie首部信息 unset beresp.http.Set-cookie 表示取消后端服務器發送到varnish上的響應報文http首部中的Set-cookie首部
第三章 varnish的安裝配置
1、安裝:
varnish已被收錄進EPEL源,故可直接利用EPEL源進行yum安裝 yum install -y varnish
2、安裝生成的程序環境
監聽的端口為: 服務監聽的端口默認為6081 管理接口默認監聽的端口為6082 /etc/varnish/varnish.params: 配置varnish服務進程的工作特性,官方提供的rpm包安裝的程序,其對應的程序自身配置文件在/etc/sysconfig/varnishd,例如監聽的地址和端口,緩存機制; /etc/varnish/default.vcl: 配置各Child/Cache線程的工作屬性; 主程序: /usr/sbin/varnishd 命令行管理工具程序: /usr/bin/varnishadm Shared Memory Log交互工具: /usr/bin/varnishhist /usr/bin/varnishlog /usr/bin/varnishncsa /usr/bin/varnishstat /usr/bin/varnishtop 測試工具程序: /usr/bin/varnishtest VCL配置文件重載程序: /usr/sbin/varnish_reload_vcl Systemd Unit File: /usr/lib/systemd/system/varnish.service varnish服務 /usr/lib/systemd/system/varnishlog.service /usr/lib/systemd/system/varnishncsa.service 日志持久的服務;
3、varnish程序自身的配置文件介紹
自身的配置文件為:/etc/varnish/varnish.params
有的版本的rpm包安裝的可能是/etc/sysconfig/varnishd
RELOAD_VCL=1 設置為1表示當使用systemctl reload varnish時,會自動重新裝載vcl的配置文件,也就是能夠讓新的配置生效 VARNISH_VCL_CONF=/etc/varnish/default.vcl 加載的緩存策略的配置文件路徑 #VARNISH_LISTEN_ADDRESS= varnish服務監聽的地址,默認是監聽在本機所有可用的地址上 VARNISH_LISTEN_PORT=6081 varnish監聽的端口,因為varnish要作為web服務器的反代進行工作時,才能將http的內容緩存,因此,一般要將其改為80端口,但是實際生產環境中,varnish一般是處于前端調度器的后面,所以可以在前端調度器上將調度的端口改為此處的端口也可以 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 varnish管理接口監聽的地址,監聽在127.0.0.1表示只允許從本機登錄進行管理 VARNISH_ADMIN_LISTEN_PORT=6082 varnish管理接口監聽的端口 VARNISH_SECRET_FILE=/etc/varnish/secret varnish管理時的秘鑰文件 VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G" varnish緩存時,使用哪種存儲方式對緩存內容進行存儲,本處是指使用file文件方式,存在/var/lib/varnish/varnish_storage.bin文件中,總共使用1G大小的空間 如果要使用內存緩存,則可以定義為:"malloc,400M" 在很多生產環境還是使用file,但是將文件放在固態硬盤,如果希望性能更好點,放在PCI-E的固態硬盤 VARNISH_TTL=120 如果后端服務器沒有指明緩存內容的TTL時間,則varnish自身為緩存定義的TTL時間 VARNISH_USER=varnish VARNISH_GROUP=varnish 以上選項,實際是varnishd運行時調用時讀取的變量,實際還有很多參數要指明,如varnish線程池的數量,以及每個線程池的線程數,此時要在varnish程序自身的配置文件中,利用 DAEMON_OPTS="-p thread_polls=2 -p thread_pool_min=100 -p thread_pool_max=5000 -p thread_pool_timeout=300" 用-p指明參數和對應的值,其指明的選項有很多,具體可以參照man varnishd手冊
4、varnishadm命令行管理工具的使用
varnishadm的工作模式有兩種
-
一種是直接shell命令行模式下進行:
varnishadm [-t TIMEOUT] [-S SECRET_FILE] -T [ADDRESS]:PORT COMMAND... -t 指明連接varnish管理的超時時間,一般無需指定 -S 指明與varnish通行時用到的秘鑰文件路徑,也就是我們在/etc/varnish/varnish.params中定義的VARNISH_SECRET_FILE的值所指定的秘鑰文件的路徑 -T [ADDRESS]:PORT 指明varnish管理的地址和端口,也就是我們在/etc/varnish/varnish.params中定義的VARNISH_ADMIN_LISTEN_ADDRESS和VARNISH_ADMIN_LISTEN_PORT,如果地址不給定,則默認為本地 COMMAND 指明要運行的varnish命令
-
另一種是varnishadm的交互式模式
varnishadm [-t TIMEOUT] [-S SECRET_FILE] -T [ADDRESS]:PORT 運行此命令后,即可進入交互式命令模式
-
交互式命令模式下的varnish命令介紹
5、vcl_recv狀態引擎的默認配置介紹
進入vcl的交互式界面,用vcl.show -v 編譯后的配置名稱
即可顯示各個狀態引擎默認的配置,各個狀態引擎的默認配置會自動附加在各個狀態引擎自定義的配置段的后面生效
第四章 vcl配置示例
以具體配置,說明varnish的常見配置
配置環境說明:
1、配置各個節點的網絡環境,安裝各個節點所需的服務器過程
-
nginx調度器的配置
-
靜態httpd的web服務器1的配置(httpd2.2的配置,如果是httpd2.4則對應修改下配置文件,顯示授權網頁目錄即可)
-
靜態httpd的web服務器2的配置
2、配置varnish服務器,將請求反代到后端的一臺主機上
3、如何驗證緩存是否命中
可通過在vcl_deliver狀態引擎上加上一個判斷機制,然后設定給客戶端的響應報文的某個首部的值來實現
4、如何獲知是從哪個varnish服務器命中的緩存
可通過在上個實驗的基礎上,在響應給客戶端的報文的首部的值中,添加上當前varnish服務器的IP來實現
5、限定客戶端的某些請求不進行緩存
當某些情況下,我們希望客戶端訪問的某些網頁路徑不能緩存時,如訪問的是相管管理頁面時,不進行緩存,則可以在vcl_recv引擎中針對用戶請求的報文的URL進行過濾,因為是根據客戶端的請求報文的相關信息進行條件匹配,因此應該在vcl_recv狀態引擎中定義相關策略
通過此種方式,可以對客戶端請求報文中的任意首部信息進行過濾,滿足或不滿足一定的條件時,我們可以定義其可不可以緩存
6、刪除客戶端的請求報文中的某些首部(如cookie信息),或后端服務器響應的某些首部(如設定cookie的首部信息),強制進行緩存,提高緩存命中率
當請求報文首部中有cookie信息時,是很難命中緩存的,因為一旦有cookie信息,varnish中緩存的鍵值信息中鍵的值就是請求的url和cookie信息組成,然后hash計算出來的結果,這樣就非常難以命中緩存,所以,對于一些不涉及敏感信息的cookie信息,我們應該在首部中進行清除之后,再進行緩存比匹配
注意:為了提高緩存命中率,應該將請求報文中的無用的cookie信息移除,在響應報文中,無效的cookie信息也將其移除,以保證緩存命中率;要移除用戶請求報文中的cookie信息,要在vcl_recv中進行,要移除后端服務器響應報文中的cookie信息,要在vcl_backend_response中進行
-
示例1:假設,我們定義除了login和admin相關的cookie信息,其他頁面的cookie信息都取消
編輯vcl配置文件/etc/vanish/default.vcl配置文件,在對應的引擎段加入 sub vcl_recv { if(!(req.url ~ "(?i)^/(login|admin)")) { unset req.http.cookie } } //表示針對客戶端的請求報文中,如果其請求的url不是以/login或/admin開頭的,則取消其請求報文首部中的cookie首部的信息,從而實現了提高緩存命中率的效果,因為請求首部中如果有cookie信息,是很難命中緩存的 sub vcl_backend_response { if(!(bereq.url ~ "(?i)^/(login|admin)")) { unset beresp.http.Set-cookie } } //表示針對后端服務器的響應報文中,如果響應的請求的url不是以/login或/admin開始的,則取消其響應報文中的Set-cookie的首部,表示不對此類信息設定cookie,從而提高了緩存命中率
-
示例2:示例:對于特定類型的資源,如公開的圖片等,取消其私有標識,并強行設定其可以由varnish緩存的時長
sub vcl_backend_response { if (beresp.http.cache-control !~ "s-maxage") { if (bereq.url ~ "(?i)\.(jpg|pbg|gif|jpeg)$") { unset beresp.Set-Cookie; set beresp.ttl = 7200s; } if (bereq.url ~ "(?i)\.(css|js)$") { unset beresp.Set-Cookie; set beresp.ttl = 3600s; } } } //表示當后端服務器的響應報文中,cache-control首部的值不匹配s-maxage,也就是沒有設定公共緩存的時長的響應報文,如果請求到后端主機的請求報文中的url是以.jpg結尾("(?i)表示不區分大小寫"),就設定其響應報文的緩存的ttl時長為7200秒,然后取消響應報文中的Set-Cookie的首部,進行緩存 //請求到后端主機的請求報文中的url是以.css結尾("(?i)表示不區分大小寫"),就設定其響應報文的緩存的ttl時長為7200秒,然后取消響應報文中Set-Cookie的首部,進行緩存
7、基于purge方式對緩存對象進行修剪
提高緩存命中率的最有效途徑之一是增加緩存對象的生存時間(TTL),但是這也可能會帶來副作用,比如緩存的內容在到達為其指定的有效期之間已經失效。因此,有時手動讓緩存的內容失效,是必要的
purge方法:是對單個緩存項進行清理
ban方法:對符合ban提供的表達式的所有緩存項一起清理
本例中使用purge方式對緩存進行修剪
先要定義vcl_purge狀態引擎、再針對客戶端的請求報文的首部進行匹配,匹配到某個特定信息時,就調用定的purge引擎進行處理
8、vcl的acl訪問控制機制,也就是基于IP的訪問控制
上個實驗中,針對PURGE方法,如果其他人知道了利用此請求方法可以對緩存項進行修剪,而使用此方法請求頁面數據,會造成很大的隱患,因此應該對其進行訪問控制,也就是只允許來自哪些IP的訪問請求使用PURGE方法
根據此思路,可以實現基于客戶端請求報文來源IP的訪問控制機制
-
基于此acl方法,還可以實現基于IP的訪問控制,如:
假設要拒絕某些IP的訪問,則可以: acl testpurgers { "10.1.32.0"/24; } sub vcl_recv { if (client.ip ~ testpurgers) { return(synth(405,"NO ACCESS")); } }
9、當varnish后端有多臺服務器時(沒臺服務器提供不同的內容),實現請求不同的資源,到不同的后端服務器上去請求
實際是先定義多個后端主機,然后判斷請求報文的uri,利用設定req.backend_hint首部,讓其對應到相關的后端服務器上
如:請求圖片時,讓varnish到后端的web2服務器上的第一個虛擬主機(也就是10.1.32.69的虛擬主機)上請求,如果請求的是文本資源(.txt結尾的資源)時,讓其到web1服務器上的第二個虛擬主機上(10.1.32.168)請求,其他的資源都到web1服務器上的第一個虛擬主機(10.1.32.68)上請求
10、當后端同一類資源有多臺主機時,對后端多臺主機的負載均衡請求
實際就是將后端的多臺主機定義為一個主機組,然后當滿足一定條件時,將請求調度到該主機組,而不是調度到單臺主機,通過引入vcl_init狀態引擎,new一個主機組,然后想該主機組內添加定義的主機,調度時,向該主機組內進行調度即可
-
定義示例格式:
import directors; # 需要導入directors功能 backend server1 { .host = .port = } backend server2 { .host = .port = } sub vcl_init { new GROUP_NAME = directors.round_robin(); GROUP_NAME.add_backend(server1); GROUP_NAME.add_backend(server2); } sub vcl_recv { # send all traffic to the bar director: set req.backend_hint = GROUP_NAME.backend(); }
如:請求.txt內資源時,讓varnish到后端的web2服務器上的第一個虛擬主機(也就是10.1.32.69的虛擬主機)上請求,和web1服務器上的第二個虛擬主機(10.1.32.168)上請求;如果請求的是.html資源時,讓其到web1服務器上的第一個虛擬主機上(10.1.32.68)和web2服務器上的第二個虛擬主機(10.1.32.169)上請求
-
注意:此實驗要想明顯看到請求被調度到不同的后端主機上,需要請求的資源不能被緩存,因為一旦緩存了后,資源就直接從varnish緩存響應了,再次請求就不會看到被調度到其他后端主機的效果
11、探測后端主機的健康性,當后端主機故障時,不往該主機上調度請求,當后端主機恢復后,又自動向該主機調度請求
在定義backend時,用.probe定義該主機對應的健康狀況檢測機制,當探測到某個主機不在線時,會自動將該后端主機移除
也可以單獨定義健康狀況檢測的probe配置段,然后在各個后端主機上進行引用
backend BE_NAME { .host = .port = .probe = { .url= .timeout= .interval= .window= .threshhold= } } .probe:定義健康狀態檢測方法; .url:檢測時請求的URL,默認為”/"; .request:發出的具體請求;(用于不使用.url檢測時) .request = "GET /.healthtest.html HTTP/1.1" "Host: www.nwc.com" "Connection: close" .window:基于最近的多少次檢查來判斷其健康狀態; .threshhold:最近.window中定義的這么次檢查中至有.threshhold定義的次數是成功的; .interval:檢測頻度; .timeout:超時時長; .expected_response:期望的響應碼,默認為200;用于基于.request機制時定義響應機制 健康狀態檢測的配置方式: (1) probe PB_NAME = { } backend NAME = { .probe = PB_NAME; ... } (2) backend NAME { .probe = { ... } }
-
示例:為上述實驗的后端主機定義健康性檢測機制
第五章 varnish日志管理工具的使用
1、varnishstat命令
varnish的緩存統計數據,類似htop命令的風格動態顯示統計格式,會顯示當前的數據,正在變化的而數據,平均數據,10分鐘平均數據,100分鐘平均數據,1000分鐘平均數據
2、varnishtop命令
可以類似系統上top命令一樣,動態顯示varnish的日志統計信息,按序排列,可以對其進行指定由哪個字段進行排序
只想顯示一次,而不是動態刷新顯示,則可以: varnishtop -1 只想顯示某個字段的值: varnishtop -i 字段名1,字段名2,... 只想顯示1次某字段的值,而不是動態刷新顯示: varnishtop -1 -i 字段名1,字段名2,... 除了某字段,都顯示: varnishtop -x 字段名 除了某字段,都顯示,但只顯示刷新一次的結果: varnishtop -1 -x 字段名
3、varnishlog命令
交互式顯示varnish的日志,只是顯示的格式是原始格式,也可以將varnishlog服務打開,讓其脫離日志90M的限制,但是varnishlog服務和varnishncsa服務建議只開啟一個,一般開啟varnishnasa
4、varnishncsa命令
交互式顯示類型httpd的combined格式的日志
varnish本身只有90M的空間來存儲日志,超過90M的部分,新的日志會覆蓋舊的日志,如果要記錄更多的日志信息,則可以將varnishnasa服務打開,讓其記錄日志,日志格式為combined格式
第六章 varnish性能優化
1、varnish的相關運行時參數
-
thread_pool_max 5000 [threads]
每個線程池最大啟動線程池個數,最大不建議超過5000 -
thread_pool_min 100 [threads]
每個線程池最小啟動的線程個數(額外的意義為,最大的空閑線程數) -
thread_pool_stack 48k [bytes]
每個線程的棧的空間大小 -
thread_pool_timeout 300.000 [seconds]
線程池的超時時間,也就是一個線程空閑多長時間就會被關閉,因為線程池有最大和最小數量,線程個數動態在最大和最小之間動態調整 -
thread_pools [pools]
線程池個數,,默認為2個,最好小于或等于CPU核心數量 -
thread_queue_limit 20 requests
每個線程池最大允許的等待隊列的長度 -
thread_stats_rate 10 [requests]
線程最大允許處理多少個請求后一次性將日志信息寫入日志區域 -
workspace_thread 2k [bytes]
每個線程額外提供多大空間作為其請求處理的專用工作空間 -
thread_pool_add_delay
創建線程時的延遲時間,也就是,需要創建線程時,不是立即創建,而是延遲一段時間,說不定在此時間內有線程空閑下來,從而不用創建新的線程 -
thread_pool_destroy_delay
銷毀線程時的延遲時間,也就是當需要銷毀線程時,不是立即就銷毀,而是等一段時間再銷毀,以免有新的請求進來而導致需要新建新線程處理
最大的并發連接數=thread_pools*thread_pool_max
2、調整參數的方式一:交互式命令行模式
varnish以及運行,在運行時進行調整其相關參數,讓其動態生效,但是重啟varnish服務后失效
注意:重啟varnish會導致緩存全部失效,造成嚴重后果,慎重
3、調整參數方法二:配置文件模式
在其配置文件/etc/varnish/varnish.params文件中,用DAEMON_OPTS="-p ARGS1=VALUE1 -p ARGS2=VALUE2 …"來設置,然后啟動varnish
此種方式適合于尚未啟動varnish,直接在配置文件中修改其運行時參數,永久有效
但是如果varnish已經啟動,則如果重啟varnish會導致緩存全部丟失,慎重
如果已經啟動,又想永久有效,可以在命令行下調整后,將相關的參數寫到配置文件
原創文章,作者:M20-1倪文超,如若轉載,請注明出處:http://www.www58058.com/58826