學習varnish隨筆

Varnish是一款高性能、開源的反向代理服務器和緩存服務器。Varnish使用內存緩存文件來減小響應時間和網絡帶寬消耗。這個項目是由挪威的一家報紙Verdens Gang的網絡分支起始的,其架構設計和開發總監Poul-Henning Kamp是FreeBSD核心的開發人員之一,最初項目的管理與基礎設施及額外開發由挪威一家Linux諮詢公司Linpro提供。php

說到varnish,squid就不得不說起。squid算得上是古老的緩存服務器。因爲varnish先進的設計理念,性能要比squid高上許多,varnish還能夠經過端口進行管理,使用正則語句作到清除指定緩存的功能,這些squid都作不到。可是varnish在高併發的狀況下,資源消耗較高,並且varnish服務進程一旦崩潰,重啓,內存中的緩存數據將所有丟失。css

一、Varnish架構

varnish是基於現代設備設計的服務項目,因此僅支持64位系統。Manager Process 負責處理請求任務,保證每一個任務分配一個worker threads。因此varnish是一個重線程型服務。除此以外,manager process 包含接受CLI命令控制的功能,包括調整運行參數,vcl配置更新。初始化子進程Cacher Process,並按必定頻率檢測cacher在線與否。html

Cacher Process 功能:前端

  • 監聽客戶端請求
  • 管理worker 線程
  • 存儲緩存數據
  • 記錄流量日誌
  • 根據統計更新計數器數值

varnish使用工做空間減小每一個線程須要請求或者修改內存時發生的爭搶。varnish具備多個工做空間,最爲重要的是  session 工做空間,用來維護session 相關數據。express

在日誌記錄方面,Cacher process 使用VSL 機制來處理,這是一個共享內存空間,能夠有效減小記錄阻塞。日誌空間分爲兩個部分,分別記錄格式化的請求日誌,以及計數器數值。能夠經過varnish自帶log工具進行查看,分析或者永久存儲日誌。apache

二、varnish的緩存存儲機制( Storage Types):

2.1  malloc[,size]
調用malloc(),爲緩存分配內存空間,此種方式不可避免地會產生碎片文件,額外佔用內存後端

[,size]用於定義空間大小;重啓後全部緩存項失效;瀏覽器


2.2   file[,path[,size[,granularity]]]
varnish建立一個文件用來存儲緩存數據,而後將此文件映射到內存空間中,可是該文件並不會持久保存數據,重啓後全部緩存項失效;緩存

granularity  遞增大小服務器


2.3   persistent,path,size
持久文件存儲,黑盒;重啓後全部緩存項有效;可是處於實驗階段,問題較多;

 

2.4  MSE

Massive Storage Engine,在plus版可用,意味着收費。該模式設計的容量巨大可達100TB,磁盤性能要優於file模式。

總結:當內存空間不足以存儲全部緩存數據時,應選擇file 或 mse 存儲。因此通常配置成file存儲,固然付費的話使用mse更佳。

三、Varnish程序環境

本文主機環境爲CentOS7.2,Varnish 版本 4.0

varnish的程序環境:
  /etc/varnish/varnish.params: 配置varnish服務進程的工做特性,例如監聽的地址和端口,緩存機制;
  /etc/varnish/default.vcl:配置各Child/Cache線程的工做屬性;
主程序:
  /usr/sbin/varnishd

CLI interface:
  /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  #logger daemon
  /usr/lib/systemd/system/varnishncsa.service   #lgger daemon  in apache format

3.1  varnishd 主程序的選項:

systemd方式啓動varnish 服務,主程序指定的配置文件爲:/etc/varnish/varnish.params
  -a address[:port][,address[:port][...],默認爲6081端口;    #對客戶端開放的監聽端口地址
  -T address[:port],默認爲6082端口;                                #管理工具鏈接的端口地址
  -s [name=]type[,options],定義緩存存儲機制;                   #能夠屢次定義此項
  -u user
  -g group
  -f config:VCL配置文件;
  -F:運行於前臺;
  ...

線程相關的參數:
在線程池內部,其每個請求由一個線程來處理; 其worker線程的最大數決定了varnish的併發響應能力;

thread_pools:Number of worker thread pools. 線程池數量,默認值爲2,官方介紹2個線程池已足夠用,再增長該數值沒有提高效果;
thread_pool_max:The maximum number of worker threads in each pool.每一個線程池建立最大線程的數量;默認5000
thread_pool_min:The minimum number of worker threads in each pool. 每一個線程池保持最少線程的數量;額外意義爲「最大空閒線程數」;默認100

因此咱們常常須要調整的參數就是thread_pool_max,thread_pool_min
計算varnish最大併發鏈接數=thread_pools * thread_pool_max

thread_pool_timeout: 線程空閒時間,超過閾值則摧毀線程 
thread_pool_add_delay:建立一個新線程的延遲時間,默認值爲0s
thread_pool_destroy_delay:摧毀一個線程的延遲時間,默認值爲2s;

設置方式:

運行動態修改經過varniadm接口設置
命令:param.set

永久有效的方法:
運行時參數:/etc/varnish/varnish.params文件, DEAMON_OPTS

  -p param=value:設定運行參數及其值; 可重複使用屢次;
  -r param[,param...]: 設定指定的參數爲只讀狀態
  例如: DAEMON_OPTS="-p thread_pool_min=2 -p thread_pool_max=10000 -p thread_pool_timeout=300"

 

3.2  varnish管理工具

  用法:varnishadm -S /etc/varnish/secret -T [ADDRESS:]PORT

    指定了鏈接密鑰,安裝varnish時生成的。指明管理接口的端口地址,默認爲127.0.0.1 可省略。

進入以後,輸入help [command] 獲取幫助

梳理經常使用指令

配置文件相關:
vcl.list :查看vcl 列表
vcl.load:裝載,加載並編譯;
vcl.use:激活;
vcl.discard:刪除;
vcl.show [-v] <configname>:查看指定的配置文件的詳細信息;-v 選項查看默認vcl代碼

運行時參數:
param.show -l:顯示列表;
param.show <PARAM>
param.set <PARAM> <VALUE>   設定參數

緩存存儲:
storage.list

後端服務器:
backend.list

 

四、VCL 基礎

Varnish Configuration Language (VCL) 是一種動態語言,用來描述請求處理和制定緩存策略。vcl配置內容由manager process 建立的VCC子進程轉換成C語言代碼,再經由gcc編譯成共享對象,最後裝載到cacher process中生效。

想要寫好vcl配置,須要瞭解varnish內部報文的處理流程,其核心關鍵詞是 finite state machine——有限狀態引擎。下圖爲簡單的處理流程:

圖中橢圓中表明狀態引擎。這些狀態引擎被概念化後成爲vcl中的子函數,以vcl_前綴開頭,在引擎中,能夠對每一個請求中的http 首部或者其餘各方面的內容進行檢查或者修改操做。return(action)代碼表示中斷一個狀態,其中action是vcl關鍵字,用來指向下一步去向哪一個狀態引擎。

每一個請求都被單獨分開處理;狀態之間存在相關性,但彼此間互相隔離。

在下一步瞭解vcl 配置代碼以前,先了解一下vcl背後的基礎概念。當varnish處理一個請求時,首先要解析這個請求。從http 首部中分析出請求的方法類型,判斷是否爲有效的請求方法等等,當基礎解析完成以後,依據第一個策略進行檢查進而作出判斷。vcl就是根據由各個策略組成的規則來進行各類動做。

上圖可分爲兩個區域:前端frontend和後端backend

前端狀態可分爲四個階段:

第一階段:

vcl_recv     #接受客戶端請求,進行判斷

第二階段:

vcl_hash   #進行hash計算,不進行判讀處理,計算以後送往各個第三階段狀態引擎中

第三階段:

vcl_hit        #緩存命中,到此處理

vcl_pass      #緩存跳過

vcl_miss      #緩存未命中

vcl_purge   #清理緩存

vcl_pipe       #對於沒法識別的http首部請求直接送入管道,交由後端處理再也不處理

第四階段:

vcl_deliver: 大部分響應客戶端的請求由此發送回去

vcl_synth:接受來自vcl_purge的任務,對於指定的緩存,進行刪除處理

後端狀態分爲兩階段:

第一階段:

    vcl_backend_fetch:接受來自前端狀態vcl_pass或vcl_miss 的任務,向後端主機請求

第二階段:

    vcl_backend_response:接受到後端返回正常狀態報文,進行是否緩存檢查,須要緩存的響應將其緩存,不須要則不緩存,最後送到vcl_deliver

    vcl_backend_error:後端主機錯誤,返回錯誤響應

除此以外還有兩個特殊狀態引擎:

vcl_init:在處理任何請求以前要執行的vcl代碼:主要用於初始化VMODs;
vcl_fini:全部的請求都已經結束,在vcl配置被丟棄時調用;主要用於清理VMODs;

五、VCL語法

 

一個大前提:varnish 4.0版本開始,vcl擁有本身的默認規則,它不可移除,老是追加在自定義的規則以後。

(1) vcl配置文件以 vcl 4.0 開頭;
(2) C語言註釋風格://, # and /* foo */ ;
(3) 子函數使用sub關鍵字聲明, 例如sub vcl_recv { ...};
(4) 無循環, state-limited variables(受限於引擎的內建變量);
(5) 使用return(action)中斷引擎狀態,指向下一步處理,action爲關鍵字 ,例如: return(pass);
(6) 可動態裝載;

5.1  三類主要語法:

sub subroutine {
...
}

if CONDITION {
...
} else {
...
}

return(), hash_data()

5.2 內建函數和關鍵字

函數:

hash_data():指明哈希計算的數據;減小差別,以提高命中率;
regsub(str,regex,sub):把str中被regex第一次匹配到字符串替換爲sub;主要用於URL Rewrite
regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替換爲sub;
return():
ban(expression)
ban_url(regex):Bans全部的其URL能夠被此處的regex匹配到的緩存對象;
synth(status,"STRING"):purge操做;

關鍵字:
  call subroutine, return(action),new,set,unset

下圖爲指定函數智能用於特定子函數中

  

操做符:
  ==, !=, ~, >, >=, <, <=
  邏輯操做符:&&, ||, !
  變量賦值:=

正則匹配:~

  (?i)  表示忽略大小寫

      同時注意匹配的規則若是是字符串須要"  " 引發

 5.3  變量類型:

內建變量:

req.*:request,表示由客戶端發來的請求報文相關;
req.http.*
req.http.User-Agent, req.http.Referer, ...
bereq.*:由varnish發往BE主機的httpd請求相關;
bereq.http.*
beresp.*:由BE主機響應給varnish的響應報文相關;
beresp.http.*
resp.*:由varnish響應給client相關;
obj.*:存儲在緩存空間中的緩存對象的屬性;只讀;

經常使用變量:

bereq.*, req.*:
bereq.http.HEADERS
bereq.request:請求方法;
bereq.url:請求的url;
bereq.proto:請求的協議版本;
bereq.backend:指明要調用的後端主機;

req.url:請求的url
req.http.Cookie:客戶端的請求報文中Cookie首部的值;
req.http.User-Agent:瀏覽器類型


beresp.*, resp.*:
beresp.http.HEADERS
beresp.status:響應的狀態碼;
reresp.proto:協議版本;
beresp.backend.name:BE主機的主機名;
beresp.ttl:BE主機響應的內容的餘下的可緩存時長;

obj.*
obj.hits:此對象從緩存中命中的次數;
obj.ttl:對象的ttl值

server.*
server.ip
server.hostname
client.*
client.ip

 同時注意變量是受狀態限制的,下圖爲可用表

用戶自定義:
  set    variable=value    #定義變量
  unset   variable           #撤銷定義的變量

六、vcl 配置示例

 6.1  響應首部增長一個cache是否命中的字段X-cache

~]$ vi /etc/varnish/default.vcl

sub vcl_deliver {
  if ( obj.hits>0 ) {
    set resp.http.X-cache = " HIT via " + server.ip;
  }
   else {
    set resp.http.X-cache = " MISS via "+ server.ip;
   }

}

~]$ varnish_reload_vcl           #重載vcl

或者 使用varnishadm 進入管理接口,使用以下命令

~]$ vcl.load   test1   default.vcl         #裝載vcl,並指定一個命名test1

若是返回狀態碼200,則語法正確,編譯經過

~]$ vcl.use  test1      #以下圖所示vcl新配置已生效

使用curl命令測試,第一次無緩存,則未命中

第二次訪問,已有緩存,則命中

 

6.2  強制對某類資源的請求不檢查緩存:

 設定訪問/login 或 /admin 下的目錄任何文件都不查詢緩存

vcl_recv {
	if (req.url ~ "(?i)^/(login|admin/)") {
	   return(pass);
	}
}

6.3  對於特定類型的資源,例如公開的圖片等,取消cookie,並強行設定其能夠由varnish緩存的時長;

sub vcl_backend_response {
if (beresp.http.cache-control !~ "s-maxage") { if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") { unset beresp.http.Set-Cookie; set beresp.ttl = 3600s; } }
}

6.4  緩存對象的修剪:purge, ban

(1) 能執行purge操做
sub vcl_purge {
return (synth(200,"Purged"));
}

(2) 什麼時候執行purge操做
sub vcl_recv {
if (req.method == "PURGE") {
return(purge);
}
...
}

上面的定義比較簡單,任何人均可以對cache作清理操做,下面則根據IP地址作出限制

添加此類請求的訪問控制法則:
acl purgers {
"127.0.0.0"/8;
"10.1.0.0"/16;
}

sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {                      #這裏正則匹配的時acl列表,不須要引號
return(synth(405,"Purging not allowed for " + client.ip));       #來自不屬於acl定義的purgers組的purge請求則返回錯誤代碼
}
return(purge);
}
...
}

 6.5   設定使用多個後端主機

backend default {
  .host = "172.16.100.6";
  .port = "80";
}

backend appsrv {
  .host = "172.16.100.7";
  .port = "80";
}

sub vcl_recv {
  if (req.url ~ "(?i)\.php") {
    set req.backend_hint = appsrv;            #php資源轉發至appsrv處理
  } else {
      set req.backend_hint = default;
   }
  ...
}

 七、定義後端服務器組

 7.1  定義後端服務器組

使用前須要在vcl配置中導入模塊:
import director;

示例:
import directors; # load the directors

backend server1 {                 
.host =
.port =
}
backend server2 {
.host =
.port =
}

sub vcl_init {                    #在init 子函數中定義
new GROUP_NAME = directors.round_robin();         #建立組,並命名爲GROUP_NAME,指定調度方法
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();  #組引用方法
}

 7.2  後端主機健康檢測機制

varnish能夠對後端主機進行健康檢測,動態進行移除或恢復後端主機調度列表

.probe:定義健康狀態檢測方法;
.url:檢測時請求的URL,默認爲"/";
.request:發出的具體請求;
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close"
.window:基於最近的多少次檢查來判斷其健康狀態;
.threshhold:最近.window中定義的這麼次檢查中至有.threshhold定義的次數是成功的;
.interval:檢測頻度;
.timeout:超時時長;
.expected_response:指望的響應碼,默認爲200;

健康狀態檢測的配置方式:
(1) probe PB_NAME = { }
backend NAME = {
.probe = PB_NAME;
...
}

(2) backend NAME {
.probe = {
...
}
}

示例:
probe check {                               #probe   先定義好
.url = "/.healthcheck.html";
.window = 5;
.threshold = 4;
.interval = 2s;
.timeout = 1s;
}

backend default {
.host = "10.1.0.68";
.port = "80";
.probe = check;        #引用檢測方式
}

backend appsrv {
.host = "10.1.0.69";
.port = "80";
.probe = check;
}

 在varniadm 命令接口中查看檢測情況

 

 八、varnish日誌

用來查看 shared memory log 日誌工具

8.1  varnishstat - Varnish 緩存統計查看

默認爲動態刷新顯示方式

選項

-1  打印當前統計結果
-f FILED_NAME   顯示指定字段的統計
-l:可用於-f選項指定的字段名稱列表;

example:
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss


8.2  varnishtop - Varnish 日誌 字段排名

默認動態更新

 

選項:

-1   打印當前排名
-i taglist  顯示指定字段排名。能夠同時使用多個-i選項,也能夠一個選項跟上多個標籤 ","分隔;
-I <[taglist:]regex>  基於正則顯示字段
-x taglist:排除列表
-X <[taglist:]regex>  基於正則排除字段

8.3  varnishlog - Display Varnish logs

顯示share memory 中的日誌記錄

8.4  varnishncsa - Display Varnish logs in Apache / NCSA combined log format

顯示share memory 中的日誌記錄,apache日誌形式

 

 本文到此結束

 完

相關文章
相關標籤/搜索