1. 程式人生 > >Varnish高性能緩存服務器

Varnish高性能緩存服務器

客戶 hint 緩存服務器 內存區域 fff 檢查 不能 防火墻規則 提升

一、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高性能緩存服務器