Linux之Varnish

緩存的基礎(chǔ)知識(shí)

1、程序本身具有局部性

  • 時(shí)間局部性
    • 過去訪問到的數(shù)據(jù)题翰,也有可能被兩次訪問
  • 空間局部性
    • 一個(gè)數(shù)據(jù)被訪問到時(shí)恶阴,離它最近的文件可能馬上也會(huì)被訪問

2、命中率

  • 文檔命中率
    • 從文檔個(gè)數(shù)進(jìn)行衡量
  • 字節(jié)命中率
    • 從內(nèi)容大小進(jìn)行衡量

3豹障、緩存系統(tǒng)的特性

  • 緩存對(duì)象
    • 有生命周期冯事,且是定期清理的
  • 緩存空間耗盡
    • 使用LRU(最近最少使用算法)或者M(jìn)RU算法進(jìn)行緩存項(xiàng)清理
  • 不可緩存項(xiàng)
    • 用戶私有數(shù)據(jù)

4、緩存系統(tǒng)一般處理步驟

  • 接收請(qǐng)求
  • 解析請(qǐng)求
    • 提取請(qǐng)求的URL及各種首部
  • 查詢緩存
  • 新鮮度檢測(cè)
  • 創(chuàng)建響應(yīng)報(bào)文
  • 發(fā)送響應(yīng)報(bào)文
  • 記錄日志

5血公、新鮮度檢測(cè)機(jī)制

  • 過期日期
    • HTTP/1.0 : expires(其是一個(gè)絕對(duì)時(shí)間)
    • HTTP/1.1 : Cache-Control: max-age=600(其是一個(gè)相對(duì)時(shí)間)
  • 產(chǎn)效性再驗(yàn)證(revalidate)
      1. 如果原始內(nèi)容未改變昵仅,則僅響應(yīng)首部信息,響應(yīng)碼為304(not modified)
      1. 如果原始內(nèi)容發(fā)生了改累魔,則正常響應(yīng)摔笤,響應(yīng)碼為200
    • 3)如果原始內(nèi)容消失,則響應(yīng)404垦写,此時(shí)緩存中的cache object也應(yīng)該被刪除
  • 條件式請(qǐng)求方式
    • If-Modified-Since : 基于請(qǐng)求內(nèi)容的時(shí)間戳作驗(yàn)證
    • If-unmodified-Since
    • If-Match
    • If-None-Match : 結(jié)合Etag對(duì)文件做MD5校驗(yàn)

6吕世、HTTP緩存相關(guān)首部

  • age : 一個(gè)緩存對(duì)象從產(chǎn)生到此刻為止,經(jīng)過的多少時(shí)間

  • Cache-Control請(qǐng)求首部

    • no-cache : 不要從緩存中返回內(nèi)容
    • max-age : 相對(duì)過期時(shí)間梯投,是以秒為單位
    • max-stale : 可以接受的對(duì)象命辖,但是過期時(shí)間必須小于max-stale值
    • min-fresh : 接受其新鮮生命期大于其當(dāng)前age跟min-fresh值之各的緩存對(duì)象
  • Cache-Control響應(yīng)首部

    • no-cache : 可以緩存,但要跟web服務(wù)器再驗(yàn)證
    • no-store : 不允許緩存
    • public : 可以用cache內(nèi)容回應(yīng)任何用戶
    • private : 只能用緩存內(nèi)容回應(yīng)先前請(qǐng)求該內(nèi)容的那個(gè)用戶
    • max-age : 本響應(yīng)包含的對(duì)象的過期時(shí)間
    • s-maxage : 公共緩存的最大生命周期
    • must-revlidate : 每次響應(yīng)給客戶端時(shí)分蓖,必須做有效性驗(yàn)證
緩存時(shí)需要考慮到的特殊首部
Authorization:跟授權(quán)相關(guān)的首部
cookie:用戶識(shí)別相關(guān)的首部
Vary:accept-encoding:所能接受的字符編碼格式

以上三種首部未特性情況下是不予緩存

通常與緩存相關(guān)的方法:
1尔艇、GET
2、HEAD

7么鹤、常見的緩存服務(wù)開源解決方案

  • varnish : 專用于web服務(wù)的緩存
  • squid : 類似nginx,apache终娃,但比varnish穩(wěn)定

Varnish

varnish對(duì)比squid的優(yōu)點(diǎn)

  • 1、varnish的穩(wěn)定性很高午磁,兩者在完成相同負(fù)荷的工作時(shí)尝抖,squid服務(wù)器發(fā)生故障的幾率要高于varnish,因?yàn)閟quid要經(jīng)常重啟
  • 2、varnish訪問速度更快迅皇,其采用了"Visual Page Cache"技術(shù)昧辽,所有緩存數(shù)據(jù)都直接從內(nèi)存中讀取,而squid是從硬盤讀取登颓,因而varnish在訪問速度方面會(huì)更快
  • 3顶瞒、varnish可以支持更多的并發(fā)連接香璃,因?yàn)関arnish的TCP連接釋放要比squid快尤筐,因而在高并發(fā)連接情況下可以支持更多TCP連接
  • 4俩垃、varnish可以通過管理端口,使用正則表達(dá)式批量的清除部分緩存瘤载,而squid是做不到的。
  • 5、squid屬于單進(jìn)程使用單核CPU塞栅,但Varnish是通過fork形式打開多進(jìn)程來做處理,所以是合理的使用所有核來處理相應(yīng)的請(qǐng)求

varnish對(duì)比squid的缺點(diǎn)

  • 1腔丧、varnish進(jìn)程一旦Hang放椰、Crash或者重啟,緩存數(shù)據(jù)都會(huì)從內(nèi)存中完全釋放愉粤,此時(shí)所有請(qǐng)求都會(huì)發(fā)送到后端服務(wù)器砾医,在高并發(fā)情況下,會(huì)給后端服務(wù)器造成很大的壓力
  • 2衣厘、在varnish使用中如蚜,如果單個(gè)vrl的請(qǐng)求通過HA/F5,每次請(qǐng)求不同的varnish服務(wù)器時(shí)影暴,被請(qǐng)求的varnish服務(wù)器都會(huì)被穿透到后端错邦,而同樣的請(qǐng)求會(huì)在多臺(tái)服務(wù)器上緩存 ,也會(huì)造成varnish的緩存資源浪費(fèi)坤检,也會(huì)造成性能下降

varnish的工作進(jìn)程特性

  • varnish工作進(jìn)程示意圖


* Management(主進(jìn)程)
* 實(shí)現(xiàn)應(yīng)用新的配置
* 編譯VCL
* 監(jiān)控Varnish的子進(jìn)程(其management每隔幾秒進(jìn)行子進(jìn)程探測(cè)兴猩,如較長時(shí)間沒有回應(yīng)探測(cè)它將重啟一個(gè)子進(jìn)程)
* 初始化varnish
* 提供命令行接口
* Child/Cache
* accept : 接收新的連接請(qǐng)求,交由worker線程處理
* worker : 用于處理并響應(yīng)用戶請(qǐng)求
* expiry : 管理過期緩存早歇,從緩存中清理過期的Cache
* Vcl compiler
* 把配置文件編譯成VCL格式
* C compiler
* C編譯器倾芝,vcl compiler調(diào)用c compiler
* 日志

    shared memory log,共享內(nèi)存日志大小默認(rèn)一般為90M+箭跳,分為兩部分組成晨另,前一部分為計(jì)數(shù)器,后一部分請(qǐng)求響應(yīng)的相關(guān)數(shù)據(jù)谱姓,日志保存在一個(gè)共享的內(nèi)存空間借尿,只能保存最近最新的日志,需要使用工具屉来,把日志不斷的導(dǎo)出路翻,以實(shí)現(xiàn)長期保存       
    * `varnishlog` : 其以守護(hù)進(jìn)程方式運(yùn)行,需要將其重啟才會(huì)把日志導(dǎo)入到本地磁盤茄靠,類似于httpd日志的comm格式
    * `varnishncsa` : 其與varnishlog類似茂契,但日志的格式與httpd的combind格式類似
  • varnish的進(jìn)程工作特性
    • varnish啟動(dòng)或有2個(gè)進(jìn)程master(management)進(jìn)程和child(worker)進(jìn)程,master讀入存儲(chǔ)配置命令慨绳,進(jìn)行初始化掉冶,然后fork并監(jiān)控child,child則分配線程進(jìn)行cache工作真竖,child還會(huì)做管理線程生成很多的worker線程
    • child線程主線程初始化過程中,將存儲(chǔ)大文件整個(gè)加載到內(nèi)存中厌小,如果該文件超出系統(tǒng)的虛擬內(nèi)存恢共,則會(huì)減少原來配置MMAP大小,然后繼續(xù)加載璧亚,這時(shí)候創(chuàng)建并初始化空間存儲(chǔ)結(jié)構(gòu)體讨韭,放在存儲(chǔ)管理的struct中,等待分配
    • 接著varnish某個(gè)負(fù)責(zé)接受http連接的線程開始等待用戶請(qǐng)求癣蟋,如果有新http連接拐袜,但這個(gè)線程只負(fù)責(zé)接收,然后喚醒等待線程池中的work線程梢薪,進(jìn)行請(qǐng)求處理
    • work線程讀入uri后,將會(huì)查找已有的object,命中直接返回尝哆,沒有命中則會(huì)從后端服務(wù)器中取出來秉撇,放到緩存中,如果緩存已滿秋泄,會(huì)根據(jù)LRU算法釋放舊的Object琐馆,對(duì)于釋放緩存,有一個(gè)超時(shí)線程檢測(cè)緩存中所有object的生命周期恒序,如果緩存過期(ttl),則刪除瘦麸,釋放相應(yīng)的存儲(chǔ)內(nèi)存
varnish使用單進(jìn)程多線程模型,其worker stats類似于一個(gè)線程池歧胁,所有的資源將整合在一個(gè)工作區(qū)中滋饲,以降低線程在申請(qǐng)或修改內(nèi)存時(shí),出現(xiàn)的競(jìng)爭(zhēng)的可能性喊巍,當(dāng)多個(gè)線程同時(shí)訪問同個(gè)資源時(shí)屠缭,工作區(qū)對(duì)資源以施加鎖保證用戶的請(qǐng)求在資源爭(zhēng)用時(shí),后來的線程處于等待狀態(tài)崭参,以協(xié)調(diào)線程的工作呵曹。
  • varnish存儲(chǔ)緩存機(jī)制

    • malloc

      基于內(nèi)存存儲(chǔ),在內(nèi)存中存儲(chǔ)各緩存對(duì)象何暮,時(shí)間久了會(huì)產(chǎn)生緩存碎片奄喂,如果分配的內(nèi)存太大,會(huì)降低效率海洼。varnish可能會(huì)激活大內(nèi)存空間分配機(jī)制(在Centos6以后)跨新,這樣也會(huì)降低緩存的查詢效率

    • file

      所有緩存對(duì)象緩存在單個(gè)文件中,重啟后將會(huì)失效贰军,不支持持久機(jī)制玻蝌,建議使用SSD存放緩存數(shù)據(jù)蟹肘,一般用于大文件緩存,如圖片等

    • persistent

      基于文件的持久存儲(chǔ)俯树,varnish重啟了帘腹,緩存還有效,其目前為實(shí)驗(yàn)性項(xiàng)目许饿,生產(chǎn)環(huán)境中不能使用

  • varnish內(nèi)存分配回收機(jī)制
    • 分配
      • malloc()函數(shù)
      • jemalloc()函數(shù) : 其是malloc的并發(fā)實(shí)現(xiàn)
    • 回收
      • free()函數(shù)
  • VCL編程語法

    VCL:varnish configuration language阳欲,又被稱之為DSL(域)編譯語言,其是參照C和perl語言的風(fēng)格編寫陋率,基本格式如下:

    • sub NAME {

      ....;

    }
    
* 不支持循環(huán)
* 受狀態(tài)引擎的變量球化,變量的可調(diào)用位置與state engine有密切相關(guān)性
* 支持終止語句,使用ruturn()返回一個(gè)action,其沒有返回值
* 可自定義變量
* //,#,/* */: 用于注釋瓦糟,會(huì)被編譯器忽略
* “域”專用筒愚,只能一個(gè)域有效
* 操作符: `=,==,~,!,&&,||`
* 條件判斷語句的寫法:

```
單分支:
if (condition) {
    ....;
} else {
    ....;
}

多分支:
if (condition) {
    ...;
} elseif {
    ...;
} else {
    ...;
}
```
* 變量賦值:`set name = value`
* 撤消變量的值:`unset name`

安裝及配置Varnish

Centos 6

  • 安裝
    • yum install varnish : 默認(rèn)安裝為varnish2的版本
  • 主進(jìn)程配置文件
    • /etc/sysconfig/varnish
    • /etc/varnish/default.vcl : VCL引擎配置文件
  • 服務(wù)管理腳本
    • /etc/rc.d/init.d/varnish : varnish服務(wù)主進(jìn)程管理
    • /etc/rc.d/init.d/varnishlog : varnishlog服務(wù)管理
    • /etc/rc.d/init.d/varnishncsa : varnishncsa服務(wù)管理

Centos 7

  • 安裝
    • yum install varnish : 默認(rèn)安裝為varnish 4的版本
  • 主進(jìn)程配置文件
    • /etc/varnish/varnish.params : varnish服務(wù)主進(jìn)程管理
    • /etc/varnish/default.vcl : VCL引擎配置文件
  • 服務(wù)管理腳本
    • /usr/lib/systemd/system/varnish.service
    • /usr/lib/systemd/system/varnishlog.service
    • /usr/lib/systemd/system/varnishncsa.service

varnish主配置文件參數(shù)說明

  • RELOAD_VCL=1 : 是否啟動(dòng)加載VCL配置文件
  • VARNISH_VCL_CONF=/etc/varnish/default.vcl : varnish的VCL配置文件路徑
  • VARNISH_LISTEN_PORT=6081 : 默認(rèn)監(jiān)聽端口
  • VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 : 遠(yuǎn)程管理監(jiān)聽地址
  • VARNISH_ADMIN_LISTEN_PORT=6082 : 遠(yuǎn)程管理監(jiān)聽端口
  • VARNISH_SECRET_FILE=/etc/varnish/secret : varnish默認(rèn)加載的密鑰文件,其為遠(yuǎn)程連接varnish的共享密鑰文件
  • VARNISH_MIN_THREADS=50 : varnish最少啟動(dòng)worker線程
  • VARNISH_MAX_THREADS=1000 : varnish最大啟動(dòng)worker線程數(shù)(據(jù)說超出5000就不穩(wěn)定了)
  • VARNISH_THREAD_TIMEOUT=120 : 空閑線程的超時(shí)時(shí)間菩浙,超時(shí)后被父進(jìn)程銷毀
  • VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin : varnish的緩存存儲(chǔ)位置文件巢掺,其是二進(jìn)制格式
  • VARNISH_STORAGE_SIZE=1G : 緩存大小
  • VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}” : 基于文件存儲(chǔ)緩存的設(shè)置方式
  • VARNISH_STORAGE_SHM=64M : 基于內(nèi)存的存儲(chǔ)緩存,指定緩存的大小劲蜻,不可與文件的方式共存
  • VARNISH_STORAGE=“malloc,${VARNISH_STORAGE_SHM}” : varnish基于內(nèi)存存儲(chǔ)緩存的設(shè)置方式
注意:varnish配置文件修改不應(yīng)重啟服務(wù)陆淀,而是手動(dòng)加載配置文件

Varnish管理工具

varnishd命令

其可以在/etc/sysconfig/varnish的配置文件中完成

  • Options
    • -f : vcl的配置文件
    • -a address[:port] :服務(wù)監(jiān)聽的IP地址及端口
    • -s[name=]type[,options] : varnish緩存的存儲(chǔ)機(jī)制
      • options
        • malloc[,size]
        • file[,path[,size[,granularity]]] (力度)
        • persistent,path,size
    • -T address[:port] : 指定管理接口,默認(rèn)6082
    • -p param=value : 指定參數(shù)
    • -r param : 指定只讀參數(shù)

2先嬉、varnishadm命令

其是通過連接varnish服務(wù)端轧苫,可以實(shí)現(xiàn)varnish服務(wù)的管理操作,實(shí)現(xiàn)動(dòng)態(tài)加載VCL的配置文件

  • Options:
    • -S scret_file : 密鑰文件疫蔓,跟服務(wù)啟動(dòng)的一樣含懊,在varnish目錄下存放
    • -T IP:PORT : 連接服務(wù)端的端口,默認(rèn)為6082
  • varnish命令行命令
    • vcl.list : 查看vcl配置文件的列表
    • vcl.load NAME default.vcl : 加載vcl當(dāng)前的配置文件為NAME
    • vcl.use NAME : 使用加載的配置文件
    • vcl.show NAME : 查看加載的配置文件詳細(xì)配置信息
    • vcl.discard : 刪除加載的配置文件
    • backend.list : 查看后端服務(wù)器列表及狀態(tài)
    • param.show -l : 查看varnish主進(jìn)程的運(yùn)行選項(xiàng)參數(shù)
    • param.set <param> <value> : 在運(yùn)行時(shí)設(shè)定主進(jìn)程的運(yùn)行參數(shù)
    • ping : 判斷后端服務(wù)器的狀態(tài)
    • status : 查看進(jìn)行的運(yùn)行狀態(tài)
    • panic.show : 如果某個(gè)子進(jìn)程曾經(jīng)panic過衅胀,可以使用這個(gè)命令查看(panic本為恐慌绢要,代表服務(wù)曾經(jīng)崩潰過)
    • storage.list: 查看緩存存儲(chǔ)機(jī)制
    • ban <field> <operator> <arg> [&& <field> <oper> <arg> ]…. : 手動(dòng)清除緩存
    • ban.list : 列出清除緩存的規(guī)則列表,由上一個(gè)參數(shù)定義

3拗小、Varnishtop命令

內(nèi)存日志區(qū)域查看工具

  • Options
    • -I REGEXP : 僅顯示被模式匹配到的條目重罪,過濾右邊的信息條目
    • -X : 僅顯示不被模式匹配到的條目,過濾右邊的信息條目
    • -i : 過濾左邊字段
    • -x : 指定的不顯示哀九,不指定的才顯示
    • -C : 忽略字符大小寫
    • -d : 顯示已有的日志
    varnishtop -i RxHeader
    varnishtop -I ^User-Agent
    varnishtop -I ^User-Agent -1 : 只顯示一屏即退出
    

4剿配、varnishstat命令

varnish的運(yùn)行統(tǒng)計(jì)數(shù)據(jù)

  • Options
    • -f filed,filed,.... : 指明只顯示哪些參數(shù)
    • -l : 列出所有字段
    • -x : 以XML格式輸出
    • -j : 以json格式輸出

5、varnishlog命令

啟動(dòng)以comm格式記錄日志到磁盤

6阅束、varnishncsa命令

啟動(dòng)以combind格式記錄日志到磁盤

VCL Engine

vcl engine是varnish通過VCL配置語言定義的緩存策略呼胚,state engine之間有相關(guān)性,上級(jí)engine通過return指明下級(jí)engine息裸,常用的引擎(varnish version 3),如下:

  • vcl_recv
    • 由return(lookup)定義到vcl_hash引擎
  • vcl_hash
    • 其是對(duì)緩存項(xiàng)進(jìn)行hash計(jì)算
  • vcl_fetch
    • 其是向后端服務(wù)器取文件的
  • vcl_hit
    • 其下一個(gè)工作引擎可能是deliver,也有可能是pass(為pass的情況下:命中后需要把緩存強(qiáng)制刪除)
  • vcl_miss
  • vcl_deliver
  • vcl_pipe
    • 無法識(shí)別的方法蝇更,交由pipe管道引擎處理
  • vcl_pass
    • 可以理解的方法沪编,但不緩存,就經(jīng)由pass
  • vcl_error

Vcl engine 完整的工作流程示意圖(1)

Vcl engine 完整的工作流程示意圖(2)

Vcl engine常見工作流程

1年扩、查詢緩存未命中的工作流
2蚁廓、查詢緩存命中的工作流
3、未識(shí)別的HTTP方法工作流
4厨幻、不予緩存的工作流
5相嵌、完整的工作流
  • restart

    • 當(dāng)命中后,把url進(jìn)行了重寫操作况脆,就需要從vcl_recv重新開始饭宾,即為重啟,這類操作被稱之為restart,但varnish有一個(gè)內(nèi)申機(jī)制格了,即重啟了10次看铆,仍然還在重啟,此次請(qǐng)求將會(huì)被丟棄
  • error

    • 類似于404類的請(qǐng)求錯(cuò)誤
6盛末、狀態(tài)引擎說明
  • 1性湿、首先由vcl_init裝載vcl引擎
  • 2、再由vcl_recv將請(qǐng)求接入满败,分析是否服務(wù)于此請(qǐng)求,并指定如何服務(wù)叹括,可能交由下一個(gè)(pipe,pass,hash)處理
  • 3算墨、vcl engine可用的return函數(shù)
    • return(lookup) : 送給vcl_hash引擎處理
    • return(pass) : 交給vcl_pass引擎處理
    • return(pipe) : 交由vcl_pipe引擎處理
    • error CODE : 返回錯(cuò)誤和相應(yīng)的CODE給客戶端
    • return(deliver) : 交由vcl_deliver直接投遞
    • return(hit_for_pass)
    • return(restart) : 重啟請(qǐng)求

VCl引擎中常用變量

  • 1、在任何引擎中均可使用
    • now : 獲取當(dāng)前系統(tǒng)當(dāng)前時(shí)間
    • .host : 后端主機(jī)或主機(jī)名
    • .port : 后端主機(jī)的端口或服務(wù)名
  • 2汁雷、用于處理一個(gè)請(qǐng)求階段

可用于recv,hash,pipe,pass引擎中净嘀。

* `client.ip` : 客戶端IP地址
* `server.hostname` : 服務(wù)器的主機(jī)名(緩存服務(wù)器)
* `server.ip` : varnish服務(wù)器的IP
* `server.port` : varnish服務(wù)器的端口
* `req.request` : 客戶端的請(qǐng)求方法
* `req.url` : 客戶端請(qǐng)求的URL
* `req.proto` : http協(xié)議版本
* `req.backend` : 用于服務(wù)此次請(qǐng)求的后端主機(jī)
* `req.backend.healthy` : 后端主機(jī)的健康狀態(tài)
* `req.http.HEADER` : 引用請(qǐng)求報(bào)文中指定的首部,哪req.http.host
* `req.hash_always_miss`
* `req.hash_ignore_busy`
* `req.can_gzip` : 客戶端是否能夠接受GZIP壓縮格式的響應(yīng)內(nèi)容
* `req.restarts` : 此請(qǐng)求被重啟的次數(shù)
  • 3侠讯、vanish向backend主機(jī)發(fā)起請(qǐng)求前可用的變量
    • bereq.request : 請(qǐng)求方法
    • bereq.url
    • bereq.proto
    • bereq.http.HEADER
    • bereq.connect_timeout : 等待與后端建立連接的超時(shí)時(shí)長
  • 4挖藏、當(dāng)后端服務(wù)器響應(yīng)varnish,但未放置緩存之前
    • beresp.do_stream : 表示流式響應(yīng)
    流式響應(yīng):當(dāng)后端backend主機(jī)響應(yīng)一個(gè)10M大小的文件厢漩,10M的文件是由多個(gè)數(shù)據(jù)報(bào)文組成膜眠,當(dāng)varnish接收到一個(gè)報(bào)文時(shí),就直接將報(bào)文發(fā)給客戶端溜嗜,也不是等待數(shù)據(jù)報(bào)文接收完整后再發(fā)出宵膨,這就被稱之為流式響應(yīng)
    
    • beresp.do_gzip : 從后端服務(wù)器收到的響應(yīng)報(bào)文,要不要壓縮以后存儲(chǔ)下來
    • beresp.do_gunzip : 從后端服務(wù)器收到的響應(yīng)報(bào)文炸宵,如果壓縮了辟躏,要不要解壓縮后再存下來
    • beresp.http.HEADER
    • beresp.proto
    • beresp.status : 響應(yīng)狀態(tài)碼
    • beresp.response : 響應(yīng)時(shí)的原因短語
    • beresp.ttl : 響應(yīng)對(duì)象的剩余生存時(shí)長,單位為second
    • beresp.backend.name : 此響應(yīng)報(bào)文來源的backend主機(jī)名稱
    • beresp.backend.ip
    • beresp.backend.port
    • beresp.storage : 緩存后端
  • 5土全、緩存對(duì)象存入cache之后可用的變量捎琐,大多數(shù)為只讀
    • obj.response : 服務(wù)端所返回的原因短語
    • obj.proto : 響應(yīng)時(shí)使用的協(xié)議
    • obj.status
    • obj.ttl : 指明當(dāng)前的對(duì)象緩存的還有多少時(shí)長
    • obj.hits : 這個(gè)緩存對(duì)象已經(jīng)命中多少次(大約值)
    • obj.http.HEADER : 后端服務(wù)器的響應(yīng)首部
  • 6会涎、決定對(duì)請(qǐng)求的健做hash計(jì)算時(shí)可用的變量
    • req.hash : 把什么內(nèi)容做hash鍵,做查詢的健
  • 7瑞凑、在為客戶端準(zhǔn)備響應(yīng)報(bào)文時(shí)可用的變量
    • resp.proto : 指定使用什么協(xié)議來響應(yīng)
    • resp.status
    • resp.response
    • resp.http.HEADER

vcl定義后端服務(wù)器主機(jī)

定義的后端主機(jī)需要在recv中調(diào)用末秃,必須會(huì)出錯(cuò)

  • 1、定義格式:
    backend NAME {
        .host=  #后端backend server IP地址
        .port=  #后端backend server 端口
    }
    
  • 2拨黔、后端服務(wù)器需要vcl_recv中調(diào)用,示例如下
    示例1:
    
    sub vcl_recv {
        ...
        if(req.url ~ "test.html") {
            set req.backend = NAME;
        } else {
            set req.backend = NAME1;
        }
        
    示例2:
    
    sub vcl_recv {
        ...
        set req.backend = NAME;
    }
    

定義后端服務(wù)器集群

varnish中可以使用director指令將一個(gè)或多個(gè)近似的后端主機(jī)定義成一個(gè)邏輯組蛔溃,并可以指定其調(diào)度方法(也叫挑選方法)來輪流將請(qǐng)求發(fā)送至后端backend主機(jī)上,不同的director可以使用同一個(gè)后端主機(jī)篱蝇,而某director也可以使用“匿名”后端主機(jī)(在director中直接定義)贺待,每個(gè)director都必須有其專用名,且在定義后必須在vcl中進(jìn)行調(diào)用零截,VCL中任何可以指定后端主機(jī)的位置均可按需將其替換為調(diào)用某已定義的director

  • 1麸塞、定義方法
    backend web1 {
        .host = "www.zhenping.me";
        .port = "80";
    }
    
    director webservers random {
        .retries = 5;
        {
            .backend = web1;
            .weight = 2;
        }
        {
            .backend = {
                .host = "www2.zhenping.me";
                .port = "80";
            }
        .weight = 3;
        }
    }
    
    以上為兩種定義方法示例
    
    
  • 2、調(diào)用方法
    示例:
        
    sub vcl_recv {
        ....
        set req.backend = webservers;
    }
    
    
  • 3涧衙、backend調(diào)度方法
    • round-robin

      • 其是對(duì)資源對(duì)象的輪詢調(diào)度方法(當(dāng)訪問index1.html到后端server1,當(dāng)訪問index2.html到后端server2),其沒有參數(shù)
    • random

      • 其是對(duì)后端backend server的隨機(jī)調(diào)度方法哪工,也是建議使用的方法,其支持以下參數(shù)
        • .weight = # : 權(quán)重
        • .retires = # : 來設(shè)定查找一個(gè)健康后端主機(jī)時(shí)的嘗試次數(shù)
      varnish2.1.0之后弧哎,random挑選方法又多了兩種變化形式client和hash雁比,client類型的director使用client.identity作為挑選因子,這意味著client.identity相同的請(qǐng)求都將被發(fā)送至同一后端主機(jī)撤嫩,clinet.itdentity默認(rèn)為client.ip偎捎,但也可以在VCL中將其修改為所需要的標(biāo)識(shí)符,類似的序攘,hash類型的director使用hash數(shù)據(jù)作為挑選因子茴她,這意味著對(duì)同一個(gè)URL的請(qǐng)求將被發(fā)往同一個(gè)后端主機(jī),其常用于多級(jí)緩存的場(chǎng)景中程奠,然后丈牢,無論是client還是hash,當(dāng)其傾向于使用后端主機(jī)不可用時(shí)將會(huì)重新挑選新的后端主機(jī)
      
    • fallback

      • 用于定義備用服務(wù)器瞄沙,其更多的是冗余的作用己沛,以下示例
      director b3 fallback {
          { .backend = web1; }
          { .backend = web2; }
          { .backend = web3; }
      }
      
      注意: 只有web1不可用才會(huì)使用到web2,web2和web1同時(shí)不可用時(shí),才會(huì)使用到web3,如果web2不可用距境,但web1可用泛粹,它也會(huì)使用web1
      

varnish檢測(cè)后端主機(jī)的健康狀態(tài)

varnish可以檢測(cè)后端主機(jī)的健康狀態(tài),在判定后端主機(jī)失效時(shí)能自動(dòng)將其從可用后端主機(jī)列表中移除肮疗,而一旦其重新變得可用還可以自動(dòng)將其設(shè)定為可用晶姊,為了避免誤判,varnish在探測(cè)后端主機(jī)的健康狀態(tài)發(fā)生轉(zhuǎn)變時(shí)(比如某次檢測(cè)時(shí)某后端主機(jī)突然成為不可用狀態(tài))伪货,通常需要連續(xù)執(zhí)行幾次探測(cè)均為新狀態(tài)才將其標(biāo)記為轉(zhuǎn)換后的狀態(tài)

每個(gè)后端服務(wù)器當(dāng)前探測(cè)的健康狀態(tài)探測(cè)方法通過.probe進(jìn)行設(shè)定们衙,其結(jié)果可由req.backend.healthy變量獲取钾怔,也可通過varnishlog中的backend_health查看或varnishadm的debug.health查看

  • .probe中探測(cè)常用指令

    • url : 探測(cè)后端主機(jī)健康狀態(tài)時(shí)請(qǐng)求的URL,默認(rèn)為/
    • .request : 探測(cè)后端主機(jī)健康狀態(tài)時(shí)所請(qǐng)求內(nèi)容的詳細(xì)格式蒙挑,定義后宗侦,它會(huì)替換.rul指定的探測(cè)方法,如下:
    .request = 
        "GET /.healthtest.html HTTP/1.1"
        "Host:www.zhenping.me"
        "Connection: close" #探測(cè)時(shí)關(guān)閉長連接
    
    • .window : 設(shè)定在判定后端主機(jī)健康狀態(tài)時(shí)基于最近多少次的探測(cè)進(jìn)行忆蚀,默認(rèn)是8次
    • .threshold : 在window中指定的次數(shù)中矾利,至少有多少次是成功的才判定后端主機(jī)是正常健康運(yùn)行,默認(rèn)是3次
    • .initial : varnish啟動(dòng)時(shí)對(duì)后端主機(jī)至少需要多少次的成功探測(cè)馋袜,轉(zhuǎn)儲(chǔ)同.threshold
    • .expected_response : 期望后端主機(jī)的響應(yīng)狀態(tài)碼男旗,默認(rèn)是200
    • interval : 探測(cè)請(qǐng)求的發(fā)送周期,默認(rèn)是5秒
    • .timeout : 每次探測(cè)請(qǐng)求的過期時(shí)長欣鳖,默認(rèn)為2秒
```
示例1:
    backend web1 {
        .host = "www.zhenping.me";
        .probe = {
            .url = "/.healthtest.html";
            .interval = 1s;
            .window = 5;
            .threshold = 2;
        }
    }
    
示例2:
    可以將probe的機(jī)制定義為一個(gè)代碼塊察皇,在backend中引用
    
    probe PRO_NAME {
        ....;
    }
    
    backend NAME {
        ...;
        .probe = PRO_NAME;
    }
    
```

移除單個(gè)緩存對(duì)象

purge用于清理緩存中的某特定對(duì)象及其變種(variants),因此泽台,在有著明確要修剪的緩存對(duì)象時(shí)可以使用此種方式什荣。HTTP協(xié)議的PURGE方法可以實(shí)現(xiàn)purge功能,不過怀酷,其僅能用于vcl_hit和vcl_miss中稻爬,它會(huì)釋放內(nèi)存工作并移除指定緩存對(duì)象的所有Vary:-變種,并等待下一個(gè)針對(duì)此內(nèi)容的客戶端請(qǐng)求到達(dá)時(shí)刷新此內(nèi)容蜕依。另外桅锄,其一般要與return(restart)一起使用。下面是個(gè)在VCL中配置的示例

acl purgers {
            "127.0.0.1";
            "192.168.0.0"/24;
        }

        sub vcl_recv {
            if (req.request != "GET" &&
                req.request != "HEAD" &&
                req.request != "PUT" &&
                req.request != "POST" &&
                req.request != "TRACE" &&
                req.request != "OPTIONS" &&
                req.request != "DELETE" &&
                req.request != "PURGE") {    #需要添加PURGE方法笔横,以不被送到PIPE引擎處理
                /* Non-RFC2616 or CONNECT which is weird. */
                return (pipe);
            }
            if (req.request != "GET" && req.request != "HEAD" && req.request != "PURGE") { #也需要添加PURGE方法不被送到PASS引擎,以確保PURGE方法可以到達(dá)HASH引擎
                /* We only deal with GET and HEAD by default */
                return (pass);
            }
            if (req.request == "PURGE") {
                if (!client.ip ~ purgers) {
                    error 405 "Method not allowed";
                }
                return (lookup);
            }
        }
        sub vcl_hit {
            if (req.request == "PURGE") {
                purge;
                error 200 "Purged";
            }
        }
        sub vcl_miss {
            if (req.request == "PURGE") {
                purge;
                error 404 "Not in cache";
            }
        }
        sub vcl_pass {
            if (req.request == "PURGE") {
                error 502 "PURGE on a passed object";
            }
        }

        客戶端在發(fā)起HTTP請(qǐng)求時(shí)咐吼,只需要為所請(qǐng)求的URL使用PURGE方法即可吹缔,其命令使用方式如下:
        # curl -I -X PURGE http://varniship/path/to/someurl

使用示例1

#drop any cookies sent to wordpress
        sub vcl_recv {
            if(!(req.url ~ “wp-(login|admin)”)) {
                unset req.http.cookie;
            }
        }

使用示例2

sub vcl_recv {
            if (req.http.host ~ “(?i)^(www.)?zhenping.me$”) {
                set req.http.host = “www.zhenping.me”;
                set req.backend = www;
            } elseif (req.http.host ~ “(?i)^images.zhenping.me$”) {
                set req.backend = images;
            } else {
                error 404 “Unknown virtual host”;
            }
        }

使用示例3

sub vcl_recv {
    if (req.http.User-Agent ~ "iPad" || req.http.User-Agent ~ "iPhone" || req.http.User-Agent ~ "Android") {
        set req.http.X-Device = "mobile";
    } else {
        set req.http.X-Device = "Desktop";
    }
}

使用示例4(測(cè)試是否命中緩存)

 sub vcl_deliver {
        if (obj.hits > 0) {
                set resp.http.X-Cache = "HIT";
        } else {
                set resp.http.X-Cache = "MISS";
        }
     return (deliver);
 }

使用示例5(隱藏后端服務(wù)軟件版本)

 sub vcl_deliver {
       
        if (resp.http.Server) {
                unset resp.http.Server;   #出于安全考慮,需要將后端所使用的軟件名稱和版本隱藏起來
        }
     return (deliver);
 }

生產(chǎn)環(huán)境實(shí)例

acl purge {
          "localhost";
          "127.0.0.1";
          "10.1.0.0"/16;
          "192.168.0.0"/16;
        }

        sub vcl_hash {
          hash_data(req.url);
          return (hash);
        }

        sub vcl_recv {
          set req.backend = shopweb;
        #  set req.grace = 4h; 
          if (req.request == "PURGE") {
            if (!client.ip ~ purge) {
              error 405 "Not allowed.";
            }
            return(lookup);
          }
          if (req.request == "REPURGE") {
            if (!client.ip ~ purge) {
              error 405 "Not allowed.";
            }
            ban("req.http.host == " + req.http.host + " && req.url ~ " + req.url);
            error 200 "Ban OK";
          }
          if (req.restarts == 0) {
            if (req.http.x-forwarded-for) {
              set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
            } 
            else {
              set req.http.X-Forwarded-For = client.ip;
            }
          }
          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);
          }
          if (req.http.Authorization) {
            /* Not cacheable by default */
            return (pass);
          }
         

          if ( req.url == "/Heartbeat.html" ) {
            return (pipe);
          }
          if ( req.url == "/" ) {
            return (pipe);
          }
          if ( req.url == "/index.jsp" ) {
            return (pipe);
          }

          if (req.http.Cookie ~ "dper=") {
            return (pass);
          }
          if (req.http.Cookie ~ "sqltrace=") {
            return (pass);
          }
          if (req.http.Cookie ~ "errortrace=") {
            return (pass);
          }
        #   if ( req.request == "GET" && req.url ~ "req.url ~ "^/shop/[0-9]+$" ) {
          if ( req.url ~ "^/shop/[0-9]+$" || req.url ~ "^/shop/[0-9]?.*" ) {
            return (lookup);
          }

         if ( req.url ~ "^/shop/(\d{1,})/editmember" || req.url ~ "^/shop/(\d{1,})/map" || req.url ~ "^/shop/(\d+)/dish-([^/]+)" ) {
            return (lookup);
          } 

          return (pass);
        #   return (lookup);
        }

        sub vcl_pipe {
          return (pipe);
        }

        sub vcl_pass {
          return (pass);
        }

        sub vcl_hit {
          if (req.request == "PURGE") {
            purge;
            error 200 "Purged.";
          }
          return (deliver);
        }

        sub vcl_miss {
          if (req.request == "PURGE") {
            error 404 "Not in cache.";
          }
        #   if (object needs ESI processing) {
        #     unset bereq.http.accept-encoding;
        #   }
          return (fetch);
        }


        sub vcl_fetch {
          set beresp.ttl = 3600s;
          set beresp.http.expires = beresp.ttl;
          #set beresp.grace = 4h;
        #   if (object needs ESI processing) {
        #     set beresp.do_esi = true;
        #     set beresp.do_gzip = true;
        #   }

          if ( req.url ~ "^/shop/[0-9]+$" || req.url ~ "^/shop/[0-9]?.*" ) {   
            set beresp.ttl = 4h;
          }

         if ( req.url ~ "^/shop/(\d{1,})/editmember" || req.url ~ "^/shop/(\d{1,})/map" || req.url ~ "^/shop/(\d+)/dish-([^/]+)" ) {
             set beresp.ttl = 24h;
          } 

          if (beresp.status != 200){
            return (hit_for_pass);
          }
          return (deliver);
        }

        sub vcl_deliver {
          if (obj.hits > 0){
            set resp.http.X-Cache = "HIT";
          } 
          else {
            set resp.http.X-Cache = "MISS";
          }
          set resp.http.X-Powered-By = "Cache on " + server.ip;
          set resp.http.X-Age = resp.http.Age;
          return (deliver);
        }

        sub vcl_error {
          set obj.http.Content-Type = "text/html; charset=utf-8";
          set obj.http.Retry-After = "5";
          synthetic {""} + obj.status + " " + obj.response + {""};
          return (deliver);
        }

        sub vcl_init {
          return (ok);
        }

        sub vcl_fini {
          return (ok);
        }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锯茄,一起剝皮案震驚了整個(gè)濱河市厢塘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肌幽,老刑警劉巖晚碾,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異喂急,居然都是意外死亡格嘁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門廊移,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糕簿,“玉大人探入,你說我怎么就攤上這事《” “怎么了蜂嗽?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長殃恒。 經(jīng)常有香客問我植旧,道長,這世上最難降的妖魔是什么离唐? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任病附,我火速辦了婚禮,結(jié)果婚禮上侯繁,老公的妹妹穿的比我還像新娘胖喳。我一直安慰自己,他們只是感情好贮竟,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布丽焊。 她就那樣靜靜地躺著,像睡著了一般咕别。 火紅的嫁衣襯著肌膚如雪技健。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天惰拱,我揣著相機(jī)與錄音雌贱,去河邊找鬼。 笑死偿短,一個(gè)胖子當(dāng)著我的面吹牛欣孤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昔逗,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼降传,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了勾怒?” 一聲冷哼從身側(cè)響起婆排,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笔链,沒想到半個(gè)月后段只,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鉴扫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年赞枕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鹦赎,死狀恐怖谍椅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情古话,我是刑警寧澤雏吭,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站陪踩,受9級(jí)特大地震影響杖们,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肩狂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一摘完、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧傻谁,春花似錦孝治、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至态蒂,卻和暖如春杭措,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钾恢。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工手素, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘩蚪。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓泉懦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疹瘦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子崩哩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容