緩存反向代理-Varnish

簡介

Varnish是一款高性能、開源的緩存反向代理服務器。它從客戶端接受請求,並嘗試從緩存中響應請求,若是沒法從緩存中提供響應,Varnish 向後端服務器發起請求,獲取響應,將響應存儲在緩存中,而後把響應發送給客戶端。若是Varnish可以從Cache中響應一個請求,所消耗的時間是微秒級別的,這個響應速度比直接從HTTP服務器響應請求的速度要快兩個數量級,緩存命中率越高,網站的訪問速度就越快。正則表達式

主要特性

  • 緩存位置:可使用內存也可使用磁盤,若是要使用磁盤的話推薦SSD作RAID1;
  • 日誌存儲:日誌也存儲在內存中,存儲策略:固定大小,循環使用;
  • 支持虛擬內存的使用;
  • 有精確的時間管理機制,即緩存的時間屬性控制;
  • 狀態引擎架構:在不一樣的引擎上完成對不一樣的緩存和代理數據進行處理,能夠經過特定的配置語言設計不一樣的控制語句,以決定數據在不一樣位置以不一樣方式緩存;
  • 緩存管理:以二叉堆格式管理緩存數據,作到數據的及時清理。

系統架構

Varnish主要有兩個進程:Management進程與Child進程(也稱爲Cache進程)。算法

  • Management進程:主要對子進程進行管理,實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等;Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,若是在指定的時長內未獲得Child進程的迴應,Management將會重啓此Child進程。
  • Child進程:生成線程池,負責對用戶請求進行處理,並經過hash查找返回用戶結果。

    Child進程包含多種類型的線程,常見的有:編程

    • Accept線程:接收新的鏈接請求並響應;
    • Worker線程:child進程會爲每一個會話啓動一個worker線程,所以在高併發的場景中可能會出現數百個worker線程甚至更多;
    • Object Expiry線程:從緩存中清理過時內容;
    • Commad line線程 : 管理接口;
    • Storage/hashing線程:緩存存儲;
    • Log/stats線程:日誌管理線程;
    • Backend Communication線程:管理後端主機線程。

日誌

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

共享內存日誌大小通常爲90M,其分爲兩部分,前一部分爲計數器,後半部分爲客戶端請求的數據。Varnish提供了多個不一樣的工具,如varnishlog、varnishncsa或varnishstat等來分析共享內存日誌中的信息並可以以指定的方式進行顯示。緩存

算法

Varnish的Director支持的挑選方法中主要有round-robin(輪詢)和random(隨機)兩種。其中,round-robin類型沒有任何參數,只須要爲其指定各後端主機便可,並在某後端主機故障時再也不將其視做挑選對象;random方法隨機從可用後端主機中進行挑選,每個後端主機都須要一個.weight參數指定其權重,同時還可使用.retires參數來設定查找一個健康後端主機時的嘗試次數。服務器

Varnish2.1.0後,random挑選方法又多了兩種變化形式client和hash。client類型的Director使用client.identity做爲挑選因子,這意味着client.identity相同的請求都將被髮送至同一個後端主機;client.identity默認爲cliet.ip,但也能夠在VCL中將其修改成所須要的標識符。相似地,hash類型的Director使用hash數據做爲挑選因子,這意味着對同一個URL的請求將被髮往同一個後端主機,其經常使用於多級緩存的場景中。不管是client還hash,當其傾向於使用後端主機不可用時將會從新挑選新的後端其機。數據結構

VCL工具

Varnish Configuration Language(VCL),Varnish配置緩存策略的工具,它是一種基於「域」(domain specific)的簡單編程語言,可使用運算符包括「 =、==、!、&& 」等,支持使用正則表達式進行字符串匹配,容許用戶使用set自定義變量,支持if判斷語句,也有內置的函數和變量等。VCL策略在啓用前,會由management進程將其轉換爲C代碼,然後再由gcc編譯器將C代碼編譯成二進制程序,編譯完成後management負責將其鏈接至varnish實例,即child進程。架構

後端存儲

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

  • file:使用特定的文件存儲所有的緩存數據,並經過操做系統的mmap()系統調用,將整個緩存文件映射至內存區域(若是條件容許);
  • malloc:使用malloc()庫調用在varnish啓動時向操做系統申請指定大小的內存空間以存儲緩存對象;
  • persistent(experimental):與file的功能相同,但能夠持久存儲數據(即重啓varnish數據時不會被清除),但仍處於測試階段。

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

選擇使用合適的存儲方式有助於提高系統性。從經驗的角度來看,建議在內存空間足以存儲全部的緩存對象時使用malloc的方法,而file存儲有着更好的性能表現。須要注意的是,varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,通常說來,其須要爲每一個緩存對象多使用差很少1K左右的存儲空間,這意味着,對於100萬個緩存對象的場景來講,其使用的緩存空間將超出指定大小1G左右。另外,爲了保存數據結構等,varnish自身也會佔去不小的內存空間。

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

  • malloc [size] 或 file [path [size [granularity]]] 或 persistent path size {experimental}

VCL內置函數

  • vcl_recv函數:用於接收和處理請求。當請求到達併成功接收後被調用,經過判斷請求的數據來決定如何處理請求。此函數通常以以下幾個關鍵字結束:
    • pass:進入pass模式,把請求控制權交給vcl_pass函數;
    • pipe:進入pipe模式,把請求控制權交給vcl_pipe函數;
    • error code [reason]:返回code給客戶端並放棄處理該請求;code是錯誤標識,例如200、405等;reason是錯誤提示信息。
  • vcl_pipe函數:此函數在進入pipe模式時被調用,用於將請求直接傳遞至後端主機,在請求和返回的內容沒有改變的狀況下,將不變的內容返回給客戶端,直到這個連接關閉。此函數通常以以下幾個關鍵字結束:
    • error code [reason]
    • pipe
  • vcl_pass函數:此函數在進入pass模式時被調用,用於將請求直接傳遞至後端主機,後端主機應答數據後送給客戶端,但不進行任何緩存,在當前鏈接下每次都返回最新的內容。此函數通常以以下幾個關鍵字結束:
    • error code [reason]
    • pass
  • vcl_hash:表示在緩存裏查找被請求的對象,而且根據查找的結果把控制權交給函數vcl_hit或者函數vcl_miss
  • vcl_hit函數:在執行vcl_hash後,若是在緩存中找到請求的內容,將自動調用該函數。此函數通常以以下幾個關鍵字結束:
    • deliver:表示將找到的內容發送給客戶端,並把控制權交給函數vcl_deliver
    • error code [reason]
    • pass
  • vcl_miss函數:在執行val_hash後,若是沒有在緩存中找到請求的內容時自動調用該方法,此函數能夠用於判斷是否須要從後端服務器取內容。此函數通常以以下幾個關鍵字結束:
    • fetch:表示從後端獲取請求的內容,並把控制權交給vcl_fetch函數
    • error code [reason]
    • pass
  • vcl_fetch函數:在從後端主機更新緩存而且獲取內容後調用該方法,接着,經過判斷獲取的內容來決定是否將內容放入緩存,仍是直接返回給客戶端。此函數通常以以下幾個關鍵字結束:
    • error code [reason]
    • pass
    • deliver
  • vcl_deliver函數:在緩存中找到請求的內容後,發送給客戶端前調用此方法。此函數通常以以下幾個關鍵字結束:
    • error code [reason]
    • deliver
  • vcl_timeout函數:此函數在緩存內容到期前調用。通常以以下幾個關鍵字結束:
    • discard:表示從緩存中清除該內容。
    • fetch
  • vcl_discard函數:在緩存內容到期後或緩存空間不夠時,自動調用該方法。此函數通常以以下幾個關鍵字結束:
    • keep:表示將內容繼續保留在緩存中
    • discard

如下是VCL處理流程圖,經過下圖能夠更清楚Varnish的工做過程:

Varnish處理 HTTP請求 的過程分爲如下幾個步驟:

  • Receive狀態,也就是請求處理的入口狀態,根據VCL規則判斷該請求應該Pass或Pipe,或者進入Lookup(本地查詢);
  • PIPE狀態,不可緩存數據,直接管道後端處理;
  • Lookup狀態,進入此狀態後,會在hash表中查找數據,若找到,則進入Hit狀態,不然進入miss狀態;
  • Pass狀態,在此狀態下,會進入後端請求,即進入Fetch狀態;
  • Fetch狀態,在Fetch狀態下,對請求進行後端獲取,發送請求,得到數據,並進行本地存儲;
  • Deliver狀態,將獲取到的數據發送給客戶端,而後完成本次請求。

VCL內置公用變量

  • 當請求到達後,可使用的公用變量以下所示:
    • req.backend:指定對應的後端主機
    • server.ip:表示服務器端IP
    • client.ip:表示客戶端IP
    • req.request:指定請求的類型,例如GET、HEAD、POST等
    • req.url:指定請求的地址
    • req.proto:表示客戶端發起請求的HTTP協議版本
    • req.http.header:表示對應請求中的http頭部信息
    • req.restarts:表示請求重啓的次數,默認最大值爲4
  • Varnish 在向後端主機請求時,可使用的公用變量以下所示:
    • beresp.request:指定請求的類型,例如GET、HEAD等
    • beresp.url:指定請求的地址
    • beresp.proto:表示客戶端發起請求的HTTP協議版本
    • beresp.http.header:表示對應請求中的http頭部信息
    • beresp.ttl:表示緩存的生存週期,也就是cache保留多長時間,單位是秒
  • 從cache或者後端主機獲取內容後,可使用的公用變量以下所示:
    • obj.status:返回內容的請求狀態代碼,例如200、30二、504等
    • obj.cacheable:返回的內容是否能夠緩存,也就是說,若是HTTP返回是200、20三、300、30一、30二、40四、410等,而且有非0的生存期,則能夠緩存
    • obj.valid:表示是不是有效的HTTP應答
    • obj.response:返回內容的請求狀態信息
    • obj.proto:返回內容的HTTP協議版本
    • obj.ttl:返回內容的生存週期,也就是緩存時間,單位是秒
    • obj.lastuse:返回上一次請求到如今的間隔時間,單位是秒
  • 對客戶端應答時,可使用的公用變量以下所示:
    • resp.status:返回客戶端的HTTP狀態代碼
    • resp.proto:返回客戶端的HTTP協議版本
    • resp.http.header:返回客戶端的HTTP頭部信息
    • resp.response:返回客戶端的HTTP狀態信息

  若是想要了解更多請查閱Varnish官方文檔 查看文檔

相關文章
相關標籤/搜索