Varnish高性能緩存服務器
- 一款高性能、開源的HTTP反向代理服務器和緩存服務器,挪威最大的在線報紙 Verdens Gang 使用3臺Varnish代替了原來的12臺Squid,性能比以前更好。
- Varnish使用內存做為緩存設備(純內存緩存服務器方案),相對於Squid(采用硬盤緩存),擁有更快的緩存速度(varnish內存管理完全交給內核,但當緩存內容超過閾值時,內核會自動將一部分緩存存入swap中,讓出內存)
1.Varnish進程
Varnish與一般服務器軟件類似,分為master(management)進程和child(主要做cache的工作)
Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,如果在指定的時長內未得到Child進程的回應,Management將會重啟此 Child進程
Child進程包含多種類型的線程,常見的如:
- Acceptor線程:接收新的連接請求並響應
- Worker線程:child進程會為每個會話啟動一個worker線程,因此,在高並發的場景中可能會出現數百個worker線程甚至更多
- Expiry 線程:從緩存中清理過期內容;Varnish依賴“工作區(workspace)”以降低線程在申請或修改內存時出現競爭的可能性
在varnish內部有多種不同的工作區,其中最關鍵的當屬用於管理會話數據的session 工作區
2.Varnish日誌
為了與系統的其它部分進行交互,Child進程使用了可以通過文件系統接口進行訪問的共享內存日誌(shared memory log),當某線程需要記錄信息,其僅需要持有一個鎖,而後向共享內存中的某內存區域寫入數據,再釋放持有的鎖即可。而為了減少競爭,每個 worker線程都使用了日誌數據緩存
- 共享內存日誌大小一般為 90M,其分為兩部分,前一部分為計數器,後半部分為客戶端請求的數據。varnish提供了多個不同的工具如varnishlog、varnishncsa或varnishstat等來分析共享內存日誌中的信息並能夠以指定的方式進行顯示
3.Varnish中的VCL
VCL(Varnish Configuration Language)是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命令完成
4.Varnish後端存儲(緩存數據的方式)
varnish支持多種不同類型的後端存儲,這可以在varnishd啟動時使用-s選項指定
存儲的類型包括:
- file:使用特定的文件存儲全部的緩存數據,並通過操作系統的mmap()系統函數調用將整個緩存文件映射至內存區域(如果條件允許);
- malloc:使用malloc()函數調用在varnish啟動時向操作系統申請指定大小的內存空間以存儲緩存對象
- persistent(experimental):與file的功能相同,但可以持久存儲數據(即重啟 varnish數據時不會被清除),仍處於測試期
varnish無法追蹤某緩存對象是否存入了緩存文件,從而也就無從得知磁盤上的緩存文件是否可用,因此file存儲方法在varnish停止或重啟時會清除數據。而persistent方法的出現對此有了一個彌補,但persistent仍處於測試階段,例如目前尚無法有效處理要緩存對象總體大小超出緩存空間的情況,所以其僅適用於有著巨大緩存空間的場景
選擇使用合適的存儲方式有助於提升系統性,從經驗的角度來看,建議在內存空間足以存儲所有的緩存對象時使用malloc的方法,反之file存儲將有著更好的性能的表現。然而需要註意的是,varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,一般說來其需要為每個緩存對象多使用差不多1K左右的存儲空間,這意味著,對於100萬個緩存對象的場景來說,其使用的緩存空間將超出指定大小1G左右。另外為了保存數據結構等,varnish 自身也會占去不小的內存空間
為 varnishd 指定使用的緩存類型時,-s 選項可接受的參數格式如下:
malloc[,size] 或file[,path[,size[,granularity]]] 或persistent,path,size {experimental}
file中的granularity用於設定緩存空間分配單位,默認單位是字節,所有其它的大小都會被圓整
5.Varnish 的特點
- 基於內存進行緩存,重啟後數據將消失
- 利用虛擬內存方式,I/O 性能好
- 支持設置 0~60 秒精確緩存時間
- VCL 配置管理比較靈活
- 32 位機器上緩存文件大小為最大 2GB
- 具有強大的管理功能
- 狀態機設計巧妙,結構清晰
- 利用二叉堆管理緩存文件,可達到積極刪除目的
6.Varnish與Squid對比
優點
- Varnish穩定性高,當Squid和Varnish同時完成相同負荷工作時,Squid發生故障的幾率高於Varnish,因為使用Squid要經常重啟
- Varnish訪問速度快,Varnish采用Visual Page Cache技術,所有緩存數據都直接從內存中讀取,而Squid從硬盤中讀取
- Varnish支持更多的並發連接,因為Varnish的TCP連接釋放要比Squid快,因此在高並發情況下可以支持更多的TCP連接
- Varnish可以通過管理端口,使用正則表達式批量的清除部分緩存
- Squid屬於單進程使用單核CPU,但Varnish通過fork形式打開多進程來處理,所以可以合理的使用所有核來處理相應的請求
缺點
- 高並發下,Varnish消耗更多的CPU、I/O和內存資源
- Varnish進程一旦掛起、崩潰或重啟,緩存的數據會從內存中釋放,此時所有的請求都會轉發到後端服務器上,給後端服務器造成很大壓力
- Varnish使用中如果單個url的請求通過HA/F5(負載均衡)每次請求到不同的Varnish服務器中,被請求的Varnish服務器都會被穿透到後端,而且同樣的請求會在多臺服務器上緩存,造成Varnish緩存的資源浪費,也造成性能下降
- Varnish不支持正向代理緩存
綜上所述在訪問量很大的情況下推薦使用varnish的內存緩存方式啟動,而且後面需要跟多臺squid服務器。主要為了防止前面的varnish服務、服務器被重啟的情況下,前期肯定會有很多的穿透這樣squid可以擔當第二層CACHE,而且也彌補了varnish緩存在內存中重啟都會釋放的問題
資源浪費的問題可以在負載均衡上做url哈希,讓單個url請求固定請求到一臺varnish服務器上,可以解決該問題
7.Varnish與其余主流軟件對比
二、Varnish工作原理
- Receive狀態:請求處理入口狀態,根據VCL規則判斷該請求應該Pass或Pipe,還是進入Lookup(本地查詢)
- Lookup狀態:進入此狀態後,會在hash表中查找數據,若找到則進入Hit狀態,否則進入Miss狀態
- Fetch狀態:在Fetch狀態下,對請求進行後端獲取、發送請求、獲得數據,並進行本地存儲
- Deliver狀態:將獲取到的數據發送給客戶端,然後完成本次請求
- Pipe狀態:不通過varnish,開通“管道”,直接有後端真實的web 節點回復客戶端請求
三、部署Varnish負載均衡高可用群集
主機 | 系統 | IP | 網卡 | 軟件 |
---|---|---|---|---|
Varnish | Centos 6.7 64Bit | 192.168.1.10 | vmnet1 | varnish |
Web1(Apache) | Centos 6.7 64Bit | 192.168.1.100 | vmnet1 | httpd |
Web2(Apache) | Centos 6.7 64Bit | 192.168.1.200 | vmnet1 | httpd |
Varnish
1.環境準備
vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0 //網卡名稱
TYPE=Ethernet //網卡類型為以太網
ONBOOT=yes //開機自啟該網卡
NM_CONTROLLED=no //關閉NetworkManager
BOOTPROTO=static //網卡設置為靜態方式
IPADDR=192.168.1.10 //IP地址配置
NETMASK=255.255.255.0 //子網掩碼配置
/etc/init.d/network restart
2.安裝Varnish
yum -y install libtool ncurses-devel pcre-devel libxslt groff pkgconfig gcc gcc-c++
//安裝varnish依賴的開發環境
rpm -ivh libedit-devel-2.11-4.20080712cvs.1.el6.x86_64.rpm
rpm -ivh python-imaging-1.1.6-19.el6.x86_64.rpm
rpm -ivh python-docutils-0.6-1.el6.noarch.rpm //安裝rpm依賴包
tar -zxvf varnish-4.0.1.tgz -C /usr/src/
cd /usr/src/varnish-4.0.1/
./autogen.sh //運行varnish腳本,會自動設置libtool變量等信息
./configure --prefix=/usr/local/varnish --enable-debugging-symbols --enable-developer-warnings
選項
--enable-debugging-symbols:開啟調試,調試一些bug信息的標誌,默認為“NO”
--enable-developer-warnings:啟用提示警告,默認為"NO"
make && make install
echo "PATH=$PATH:/usr/local/varnish/bin:/usr/local/varnish/sbin">>/etc/profile
//將varnish命令路徑加入PATH變量,這時在任意位置都可使用varnish相關命令
source /etc/profile //立即生效該PATH變量
3.配置Varnish
cp /usr/local/varnish/share/doc/varnish/example.vcl /usr/local/varnish/default.vcl
//拷貝默認提供的varnish配置文件到varnish目錄下
vim /usr/local/varnish/default.vcl
import directors; //加載directors模塊,提供負載均衡
backend web1 { //定義後端服務器的標識名稱
.host = "192.168.1.100"; //定義後端服務器的IP
.port = "80"; //定義後端服務器監聽端口
.probe = { //開啟健康檢查
.url = "/"; //檢查請求的URL(請求服務器的網頁根目錄)
.interval = 5s; //查詢的間隔時長(每隔幾秒檢測一次)
.timeout = 1s; //超時時間,即等待後端1s都無響應即為故障
.window = 5; //判斷健康狀態時,依最近多少次的檢測作為依據
.threshold = 3; //.window指定次數中,3次成功,才代表後端健康
}
}
backend web2 {
.host = "192.168.1.200";
.port = "80";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 1s;
.window = 5;
.threshold = 3;
}
}
sub vcl_init { //VCL初始化VMODs模塊,定義director
new bar = directors.round_robin(); //定義調度算法,該處為加權輪詢
bar.add_backend(web1); //添加標識名稱為web1的加入director
bar.add_backend(web2); //添加標識名稱為web2的加入director
}
sub vcl_recv {
set req.backend_hint = bar.backend(); //將所有的流量轉發給dictctors
}
varnishd -C -f /usr/local/varnish/default.vcl
//檢測VCL配置是否有誤,如輸出一系列的內置配置,即無問題,反之
varnishd -f /usr/local/varnish/default.vcl -a 0.0.0.0:80
//啟動varnish,並監聽當前服務器的80端口
-f /usr/local/etc/varnish/default.vcl
這個 –f 選項指定varnishd使用哪個配置文件。
-s malloc,1G
這個 –s 選項用來確定varnish使用的存儲類型和存儲容量,我使用的是malloc類型(malloc是一個C函數,用於分配內存空間), 1G 定義多少內存被malloced,1G = 1gigabyte。
-T 127.0.0.1:2000
Varnish有一個基於文本的管理接口,啟動它的話可以在不停止varnish的情況下來管理varnish。您可以指定管理軟件監聽哪個接口。當然您不能讓全世界的人都能訪問您的varnish管理接口,因為他們可以很輕松的通過訪問varnish管理接口來獲得您的root訪問權限。我推薦只讓它監聽本機端口。如果您的系統裏有您不完全信任的用戶,您可以通過防火墻規則來限制他訪問varnish的管理端口。
-a 0.0.0.0:8080
這一句的意思是制定varnish監聽所有IP發給8080端口的http請求,如果在生產環境下,您應該讓varnish監聽80,這也是默認的。
vcl配置文件的介紹請執行如何命令查看:
man /usr/local/varnish/share/man/man7/vcl.7
netstat -utpln | grep varnish
varnishlog //動態輸出varnish的緩存及客戶端訪問完整情況
varnish 命令參數
-f:指定varnish服務器的配置文件
-aaddress:port:表示varnish對httpd的監聽地址及端口
-Taddress:port:設定varnish的 telnet管理地址及端口
-baddress:port:表示後端服務器的地址及端口
-d:表示使用debug調試模式
-Pfile:varnish進程PID文件存放路徑
-s:varnish緩存文件位置與大小(-s file,文件路徑,大小)
-w:最小,最大線程和超時時間(例:-w 1200,5 1200 10)
Web1
vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0 //網卡名稱
TYPE=Ethernet //網卡類型為以太網
ONBOOT=yes //開機自啟該網卡
NM_CONTROLLED=no //關閉NetworkManager
BOOTPROTO=static //網卡設置為靜態方式
IPADDR=192.168.1.100 //IP地址配置
NETMASK=255.255.255.0 //子網掩碼配置
/etc/init.d/network restart
yum -y install httpd //安裝apache服務
echo "This is Web1">/var/www/html/index.html
//給第一臺Web服務器編寫測試頁面
/etc/init.d/httpd start && chkconfig --level 35 httpd on
//啟動httpd服務並設置為開機自啟
Web2
vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0 //網卡名稱
TYPE=Ethernet //網卡類型為以太網
ONBOOT=yes //開機自啟該網卡
NM_CONTROLLED=no //關閉NetworkManager
BOOTPROTO=static //網卡設置為靜態方式
IPADDR=192.168.1.200 //IP地址配置
NETMASK=255.255.255.0 //子網掩碼配置
/etc/init.d/network restart
yum -y install httpd //安裝apache服務
echo "This is Web2">/var/www/html/index.html
//給第二臺Web服務器編寫測試頁面
/etc/init.d/httpd start && chkconfig --level 35 httpd on
//啟動httpd服務並設置為開機自啟
測試
IE --> http://192.168.1.10(Varnish服務器IP)
測試負載均衡
註:測試負載均衡時,由於采用加權輪詢算法,因此有可能刷新幾次都在Web1服務器上,可多刷新幾次
測試高可用
ifdown eth0 //在Web1上輸入,模擬Web1故障
註:測試高可用時,由於Varnish強大的緩存能力,Web1的頁面會緩存,因此當將Web1停止時,可以還可以訪問到Web1,這是等待一會,讓Varnish自動清空緩存即可
Varnish高性能緩存服務器