關於varnish緩存



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

緩存的概念

熟悉一些名詞:

  • 時間局部性:一個數據被訪問過之后,可能很快會被再次訪問到;

  • 空間局部性:一個數據被訪問時,其周邊的數據也有可能被訪問到

  • 數據緩存:例如MySQL到web應用服務器之間的緩存,服務器緩存的資源是數據緩存

  • 頁面緩存:接入層和應用層中間的緩存,服務器緩存的是可緩存的頁面,這層就是緩存層

  • 緩存命中率:hit/(hit+miss),一般高於30%命中率則是正向收益,好的設計系統可以達到80%到95%以上

  • 字節命中率:按照數據的字節大小來計算命中率

  • 請求命中率:按照請求的數量來計算命中率

  • 代理式緩存:客戶端訪問緩存服務器,緩存服務器沒有命中緩存時到后端服務器請求數據,此時它作為反向代理服務器工作,這種類型的緩存服務器叫做代理式緩存

  • 旁掛式緩存:客戶端親自去查詢數據庫,並且將數據復制給緩存服務器一份,下次先去找緩存服務器,如果沒有命中則再去數據庫服務器查詢,此時這種工作方式的緩存叫做旁掛式緩存,這個客戶端叫做胖客戶端(smart client)

  • private cache:私有緩存,用戶代理附帶的本地緩存機制

  • public cache:公共緩存,反向代理服務器的緩存功能

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

  • 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

一、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命令完成。


二、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–>交給后端服務器

三、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↓]

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM