1、varnish的基本介紹
Varnish 的作者Poul-Henning Kamp是FreeBSD的內核開發者之一,他認為現在的計算機比起1975年已經復雜許多。在1975年時,儲存媒介只有兩種:內存與硬盤。但現在計算 機系統的內存除了主存外,還包括了cpu內的L1、L2,甚至有L3快取。硬盤上也有自己的快取裝置,因此squid cache自行處理物件替換的架構不可能得知這些情況而做到最佳化,但操作系統可以得知這些情況,所以這部份的工作應該交給操作系統處理,這就是 Varnish cache設計架構。
Varnish與一般服務器軟件類似,就是一個web緩存代理服務器,分為master(management)進程和child(worker,主要 做cache的工作)進程。master進程讀入命令,進行一些初始化,然后fork並監控child進程。child進程分配若干線程進行工作,主要包 括一些管理線程和很多woker線程。
Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。 Management進程會每隔幾秒鍾探測一下Child進程以判斷其是否正常運行,如果在指定的時長內未得到Child進程的回 應,Management將會重啟此Child進程。
Child進程包含多種類型的線程,常見的如:
Acceptor線程:接收新的連接請求並響應;
Worker線程:child進程會為每個會話啟動一個worker線程,因此,在高並發的場景中可能會出現數百個worker線程甚至更多;
Expiry線程:從緩存中清理過期內容;
Varnish依賴“工作區(workspace)”以降低線程在申請或修改內存時出現競爭的可能性。在varnish內部有多種不同的工作區,其中最關鍵的當屬用於管理會話數據的session工作區。
進程的工作過程原理及過程:
2、varnish與squid的區別
varnish和squid在中小規模的應用上,varnish足夠輕量級,足夠好用,但是在巨大的並發請求來說,單個varnish所能夠承載的並發 訪問量大概在5000個連接請求左右,超出5000個可能就就得不穩定了;而在這里squid就能表現出良好的性能了,因此在大規模的企業級應用中仍然是 以squid居多,而在中小規模的自己公司的反向代理緩存中varnish居多;
3、varnish的日志說明
為了與系統的其它部分進行交互,Child進程使用了可以通過文件系統接口進行訪問的共享內存日志(shared memory log),因此,如果某線程需要記錄信息,其僅需要持有一個鎖,而后向共享內存中的某內存區域寫入數據,再釋放持有的鎖即可。而為了減少競爭,每個 worker線程都使用了日志數據緩存。
共享內存日志大小一般為90M,其分為兩部分,前一部分為計數器,后半部分為客戶端請求的數據。varnish提供了多個不同的工具如 varnishlog、varnishncsa或varnishstat等來分析共享內存日志中的信息並能夠以指定的方式進行顯示。
4、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命令完成。
5、varnish的后端存儲
varnish的緩存對象在每次服務重啟時都會被清空並重新建立,所以這些服務器都是不應該隨便去重啟的,varnish為了把數據更持久化的存儲,引入了更多的存儲機制,所以varnish支持多種不同的后端存儲;
varnish支持多種不同類型的后端存儲,這可以在varnishd啟動時使用-s選項指定。后端存儲的類型包括:
(1)file:使用特定的文件存儲全部的緩存數據,並通過操作系統的mmap()系統調用將整個緩存文件映射至內存區域(如果條件允許);
(2)malloc:使用malloc()庫調用在varnish啟動時向操作系統申請指定大小的內存空間以存儲緩存對象;
(3)persistent(experimental):與file的功能相同,但可以持久存儲數據(即重啟varnish數據時不會被清除);仍處於測試期;
varnish無法追蹤某緩存對象是否存入了緩存文件,從而也就無從得知磁盤上的緩存文件是否可用,因此,file存儲方法在varnish停止或重啟 時會清除數據。而persistent方法的出現對此有了一個彌補,但persistent仍處於測試階段,例如目前尚無法有效處理要緩存對象總體大小超 出緩存空間的情況,所以,其僅適用於有着巨大緩存空間的場景。
選擇使用合適的存儲方式有助於提升系統性,從經驗的角度來看,建議在內存空間足以存儲所有的緩存對象時使用malloc的方法,反之,file存儲將有 着更好的性能的表現。然而,需要注意的是,varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,一般說來,其需要為每個緩存對象多使用差 不多1K左右的存儲空間,這意味着,對於100萬個緩存對象的場景來說,其使用的緩存空間將超出指定大小1G左右。另外,為了保存數據結構 等,varnish自身也會占去不小的內存空間。
6、varnish的工作原理及工作流程
官方提供的工作流程圖:
vcl的工作方式是基於狀態引擎(state engine)來實現的;上圖說明:
vcl_recv的結果如果可以查詢緩存並可以識別,那就要到vcl_hash這步了,如果無法識別那就通過pipe(管道)送給vcl_pipe,如 果能識別,但不是一個可緩存的對象,那就通過pass送到vcl_pass去,vcl_hash之后就可查看緩存中有沒有了,有這個請求的對象就表示命中 (vcl_hit),如果沒有那就表示未命中(vcl_miss),如果命中的就可以直接通過deliver直接送給vcl_deliver響應了,如果 未命中就通過fetch交給vcl_fatch去后端服務器上去取數據,取回數據之后如果數據可以緩存就緩存(cache),本地緩存完之后再構建響應, 如果不可以緩存就不做緩存交給vcl_deliver響應了;而如果命中了交給vcl_pass,交給pass之后就要到Fetch objet from backend后端服務器上去取數據了,這是因為這個命中的對象可能是過期或者是要做單獨立額外的處理的;這就是vcl的狀態引擎過程。
一、安裝實現過程:
# 安裝varnish,版本是3.0.4-1.el6 [root@node0 ~]# rpm -ivh varnish-3.0.4-1.el6.x86_64.rpm varnish-docs-3.0.4-1.el6.x86_64.rpm varnish-libs-3.0.4-1.el6.x86_64.rpm [root@node0 ~]# rpm -ql varnish # 查看varnish的安裝文件[root@node0 ~]# vim /etc/sysconfig/varnish # 查看配置文件 NFILES=131072 # 所能夠打開的最大文件數 MEMLOCK=82000 # 用多大內存空間保存日志信息 DAEMON_COREFILE_LIMIT="unlimited" # 進程核心轉儲所使用的內存空間,unlimited表示無上限 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_MIN_THREADS=1 # 最少線程數 VARNISH_MAX_THREADS=1000 # 最大線程數 VARNISH_THREAD_TIMEOUT=120 # 線程的超時時間 VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin # 基於文件存儲時的文件路徑 VARNISH_STORAGE_SIZE=1G # 存儲文件的大小 VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" # 存儲的文件格式 VARNISH_TTL=120 # 聯系后端服務器的超時時間 DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \ -u varnish -g varnish \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE}" # 使用定義的各高級配置的參數 # 定義后端服務器 [root@node0 sysconfig]# cd /etc/varnish/ [root@node0 varnish]# cp default.vcl default.vcl.bak [root@node0 varnish]# mv default.vcl test.vcl [root@node0 varnish]# vim test.vclbackend webserver { .host = "172.16.27.1"; # 后端服務器的地址 .port = "80"; # 后端服務監聽的端口 } # 啟動服務 [root@node0 sysconfig]# service varnish start # 可以進入varnish的命令操作,進去后直接輸入help就可以查看幫助信息; [root@node0 varnish]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 200 201 ----------------------------- Varnish Cache CLI 1.0 ----------------------------- Linux,2.6.32-431.el6.x86_64,x86_64,-smalloc,-hcritbit Type 'help' for command list. Type 'quit' to close CLI session. varnish> help 200 377 help [command] ping [timestamp] auth response quit banner status start stop stats vcl.load <configname> <filename> vcl.inline <configname> <quoted_VCLstring> vcl.use <configname> vcl.discard <configname> vcl.list vcl.show <configname> param.show [-l] [<param>] param.set <param> <value> purge.url <regexp> purge <field> <operator> <arg> [&& <field> <oper> <arg>]... purge.list |
安裝配置好后端web服務器並啟動,地址為172.16.27.1,而后通過varnish服務器地址訪問后端服務器,這里僅僅只是定義一指向后端服務 器,也就說現在也只能工作起來,但是還沒有定義相關的緩存屬性等信息,那就先通過varnish服務器端訪問一下先吧:
[root@node1 ~]# yum -y install httpd php php-mysql [root@node1 ~]# cd /var/www/html [root@node1 html]# vim index.html <h1>www.tanxw.com and varnish fo backend</h1> |
二、設置響應是否命中,接着繼續編寫配置文件:
[root@node0 varnish]# vim test.vcl sub vcl_deliver { # 定義子例程 if (obj.hits > 0){ # 判斷如果命中了就在http響應首部設置X-Cache為HIT set resp.http.X-Cache = "HIT from " server.ip; } else { # 否則就在http響應首部設置X-Cache為MISS set resp.http.X-Cache = "MISS";} } # 在varnish的命令行中重新編譯重新加載配置文件 varnish> vcl.load test1 /etc/varnish/test.vcl 200 13
backend webserver { [root@node0 varnish]# curl -I http://172.16.27.88/index.html # 也可以在命令行請求 |
然后再到頁面上訪問看一下是否已經生效:
三、指定某些文件不能查緩存,斷續添加配置文件
[root@node0 varnish]# vim test.vcl # 添加如下代碼 sub vcl_recv { # 定義請求的文件中如果匹配test.html就pass,就不查緩存 return(pass); } return(lookup); } # 再到varnish的命令行中重新加載配置文件並應用 varnish> vcl.load test4 /etc/varnish/test.vcl # 在命令行請求看一下緩存,不管怎么請求X-Cache都是MISS [root@node0 varnish]# curl -I http://172.16.27.88/test.html |
而后再請求test.html頁面;
四、設定緩存時長和定義圖片防盜鏈:
[root@node0 varnish]# vim default.vcl sub vcl_fetch { if (req.url ~ "\.(jpg|jpeg|gif|png)$") { # 如果url是以圖片格式結尾的緩存2小時set beresp.ttl = 7200s; } if (req.url ~ "\.(html|css|js)$") { # 如果url是以html|css|js結尾的緩存20分鍾 set beresp.ttl = 1200s; } } sub vcl_recv { # 圖片防盜鏈 |
五、移除單個緩存對象:purge 用於清理緩存中的某特定對象及其變種(variants),因此,在有着明確要修剪的緩存對象時可以使用此種方式。HTTP協議的PURGE方法可以實現 purge功能,不過,其僅能用於vcl_hit和vcl_miss中,它會釋放內存工作並移除指定緩存對象的所有Vary:-變種,並等待下一個針對此 內容的客戶端請求到達時刷新此內容。另外,其一般要與return(restart)一起使用。
[root@node0 varnish]# vim default.vcl acl purgers { # 定義acl訪問控制,只允許以下網段或主機執行purgers操作 "172.16.0.0"/16; } sub vcl_recv { if (req.request == "PURGE") { # 如果請求方法是PURGE,並且客戶端IP在上面定義的網段內的就允許執行PURGE操作,否則生成一個錯誤頁面返回給用戶 if (!client.ip ~ purgers) { error 405 "Method not allowed"; } return (lookup); } } sub vcl_hit { if (req.request == "PURGE") { # 如果緩存中命中,那么就清除緩存內容 purge; error 200 "Purged"; } } sub vcl_miss { if (req.request == "PURGE") { # 如果緩存中未命中,說明緩存中沒有內容 purge; error 404 "Not in cache"; } } sub vcl_pass { if (req.request == "PURGE") { # 如在pass中要清除緩存,直接返回錯誤碼 error 502 "PURGE on a passed object"; } } # 保存退出,而后直接在命令行中進行測試一下: [root@node0 varnish]# curl -I http://172.16.27.88/index.html [root@node0 varnish]# curl -X PURGE http://172.16.27.88/index.html [root@node0 varnish]# curl -I http://172.16.27.88/index.html |
六、Varnish檢測后端主機的健康狀態:
Varnish可以檢測后端主機的健康狀態,在判定后端主機失效時能自動將其從可用后端主機列表中移除,而一旦其重新變得可用還可以自動將其設定為可 用。為了避免誤判,Varnish在探測后端主機的健康狀態發生轉變時(比如某次探測時某后端主機突然成為不可用狀態),通常需要連續執行幾次探測均為新 狀態才將其標記為轉換后的狀態。
每個后端服務器當前探測的健康狀態探測方法通過.probe進行設定,其結果可由req.backend.healthy變量獲取,也可通過varnishlog中的Backend_health查看或varnishadm的debug.health查看。
.probe中的探測指令常用的有:
(1) .url:探測后端主機健康狀態時請求的URL,默認為“/”;
(2) .request: 探測后端主機健康狀態時所請求內容的詳細格式,定義后,它會替換.url指定的探測方式;比如:
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close";
(3) .window:設定在判定后端主機健康狀態時基於最近多少次的探測進行,默認是8;
(4) .threshold:在.window中指定的次數中,至少有多少次是成功的才判定后端主機正健康運行;默認是3;
(5) .initial:Varnish啟動時對后端主機至少需要多少次的成功探測,默認同.threshold;
(6) .expected_response:期望后端主機響應的狀態碼,默認為200;
(7) .interval:探測請求的發送周期,默認為5秒;
(8) .timeout:每次探測請求的過期時長,默認為2秒;
backend webserver { .host = "www.magedu.com"; # 定義后端主機 .probe = { .url = "/.healthtest.html"; # 向后端主機獲取這個頁面 .interval = 1s; # 每隔1秒鍾嘗試一次 .window = 5; # 最多嘗試5次,判斷采樣的樣本 .threshold = 2; # 如果采樣5次,如果有2次是錯誤的,就認為是失敗的,上線也是一樣 }} |
七、Varnish的命令行工具
varnishadm命令語法:varnishadm [-t timeout] [-S secret_file] [-T address:port] [-n name] [command [...]]
通過命令行的方式連接至varnishd進行管理操作的工具,指定要連接的varnish實例的方法有兩種:
-n name —— 連接至名稱為“name”的實例;
-T address:port —— 連接至指定套接字上的實例;
其運行模式有兩種,當不在命令行中給出要執行的"command"時,其將進入交互式模式;否則,varnishadm將執行指定的"command"並退出。要查看本地啟用的緩存,可使用如下命令進行。
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 storage.list
總結:
varnish是一個很強大的緩存服務器,還可以做動靜分離,這里限於篇幅,在這里就不一一例舉了,有關信息可以參數官方文檔,還可以做后端服務器的調度等,於是這里總結得過於倉促,有做得不到之處還望大神多多指出,如果有什么問題可以留言交流學習。