關於varnish緩存


前言:本文將以varnish4.X版本爲基礎,進行學習。前端

緩存的概念

熟悉一些名詞:linux

  • 時間局部性:一個數據被訪問過以後,可能很快會被再次訪問到;
  • 空間局部性:一個數據被訪問時,其周邊的數據也有可能被訪問到git

  • 數據緩存:例如MySQL到web應用服務器之間的緩存,服務器緩存的資源是數據緩存
  • 頁面緩存:接入層和應用層中間的緩存,服務器緩存的是可緩存的頁面,這層就是緩存層web

  • 緩存命中率:hit/(hit+miss),通常高於30%命中率則是正向收益,好的設計系統能夠達到80%到95%以上
  • 字節命中率:按照數據的字節大小來計算命中率
  • 請求命中率:按照請求的數量來計算命中率正則表達式

  • 代理式緩存:客戶端訪問緩存服務器,緩存服務器沒有命中緩存時到後端服務器請求數據,此時它做爲反向代理服務器工做,這種類型的緩存服務器叫作代理式緩存
  • 旁掛式緩存:客戶端親自去查詢數據庫,而且將數據複製給緩存服務器一份,下次先去找緩存服務器,若是沒有命中則再去數據庫服務器查詢,此時這種工做方式的緩存叫作旁掛式緩存,這個客戶端叫作胖客戶端(smart client)數據庫

  • private cache:私有緩存,用戶代理附帶的本地緩存機制
  • public cache:公共緩存,反向代理服務器的緩存功能express

  • CND:Content Delivery Network 內容投遞系統apache

  • GSLB:全網均衡調度編程

  • 緩存有效性判斷機制
    • 過時時間
    • 條件式驗證
      • Last-Modified/If-Modified-Since:基於文件的修改時間戳來判別
      • Etag/If-None-Match:基於文件的校驗碼來判別

「過時時間驗證」緩存是否失效顆粒度太大,若是頁面剛剛緩存應用服務器發生了變化,結果客戶端拿到的就是過時數據;從而加入了條件式驗證緩存的失效性,每次客戶端請求到達緩存服務器,緩存服務器都要拿本地的數據和應用服務器的數據比較時間戳,若是時間戳發生了變化則緩存新的數據;這樣雖然粒度小了,可是仍是會有問題,若是應用服務器在同一秒頁面數據變化了三次,而緩存服務器拿到的是第一份數據,這樣仍是會發生數據失效的問題;從而又引入了Etag(擴展標記)來標記惟一的頁面數據。此時雖然解決了數據失效性的問題,可是每次客戶端的請求都要去後端服務器作比較,對緩存和應用服務器都是不小的壓力,咱們不得不採起折中的解決方案就是「過時時間驗證+條件式驗證」,將不常常變更的頁面作過時時間驗證,變更頻繁的採用條件式驗證。

請求報文用於通知緩存服務如何使用緩存響應請求:

cache-request-directive = 
"no-cache" 不能使用緩存系統中的緩存響應我,必須先去應用服務器作緩存驗證
"no-store" 不能使用緩存系統中的緩存響應我,必須去應用服務器請求響應我
"max-age" "=" delta-seconds 
"max-stale" [ "=" delta-seconds ]
"min-fresh" "=" delta-seconds
"no-transform"
"only-if-cached"
cache-extension

響應報文用於通知緩存服務器如何存儲上級服務器響應的內容:

cache-response-directive =
"public" 全部緩存系統均可以緩存
"private" [ "=" <"> 1#field-name <"> ] 僅可以被私有緩存所緩存
"no-cache" [ "=" <"> 1#field-name <"> ],可緩存,但響應給客戶端以前須要revalidation,即必須發出條件式請求進行緩存有效性驗正
"no-store" ,不容許存儲響應內容於緩存中
"no-transform" 不能轉換格式
"must-revalidate" 必須從新驗證
"proxy-revalidate" 
"max-age" "=" delta-seconds 私有緩存最大緩存時長
"s-maxage" "=" delta-seconds 公共緩存最大緩存時長
cache-extension

Web Page Cache解決方案:squid和varnish,它們的關係就像Apache和Nginx

1、varnish緩存

1. 簡介

Varnish cache,是一套高性能的開源反向網站緩存服務器(reverse proxy server)、HTTP加速器 ,不少門戶網站已經部署了varnish,而且性能要比squid高上許多,甚至比squid還穩定,且效率更高,資源佔用更少。

特色:

  • Varnish可使用內存也可使用硬盤進行數據緩存
  • 支持虛擬內存的使用
  • 有精確的時間管理機制
  • 狀態引擎架構:經過特定的配置語言設計不一樣的語句
  • 以二叉堆格式管理緩存數據

優點:

  • 穩定性強:將worker單獨分開;
  • 速度快:採用「page Cache」技術,全部緩存數據直接從內存讀取;
  • 支持多併發;
  • 經過管理端口,使用正則批量清除部分緩存;或者經過頁面清;
  • 經過fork打開多進程處理

劣勢:

  • 進程一旦crash或重啓,緩存的數據將從內存中徹底釋放
  • 在多臺varnish實現負載均衡時,每次請求都會落到不一樣的varnish服務器中,形成url請求可能會穿透到後
  • 劣勢解決方案
    • a. 在varnish的後端添加squid/nignx代理,這樣防止了當varnish緩存被清空時,瞬間大量的請求發往web服務器
    • b. 在負載均衡上作url哈西,讓單個url請求固定請求到一臺varnish服務器上

2. 整體結構

64380cd

如上圖所示,主要進程:Management、Cacher。

2.1 兩個主進程

2.1.1 Management進程

Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,若是在指定的時長內未獲得Child進程的迴應,Management將會重啓此Child進程。

Manager管理的接口

  • CLI interface :命令行接口
  • Telnet interface :telnet接口
  • Web interface :Web管理接口

2.1.2 Child/Cacher進程

進程包括多個線程

  • Accept 線程:接收新的鏈接請求並響應
  • Worker 線程:child進程會爲每一個會話啓動一個worker線程,所以,在高併發的場景中可能會出現數百個worker線程甚至更多;
  • Object Expiry 線程:從緩存中清理過時內容;
  • Commad line 線程 : 管理接口
  • Storage/hashing 線程 :緩存存儲
  • Log/stats 線程:日誌管理線程
  • Backend Communication 線程:管理後端主機線程
  • Varnish依賴「工做區(workspace)」以下降線程在申請或修改內存時出現競爭的可能性。在varnish內部有多種不一樣的工做區,其中最關鍵的當屬用於管理會話數據的session工做區。

2.2 Varnish的日誌收集

爲了與系統的其它部分進行交互,Child進程使用了能夠經過文件系統接口進行訪問的共享內存日誌(shared memory log),所以,若是某線程須要記錄信息,其僅須要持有一個鎖,然後向共享內存中的某內存區域寫入數據,再釋放持有的鎖便可。而爲了減小競爭,每一個worker線程都使用了日誌數據緩存。共享內存日誌大小通常爲90M,其分爲兩部分,前一部分爲計數器,後半部分爲客戶端請求的數據。

varnish提供了多個不一樣的工具如varnishlog、varnishncsa或varnishstat等來分析共享內存日誌中的信息並可以以指定的方式進行顯示。

2.3 VCL—varnish配置緩存策略的工具

Varnish Configuration Language(VCL)是varnish配置緩存策略的工具,它是一種基於域(domain specific)的簡單編程語言,它支持有限的算術運算和邏輯運算操做、容許使用正則表達式進行字符串匹配、容許用戶使用set自定義變量、支持if判斷語句,也有內置的函數和變量等。

使用VCL編寫的緩存策略一般保存至.vcl文件中(默認文件:$varnish_home/default.vcl,其須要編譯成二進制的格式後才能由varnish調用,即編寫的.vcl文件由VCL compiler來編譯,VCL compiler調用C compiler來編譯後由management來讀取生效(讀取是及時的),編譯後management讓各Child進程來應用生效(由於編譯成sharedobject爲各子進程各讀取了一份)。事實上,整個緩存策略就是由幾個特定的子程序如vcl_recv、vcl_fetch等組成,不一樣的子程序在不一樣的時間裏執行,好比一個子程序在接到請求時執行,另外一個子程序在接收到後端服務器傳送的文件時執行。若是沒有事先爲某個位置自定義子例程,varnish將會執行默認的定義。

VCL策略在啓用前,會由management進程將其轉換爲C代碼,然後再由gcc編譯器將C代碼編譯成二進制程序。編譯完成後,management負責將其鏈接至varnish實例,即child進程。正是因爲編譯工做在child進程以外完成,它避免了裝載錯誤格式VCL的風險。所以,varnish修改配置的開銷很是小,其能夠同時保有幾份尚在引用的舊版本配置,也可以讓新的配置即刻生效。編譯後的舊版本配置一般在varnish重啓時纔會被丟棄,若是須要手動清理,則可使用varnishadm的vcl.discard命令完成。


2、Varnish的工做原理(more)

varnish工做流

1. VCL內置函數與狀態引擎的概念

每一個請求都被單獨處理,處理過程將處在不一樣的狀態中進行,退出一種狀態就會轉入下一個狀態。
狀態之間存在相關性,但彼此間互相隔離,下面的圖中能夠清楚的看出狀態的轉換,以及不一樣狀態所要通過的處理函數。

  • 4.0

vcl狀態引擎轉換
vcl狀態引擎轉換

  • 橢圓形部分稱爲varnish的狀態節點,又稱爲vcl狀態引擎,還有種叫法爲varnish的vcl內置函數(子程序)。
  • 紅色的線條:沒有查詢緩存/緩存中數據過時/緩存中沒有數據 狀況下的流程
  • 橙黃色的線條:直接將匹配數據經過內置函數vcl_pipe送日後臺主機的流程
  • 綠色的線條:查詢緩存數據命中且數據沒有過時/經後臺主機返回的數據經被緩存後返回給客戶流程
  • 藍色的線條:數據沒有命中緩存向後臺主機發出查詢的流程
  • 黑色的線條:數據從後臺主機返回給varnish緩存的流程

狀態引擎是被概念化的VCL內置函數或叫VCL子程序,以vcl_前綴開頭,在引擎中,能夠對每一個請求中的http 首部或者其餘各方面的內容進行檢查或者修改操做。return(action)代碼表示中斷一個狀態,其中action是vcl關鍵字,用來指向下一步去向哪一個狀態引擎。
狀態引擎即在VCL子程序被調用時,按照VCL子程序中自定義的規則策略作出的階段性動做。


2. VCL處理流程

VCL背後的基礎概念:varnish開始處理一個請求時,首先須要分析HTTP請求自己,好比從首部獲取請求方法、驗正其是否爲一個合法的HTT請求等。當這些基本分析結束後就須要依據第一個決策來進行檢查進而作出判斷,即varnish是否從緩存中查找請求的資源。這個決定的實現則須要由VCL來完成,簡單來講,要由vcl_recv方法來完成。若是管理員沒有自定義vcl_recv函數,varnish將會執行默認的vcl_recv函數。然而,即使管理員自定義了vcl_recv,但若是沒有爲自定義的vcl_recv函數指定其終止操做(terminating),其仍將執行默認的vcl_recv函數。事實上,varnish官方強烈建議讓varnish執行默認的vcl_recv以便處理自定義vcl_recv函數中的可能出現的漏洞。
VCL處理流程就是根據由各個策略組成的規則來進行各類動做。

2.1 內置函數的做用

結合上節內容,VCL處理流程可分兩個區域

  • 前端 frontend
  • 後端 backend

frontend區域

階段1

vcl_recv:用於接受和處理客戶端請求的狀態引擎。當請求到達併成功接收後被調用,經過判斷請求的數據來決定如何處理請求。例如如何響應、怎麼響應、使用哪一個後端服務器等。

階段2

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

階段3

vcl_hit:從緩存中查找到緩存對象時要執行的操做;
vcl_miss:從緩存中款查找到緩存對象時要執行的操做;
vcl_pass:用於將請求直接傳遞至後端主機,後端主機在應答數據後將應答數據發送給客戶端,跳過緩存。
vcl_purge:清理緩存
vcl_pipe:對於沒法理解的用戶請求,將請求直接發日後端主機;

階段4

vcl_deliver:將用戶請求的內容響應給客戶端時用;
vcl_synth:接受來自vcl_purge的任務,對於指定的緩存,進行刪除處理

backend區域

階段1

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

階段2

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

兩個特殊狀態引擎(4.0版本)

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

2.2. 常見的狀態引擎之間的處理流程

若是緩存命中:
用戶請求–>vcl_recv–>vcl_hash–>vcl_hit–>vcl_deliver–>響應給用戶

若是緩存未命中:
用戶請求–>vcl_recv–>vcl_hash–>vcl_miss–>vcl_backend_fetch–>後端服務器接受請求發送響應報文–>vcl_backend_response–>vcl_deliver
或:
用戶請求–>vcl_recv–>vcl_hash–>vcl_miss–>vcl_pass–>vcl_backend_fetch–>後端服務器接受請求發送響應報文–>vcl_backend_response–>vcl_deliver–>響應給用戶

若是不能從緩存中進行響應
用戶請求–>vcl_recv–>vcl_hash–>vcl_pass–>vcl_backend_fetch–>後端服務器接受請求發送響應報文–>vcl_backend_response–>vcl_deliver–>響應給用戶

若是進行緩存修剪
用戶請求–>vcl_recv–>vcl_hash–>vcl_purge–>vcl_synth–>返回給用戶

若是請求報文沒法理解
用戶請求–>vcl_recv–>vcl_hash–>vcl_pipe–>交給後端服務器

3、varnish程序環境(more

Varnish程序的組成部分,大體分如下幾類

  • varnish的程序配置
    /etc/varnish/varnish.params: 配置varnish服務進程的工做特性,例如監聽的地址和端口,緩存機制;
    /etc/varnish/default.vcl:配置各Child/Cache線程的工做屬性;編寫緩存策略的核心配置,經過官網學習最新的Varnish子進程的使用
  • 主程序
    /usr/sbin/varnishd
  • CLI interface
    /usr/bin/varnishadm:登陸管理程序
  • VCL配置文件重載程序
    /usr/sbin/varnish_reload_vcl
  • Shared Memory Log交互工具
    /usr/bin/varnishhist
    /usr/bin/varnishlog
    /usr/bin/varnishncsa
    /usr/bin/varnishstat
    /usr/bin/varnishtop
  • 測試工具程序
    /usr/bin/varnishtest
  • Systemd Unit File
    varnish服務:/usr/lib/systemd/system/varnish.service
    logger daemon:/usr/lib/systemd/system/varnishlog.service
    lgger daemon in apache format:/usr/lib/systemd/system/varnishncsa.service

1. 配置文件

1.1 緩存策略配置文件

/etc/varnish/default.vcl涉及知識點將在下篇文章VCL配置語言中整理

1.2 varnish.params

/etc/varnish/varnish.params默認配置以下:

# 將其設置爲1以使systemd從新加載嘗試切換VCL而不從新啓動。
RELOAD_VCL=1
# 指定配置文件
VARNISH_VCL_CONF=/etc/varnish/default.vcl
# varnish服務監聽的IP地址,默認爲全部地址
VARNISH_LISTEN_ADDRESS="服務的IP地址"
# 監聽的端口默認爲6081
VARNISH_LISTEN_PORT=6081
# 接受管理程序監聽的IP
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
# 管理端口
VARNISH_ADMIN_LISTEN_PORT=6082
#t 密鑰文件的路徑
VARNISH_SECRET_FILE=/etc/varnish/secre
# 使用的緩存機制
VARNISH_STORAGE="malloc,256M"
# 使用varnish用戶運行varnishi服務
VARNISH_USER=varnish
VARNISH_GROUP=varnish
# 設置線程池中最小線程和最大線程數及線程空閒時間
 # thread_pools:工做線程數,最好小於或等於CPU核心數量
 # thread_pool_max:每線程池的最大線程數
 # thread_pool_min:最大空閒線程數
 # thread_pool_timeout:空閒超過多長時間被清除
 # thread_pool_add_delay:生成線程以前等待的時間
 # thread_pool_destroy_delay:清除超出最大空閒線程數的線程以前等待的時間
# DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"

2. 管理工具(more)

2.1 varnishd

  • -s [name=]type[,options] :定義緩存數據的存儲方式
    • malloc[,size]:內存存儲,[,size]用於定義空間大小;重啓後全部緩存項失效
    • file[,path[,size[,granularity]]]:磁盤文件存儲,黑盒;重啓後全部緩存項失效
    • persistent,path,size:文件存儲,黑盒;重啓後全部緩存項有效;實驗階段,不建議使用
  • -a address[:port][,address[:port][...]:服務監聽端口,默認爲6081端口
  • -T address[:port]:管理服務監聽端口,默認爲6082端口
  • -f config:VCL配置文件
  • -F:運行於前臺
  • -p param=value:設定運行參數及其值; 可重複使用屢次
  • -r param[,param...]: 設定指定的參數爲只讀狀態

RPM安裝 啓動方式

#/usr/lib/systemd/system/varnish.service #system啓動項設置,可參考
systemctl restart varnish

2.2 varnishadm

  • 登陸管理系統
    varnishadm -S /etc/varnish/secret -T address[:port]
help [<command>] 獲取幫助
ping [<timestamp>] 測試服務器
auth <response>
quit 退出cli
banner
status 顯示狀態
start 啓動
stop 中止
vcl.load <configname> <filename> 加載VCL配置文件
vcl.inline <configname> <quoted_VCLstring>
vcl.use <configname> 激活VCL配置文件
vcl.discard <configname> 刪除VCL配置
vcl.list 列出VCL配置
param.show [-l] [<param>] 列出當前運行的參數
param.set <param> <value> 運行參數臨時調整
panic.show
panic.clear
storage.list 列出數據存儲信息
vcl.show [-v] <configname> 列出VCL詳細配置
backend.list [<backend_expression>] 列出後端服務器
backend.set_health <backend_expression> <state>
ban <field> <operator> <arg> [&& <field> <oper> <arg>]...

2.3 日誌交換工具

2.3.1 varnishstat

  • 顯示指定參數的當前統計數據
    varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
  • 列出指定配置段的每一個參數的意義
    varnishstat -l -f MAIN -f MEMPOOL

2.3.2 varnishtop

  • -1:打印統計信息一次並退出,而不是持續更新的顯示
  • -i taglist:能夠同時使用多個-i選項,也能夠一個選項跟上多個標籤
  • -I <[taglist:]regex>:對指定的標籤的值基於regex進行過濾
  • -x taglist:排除列表
  • -X <[taglist:]regex>:對指定的標籤的值基於regex進行過濾,符合條件的予以排除

  [sleepy↓]

相關文章
相關標籤/搜索