varnish運行機制及管理優化


Varnish 代理緩存服務器php

Varnish之於squid就比如nginx之於apache,是一款輕量級的代理緩存服務器,在CDN(內容分發網絡)中廣爲使用。
css


Varnish Configuration Language (VCL)varnish配置緩存策略的工具,它是一種基於「域」(domain specific)的簡單編程語言,它支持有限的算術運算和邏輯運算操做、容許使用正則表達式進行字符串匹配、容許用戶使用set自定義變量、支持if判斷語句,也有內置的函數和變量等。使用VCL編寫的緩存策略一般保存至.vcl文件中,其須要編譯成二進制的格式後才能由varnish調用。事實上,整個緩存策略就是由幾個特定的子例程如vcl_recvvcl_fetch等組成,它們分別在不一樣的位置(或時間)執行,若是沒有事先爲某個位置自定義子例程,varnish將會執行默認的定義。html



varnish的後端存儲nginx

varnish支持多種不一樣類型的後端存儲,這能夠在varnishd啓動時使用-s選項指定。後端存儲的類型包括:
web

(1)file
正則表達式

使用特定的文件存儲所有的緩存數據,並經過操做系統的mmap()系統調用將整個緩存文件映射至內存區域(若是條件容許)算法

(2)malloc
apache

使用malloc()庫調用在varnish啓動時向操做系統申請指定大小的內存空間以存儲緩存對象;編程

(3)persistent(experimental)
vim

file的功能相同,但能夠持久存儲數據(即重啓varnish數據時不會被清除);仍處於測試期;

varnish沒法追蹤某緩存對象是否存入了緩存文件,從而也就無從得知磁盤上的緩存文件是否可用,所以,file存儲方法在varnish中止或重啓時會清除數據。而persistent方法的出現對此有了一個彌補,但persistent仍處於測試階段,例如目前尚沒法有效處理要緩存對象整體大小超出緩存空間的狀況,因此,其僅適用於有着巨大緩存空間的場景

選擇使用合適的存儲方式有助於提高系統性,建議在內存空間足以存儲全部的緩存對象時使用malloc的方法,反之,file存儲將有着更好的性能的表現。

varnishd指定使用的緩存類型時,-s選項可接受的參數格式以下:

malloc[,size]

file[,path[,size[,granularity]]]

persistent,path,size {experimental}

varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,varnish爲了保存數據結構,也要佔去很多的內存空間


Varnish與Squid的對比

說到Varnish,不能不提Squid,Squid是一個高性能的代理緩存服務器,它和varnish之間有諸多的異同點,這裏分析以下:

下面是他們之間的相同點:
(1)都是一個反向代理服務器,
(2)都是開源軟件,
下面是它們的不一樣點,也是Varnish的優勢:
(1)Varnish的穩定性很高,二者在完成相同負荷的工做時,Squid服務器發生故障的概率要高於Varnish,由於使用Squid要常常重啓。
(2)Varnish訪問速度更快,Varnish採用了「Visual Page Cache」技術,全部緩存數據都直接從內存讀取,而squid是從硬盤讀取,於是Varnish在訪問速度方面會更快。
(3)Varnish能夠支持更多的併發鏈接,由於Varnish的TCP鏈接釋放要比Squid快。於是在高併發鏈接狀況下能夠支持更多TCP鏈接。
(4)Varnish能夠經過管理端口,使用正則表達式批量的清除部分緩存,而Squid是作不到的。
固然,與傳統的Squid相比,Varnish也是有缺點的,列舉以下:
(1)varnish在高併發狀態下CPU、IO、內存等資源開銷都高於Squid。
(2)varnish進程一旦Hang、Crash或者重啓,緩存數據都會從內存中徹底釋放,此時全部請求都會發送到後端服務器,在高併發狀況下,會給後端服務器形成很大壓力。




Vcl處理流程圖


211641128.jpg




Varnish支持的算法

Varnishdirector支持的挑選方法中比較簡單的有round-robinrandom兩種。其中,round-robin類型沒有任何參數,只須要爲其指定各後端主機便可,挑選方式爲輪叫,並在某後端主機故障時再也不將其視做挑選對象;random方法隨機從可用後端主機中進行挑選,每個後端主機都須要一個.weight參數以指定其權重,同時還能夠director級別使用.retires參數來設定查找一個健康後端主機時的嘗試次數。



安裝配置,官方提供的方法

https://www.varnish-cache.org/installation/redhat


# rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch
/varnish-release-3.0-1.el6.noarch.rpm
# yum -y install varnish


也能夠到這裏下載,下載時要下載同一個版本的安裝

http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/

下載完整的一套

varnish-3.0.3-1.el6.x86_64.rpm 必須的

varnish-libs-3.0.3-1.el6.x86_64.rpm 必須的

varnish-libs-devel-3.0.3-1.el6.x86_64.rpm 沒必要須

varnish-docs-3.0.3-1.el6.x86_64.rpm 沒必要須


# rpm -ql varnish
/etc/rc.d/init.d/varnish  #服務腳本
/etc/rc.d/init.d/varnishlog   #啓動日誌功能,將緩存存放到日誌文件-----------
-----------------------------------------/var/log/varnish/varnish.log中。
/etc/sysconfig/varnish    #運行時的參數,varnish服務自身的配置
/etc/varnish/   #存放vcl文件, vcl文件能夠定義多個


配置文件註釋


# cat varnish | grep -v -e ^# -e ^$
NFILES=131072   #最多能夠打開多少個套接字文件,套接字65536,前段後端各一個
MEMLOCK=82000  #內存中保存日誌的空間大小82M
NPROCS="unlimited"  #打開的線無上限
RELOAD_VCL=1  #每一次重啓,從新編譯並載入vcl,不用重啓就能編譯,reload
#DAEMON_OPTS="-a :6081 \ #傳遞給啓動時的選項,默認監聽的端口,應設爲80,避免衝突
#-T localhost:6082 \# 經過此端口連進去能夠設置新的vcl
# -f /etc/varnish/default.vcl \#默認加載的vcl文件
#-u varnish -g varnish \#用戶和組
# -S /etc/varnish/secret \#密鑰文件,若是沒有,任何人均可以鏈接到服務器
#-s file,/var/lib/varnish/varnish_storage.bin,1G"VARNISH_VCL_CONF=
/etc/varnish/default.vcl
#緩存文件存儲位置
VARNISH_LISTEN_PORT=6081
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
VARNISH_SECRET_FILE=/etc/varnish/secret
VARNISH_MIN_THREADS=50
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_STORAGE_SIZE=1G
VARNISH_STORAGE="malloc,${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}"
# mv varnish varnish.bak
# cat varnish.bak | grep -v -e ^# -e ^$ > varnish
# vim varnish
NFILES=131072
MEMLOCK=82000
NPROCS="unlimited"
RELOAD_VCL=1
VARNISH_VCL_CONF=/etc/varnish/default.vcl
VARNISH_LISTEN_PORT=80
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
VARNISH_SECRET_FILE=/etc/varnish/secret
VARNISH_MIN_THREADS=50
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}"




Varnish管理工具


# service varnish start
# ss -tanlp | grep varnish
LISTEN     0      128                      :::80                      :::*      users:(("varnishd",30208,8))
LISTEN     0      10                127.0.0.1:6082                     *:*      users:(("varnishd",30207,7))
# varnishadm -h
varnishadm: invalid option -- 'h'
usage: varnishadm [-n ident] [-t timeout] [-S secretfile] -T [address]:port command [...]
-n is mutually exlusive with -S and -T
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> help
200 
help [command]
ping [timestamp]   # 測試varnish是否工做正常
auth response
quit
Banner  #進入varnish控制器時顯示的標語
Status  #當前服務器狀態
Start   #啓動子進程
Stop   #中止子進程
vcl.load <configname> <filename>   # 裝載vcl文件
vcl.inline <configname> <quoted_VCLstring>  #編譯加載給出的vcl數據
vcl.use <configname> #使用vcl
vcl.discard <configname>  #加載正確的配置數據
Vcl.list  #當前正在使用vcl文件
vcl.show <configname>   #顯示當前的vcl
param.show [-l] [<param>] #顯示參數
param.set <param> <value>  #設置參數
Panic.show #顯示恐慌信息
Panic.clear #清除恐慌信息
Storage.list  #顯示存儲方式
Backend.list  #顯示後端服務器
backend.set_health matcher state #設置後端服務器健康情況
ban.url <regexp>
ban <field> <operator> <arg> [&& <field> <oper> <arg>]...
Ban.list #列出活動的ban



使用varnish做爲後端服務器的代理緩存

Ip172.16.5.15 varnish服務器ip

Ip172.16.5.16 後端服務器ip


# vim /etc/varnish/backend.vcl
backend default {
  .host = "172.16.5.16";
  .port = "8080";
}

在後端服務器上啓動web服務,確保web服務監聽的端口爲8080


# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
200 
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,2.6.32-358.el6.x86_64,x86_64,-sfile,-smalloc,-hcritbit
varnish-3.0.4 revision 9f83e8f
Type 'help' for command list.
Type 'quit' to close CLI session.
varnish> vcl.load backend1 /etc/varnish/backend.vcl
200 
VCL compiled.
varnish> vcl.use backend1
200 
varnish> vcl.list
200 
available       2 boot
active          0 backend1

212321489.jpg



請求資源時的時間消耗


DNS查詢時間


創建鏈接


服務器處理


響應報文傳輸時間


斷開鏈接



一個完整的vcl配置文件,後端服務器本身配置,經本人驗證,該配置的各類功能都可以實現。

# vim /etc/sysconfig/varnish
NFILES=131072
MEMLOCK=82000
NPROCS="unlimited"
RELOAD_VCL=1
VARNISH_VCL_CONF=/etc/varnish/backend.vcl
VARNISH_LISTEN_PORT=80
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
VARNISH_SECRET_FILE=/etc/varnish/secret
VARNISH_MIN_THREADS=50
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}"


# vim /etc/varnish/backend.vcl
############定義健康狀態檢測###############
probe healthcheck {
    .url = "/";                    #定義健康檢查的頁面爲主頁面
    .interval = 6s;                #探測請求的發送週期,默認爲5秒;
   .timeout = 0.3 s;              #每次探測請求的過時時長
    .window = 8;                #設定在斷定後端主機健康狀態時基於最近多少次的探測進行
    .threshold = 3;               #在.window中指定的次數中,至少有多少次是成功的才斷定後端主機正健康運行
   # .initial = 3;               #用法同.threshold
}
############定義兩組服務器##############
backend web1 {
  .host = "172.16.5.15";           #服務器主機
  .port = "8080";                   #服務器端口
  .probe = healthcheck;           #健康狀態檢測
}
backend web2 {
  .host = "172.16.5.17";           #服務器主機
  .port = "8080";                   #服務器端口
  .probe = healthcheck;           #健康狀態檢測
}
backend web3 {
  .host = "172.16.5.16";           #服務器主機
  .port = "8080";                   #服務器端口
  .probe = healthcheck;           #健康狀態檢測
}
backend web4 {
  .host = "172.16.5.18";           #服務器主機
  .port = "8080";                   #服務器端口
  .probe = healthcheck;           #健康狀態檢測
}
###############顯示命中與否的信息##############
sub vcl_deliver {
       if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT from" + " " + server.ip;
       } else {
            set resp.http.X-Cache = "MISS";
       }
}
############定義集羣,調用服務器##############
director webserver random {     #定義一個名爲webserver的directory,由web1,和web2分但請求,使用random算法,處理靜態請求
    {.backend = web1;
     .weight  = 2;               #設置權重爲2
    }
    {.backend = web2;
     .weight = 5;
    }
}
director phpserver  random {     #定義一個名爲appserver的directory,由app1,和app2分但請求,使用random算法,處理動態請求
        {.backend = web3;
         .weight = 2;}
        {.backend = web4;
         .weight = 5;}
}
###########################定義清理緩存的ip################
acl purgers {
    "127.0.0.1";
    "172.16.5.100";
}
###############將請求直接送給後端服務器###########
sub vcl_recv {
      if (req.url ~ "test.html") {
           return (pass);
      }
      if (req.url ~ "\.php$") {
           set req.backend = phpserver;
      } else {
           set req.backend = webserver;
      }
#############定義不能清除緩存的IP,調用上面的Acl############
    if (req.request == "PURGE"){                  #使用PURGE命令清除緩存
            if(!client.ip ~ purgers){              #非ACl定義的IP,則不能清除緩存  
         error 405 "Method not allowed";
            }
           return (lookup);         #將查找結果交由vcl_hit函數或者vcl_miss函數
}
#############不正常的訪問不緩存############
  if (req.request != "GET" &&
       req.request != "HEAD" &&
              req.request != "PUT" &&
              req.request != "POST" &&
              req.request != "TRACE" &&
              req.request != "OPTIONS" &&
              req.request != "DELETE") {
                /* Non-RFC2616 or CONNECT which is weird. */
                return (pipe);
            }
            if (req.request != "GET" && req.request != "HEAD") {
                /* We only deal with GET and HEAD by default */
                return (pass);
            }
#############不緩存認證信息和Cookie############
            if (req.http.Authorization || req.http.Cookie) {
                /* Not cacheable by default */
                return (pass);
            }
############支持壓縮功能###################
if (req.http.Accept-Encoding) {          
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
# No point in compressing these
remove req.http.Accept-Encoding;
} else if (req.http.Accept-Encoding ~ "gzip") {
             set req.http.Accept-Encoding = "gzip";
} else if (req.http.Accept-Encoding ~ "deflate") {
             set req.http.Accept-Encoding = "deflate";
} else {
             remove req.http.Accept-Encoding;
}
        }
}
############vcl_hit函數段##############
sub vcl_hit {
    if (req.request == "PURGE"){                  #請求方法是PURGE,這清理緩存
        purge;
        error 200 "Purged";
}
}
############vcl_miss函數段##############
sub vcl_miss {
    if (req.request == "PURGE"){
          purge;
        error 404 "Not in cache";
}
}
############vcl_pass函數段##############
sub vcl_pass {
    if (req.request == "PURGE"){
        error 502 "PURGE on a passed object";
}
}
############vcl_fetch函數段##############
sub vcl_fetch
{
#############定義緩存時長############
    if (req.request == "GET" && req.url ~ "\.html$"){
    set beresp.ttl = 300s;                         #超時時長爲300秒
if (req.request == "GET" && req.url ~ "\.(png|xsl|xml|pdf|ppt|doc|docx|chm|rar|zip|bmp|jpeg|swf|ico|mp3|mp4|rmvb|ogg|mov|avi|wmv|swf|txt|png|gif|jpg|css|js|html|htm)$") {
       set beresp.ttl = 600s;
    }
    return (deliver);
}
}

啓動varnish監控工具

# varnishstat
Hitrate ratio:        3        3        3
Hitrate avg:     0.9989   0.9989   0.9989
       20496         0.00         1.82 client_conn - Client connections accepted
       20506         0.00         1.82 client_req - Client requests received
       20477         0.00         1.82 cache_hit - Cache hits
          29         0.00         0.00 cache_miss - Cache misses
          13         0.00         0.00 backend_conn - Backend conn. success
           3         0.00         0.00 backend_fail - Backend conn. failures
          15         0.00         0.00 backend_reuse - Backend conn. reuses
          12         0.00         0.00 backend_toolate - Backend conn. was closed
          28         0.00         0.00 backend_recycle - Backend conn. recycles
          15         0.00         0.00 fetch_length - Fetch with Length
          13         0.00         0.00 fetch_chunked - Fetch chunked
         387          .            .   n_sess_mem - N struct sess_mem
           0          .            .   n_sess - N struct sess
           1          .            .   n_object - N struct object
         101          .            .   n_objectcore - N struct objectcore
         101          .            .   n_objecthead - N struct objecthead
         100          .            .   n_waitinglist - N struct waitinglist
           1          .            .   n_vbc - N struct vbc
         100          .            .   n_wrk - N worker threads
         152         0.00         0.01 n_wrk_create - N worker threads created
        1652         0.00         0.15 n_wrk_queued - N queued work requests
           6          .            .   n_backend - N backends
          27          .            .   n_expired - N expired objects
          32          .            .   n_lru_moved - N LRU moved objects

Client connections accepted:表示客戶端向反向代理服務器成功發送HTTP請求的總數量


Client requests received: 表示到如今爲止,瀏覽器向反向代理服務器發送HTTP請求的累積次數,因爲可能會使用長鏈接,因此這個值通常會大 於「Client connections accepted」


Cache hits:表示反向代理服務器在緩存區中查找而且命中緩存的次數。


Cache misses:表示直接訪問後端主機的請求數量,也就是非命中數。


N struct object:表示當前被緩存的數量。


N expired objects:表示過時的緩存內容數量。


N LRU moved objects:表示被淘汰的緩存內容個數



監控後端服務的健康狀態,varnishlogs


# varnishlog
    0 Backend_health - web2 Still sick ------- 0 3 8 0.000000 0.000000
    0 Backend_health - web3 Still sick ------- 0 3 8 0.000000 0.000000
    0 Backend_health - web1 Still healthy 4--X-RH 8 3 8 0.007568 0.011728 HTTP/1.1 200 OK
    0 Backend_health - web4 Still sick ------- 0 3 8 0.000000 0.000000
    0 Backend_health - web2 Still sick ------- 0 3 8 0.000000 0.000000
    0 Backend_health - web2 Still sick ------- 0 3 8 0.000000 0.000000
    0 Backend_health - web3 Still sick ------- 0 3 8 0.000000 0.000000
0 Backend_health - web1 Still healthy 4--X-RH 8 3 8 0.005915 0.010275 HTTP/1.1 200 OK




手動清理緩存


# curl -X PURGE http://172.16.5.15/
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>405 Method not allowed</title>   # 配置文件中定義的清理緩存的ip非本機,修改配置文件再試一次
  </head>
  <body>
    <h1>Error 405 Method not allowed</h1>
    <p>Method not allowed</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 614714334</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
# curl -X PURGE 172.16.5.15/index.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>200 Purged</title>  #手動清理成功
  </head>
  <body>
    <h1>Error 200 Purged</h1>
    <p>Purged</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 614714341</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>



Varnish性能優化主要參數


# varnish -S /etc/varnish/sercet -T 127.0.0.1:6082
varnish> param.show
thread_pools               4 [pools]
thread_pool_min            50 [threads]
thread_pool_max            5120 [threads]
thread_pool_timeout        10 [seconds]
lru_interval               20 [seconds]
listen_depth               1024 [connections]

lru_interval:這是個時間參數,大概意思是說若是有一個對象在內存中超過了此參數設定的時間尚未被重用時,就把這個對象從LRU(Least Recently Used)隊列中移除。這實際上是緩存系統的一個經常使用算法,合理的設置這個時間,能夠提升系統的運行效率。

listen_depth:這個參數是設置TCP鏈接隊列的長度,設置大一點能夠提升併發處理能力。對於這些優化參數,最好的方式是加到varnish的啓動腳本中,經過varnishd的「-p」參數調用便可。

thread_pools:用來設置線程池的數量,通常認爲這個值和系統CPU的數目相同最好,設置過多的pools,varnish的併發處理能力會更強,可是也會消耗更多的CPU和內存。

thread_pool_min:用來設置每一個pools的最小threads數,當pools接收到可用的請求後,就會將請求分配給空閒的threads來處理。

thread_pool_max:表示全部pools對應的threads數總和的最大值,此值不能太大,能夠設置爲系統峯值的90%左右便可,設置過大,會致使進程hung住。

thread_pool_timeout:表示threads的超時過時時間,當threads數大於thread_pool_min設定值時,threads空閒超過thread_pool_timeout設定的時間時,thread就會被釋放掉。

相關文章
相關標籤/搜索