WEB緩存控制機制與varnish簡介

  在說到緩存varnish前,我們首先來了解下對於web服務緩存到底是什麼?它有哪些特點,基礎原理是什麼?

  http是web應用協議,通常我們說的一次http事務,不外乎就是客戶端請求,服務端響應,通常我們是這樣去理解http一次事務的過程;其實對於web服務器來說,一個客戶端訪問服務端的某資源時,往往客戶端的請求沒有到達真正提供web服務的服務器上,就被響應了,這是為什麼呢?我們知道一個WEB站點在提供對外訪問的頁面上在一定時間內都不會發生變化,而對於這些不經常變化的資源,訪問又特別大的情況,如果所有客戶端的請求都到真正提供WEB服務的服務器上請求資源,可以想像,對於提供web服務的服務器所在網絡是需要一個巨大帶寬才能夠足以支撐並發很多用戶去訪問;所以我們的站點不應該也不能夠讓所有的客戶端直接訪問後端真正的web服務器;在現實生活中我們訪問某度的網站,感覺很快的樣子,其實這背後就是緩存的作用;那什麼是緩存呢?所謂緩存,對於http協議來說,就是把那些經常被訪問到的熱區資源,通過某種機制把它存放在離客戶端最近的地方,客戶端訪問該資源時,直接從緩存中響應即可,這樣的機制就是緩存;簡單講緩存就是把熱區資源放到離客戶端最近的地方,方便客戶端訪問時,直接從緩存的資源響應給客戶端,這樣一來就解決了,後端真正提供web服務的服務器所在網絡帶寬的問題,同時也加速了客戶端的訪問請求;對於http協議來說,程序的運行具有時間局部性和空間局部性特徵,所謂時間局部性特徵就是一個數據被訪問過之後,可能很快會被第二次訪問到;空間局部性指的是一個數據被訪問時,其周邊的數據也有可能別訪問到;如果我們把這些很受歡迎的資源(可能被多次訪問到的資源)和其周圍的一些資源存起來,放到離客戶端最近的地方,這樣一來,大多數的客戶端訪問我們的站點就會被緩存響應,能夠真正到達後端真正提供web服務的服務器上的客戶端請求就大大減少;這就是緩存的作用,它一方面是減少後端服務器的壓力,同時加速了客戶端的訪問;通常情況下緩存是有生命周期的,什麼意思呢?就是說緩存不是說一直存放在哪裡不變的,它是有時效性的,如果一個緩存項過期了,那麼該緩存就會被識別為失效的緩存項,對於失效的緩存通常會有一個緩存管理機制處理該緩存項,最常見的處理方式就是把失效的緩存項直接清理出去,除此之外在http1.1協議中,對於這種失效的緩存來講,通常客戶端請求該資源時,一看緩存時間過期了,那麼此時緩存服務器會向後端或上游服務器發送一個條件式請求問下真正的服務器,說“我這裡的緩存失效了,請問你那裡的資源的時間戳改變了嗎?如果沒有改變我就用我這裡的緩存響應給客戶端咯”,如果後端服務器用304響應緩存服務器,就說明後端服務器上對於該資源在時間戳上沒有發生改變,緩存服務器收到304的響應後,它會把自己的緩存生命周期往後延長一段時間,同時把客戶端的請求從該緩存中響應給客戶端;如果後端服務器響應的是200的狀態碼,緩存服務器收到該響應,會把後端服務器的響應資源緩存到自己本地,然後在從緩存中響應客戶端請求;這就是所謂的條件是請求;對於緩存來說,緩存的命中至關重要,所謂命中就表示客戶端訪問某資源,能夠從緩存中響應,那麼我們就說該次http事務被緩存命中;一個緩存如果命中率極低,那麼我們就會認為該緩存緩存的意義不大,所以一個緩存項緩存是否有意義,關鍵還要看它的命中率如何;命中率有兩種,第一種是基於頁面數量來進行衡量的,我們叫做頁面命中率;一個是基於頁面的體積進行衡量的,我們叫這種為位元組命中率;同時緩存又分私有緩存和公有緩存,所謂私有緩存就表示某客戶端的私有數據,通常該緩存只能被某一客戶端命中,所以通常情況下,這種私有緩存是在瀏覽器上存儲;而公有緩存是指沒有私有屬性的緩存,對於所有客戶端都可用,我們這裡通常說的緩存都是指這種公有緩存;

  了解了緩存的大概介紹,我們再來看看在http協議中緩存是如何被控制的;http1.0中的緩存控制機制吧!在http1.0協議中,緩存控制機制是通過後端服務器的響應首部expires給定一個到期時間,來明確告訴客戶端該資源在給定的這個時間內都是有效的;我們知道對於一個站點來說,它可能是全球的,這樣一來如果通過絕對時間來控制緩存,很明顯,如果客戶端的時間和服務端的時間有誤差,很有可能存在一部分客戶端訪問某資源時,得到服務端響應expires首部的時間在客戶端就是失效的。這樣一來對於這部分客戶端很明顯緩存對於他們是無緣的;所以在http1.0中這種絕對時間控制機制對於那種全球性的網站是不太適合的;為了解決這樣的困境,在http1.1協議中引入了相對時間控制機制,這種緩存控制機制是利用響應報文首部的cache-control特定值maxage或s-maxage的值控制的;什麼意思呢?就是客戶端請求某一資源時,服務端會明確告訴客戶端該資源可緩存,緩存的時間是多長時間,這樣一來就不存在客戶端系統時間和服務器時間不兼容或者有誤差的情況導致緩存天前或延後失效的問題;maxage指定的時間適用於那些公有緩存和私有緩存,而s-maxage只適用於公有緩存;在如今普片http1.1或2.0協議中為了兼容http1.0,通常這兩種時間控制機制都是共同存在的;我們可以隨便打開一網站來看看這兩個首部;

   提示:以上響應首部就是告訴瀏覽器下次請求該資源時,如果在expires首部給定的時間之前訪問該資源,都會從緩存中直接響應;如果我們客戶端時間和服務端的時間有誤差或不兼容,那麼在本次請求的後7776000秒之前,如果該資源再次被訪問都從緩存中直接響應;也就說在本次訪問到下次訪問的時間如果小於7776000秒就直接從緩存中響應;

  在http1.1協議中除了上面基於時間的緩存控制機制外,還引入了條件式請求的機制來判斷緩存有效方式,在上面我們已經大概闡述過條件式請求的邏輯;這裡再大概的描述下,所謂條件式請求就是客戶端每訪問一次服務端的資源,都會去問真正的服務器該資源的時間戳改變了沒有,如果沒有改變服務端就用304響應告訴客戶端沒有變,從而客戶端的請求就會被緩存直接響應;如果服務端上的對應資源發生了變化,那麼服務端會以200的響應碼告訴客戶端資源的時間戳發生改變了,同時把改變後的資源發送給客戶端,客戶端收到服務端的響應後,它會把新的資源緩存起來,然後再用新的資源響應客戶端;其實對於這種基於時間戳的形式來判斷資源是否改變,其實是不是很精準的;比如服務器上的某一資源在一秒鐘變化了8次,如果基於時間戳來判斷資源是否改變(精確到秒),很可能服務端會告訴客戶端資源沒變,其實服務端上的資源改變了,為了解決這種問題,在http1.1還引進了擴展標記的控制機制,這種控制機制和基於時間戳控制機制流程都是一樣的,只是在基於時間戳控制是以資源的時間戳來判斷該資源是否發生改變,而擴展標記控制機制是以資源的校驗碼來判別資源是否發生改變,很明顯後者對於資源是否發生改變的控制更加精準,當同時對服務端的CPU消耗也就更多一點,因為每一次響應都要把對應資源校驗下,拿到其校驗碼進行和客戶端的校驗碼對比;在http1.1中基於時間戳的條件是請求表現形式在客戶端請求首部if-modified-since,表示告訴服務自從某某時間後服務端對應資源發生變化了嗎,響應報文中以last-modified首部來告訴客戶端服務器上對應資源的最近修改時間戳,如果響應報文中的時間戳比請求報文中的時間戳新,那麼客戶端就會收到200的響應碼,如果響應報文中的時間戳小於或等於請求報文中的時間戳,那麼客戶端就會收到304的響應碼,意思就是指資源沒有發生變化,該緩存可以繼續使用;通常客戶端請求某資源服務端會用last-modified首部告訴客戶端資源的時間戳,以便判斷資源是否發生改變;基於擴展標記的方式在http1.1協議中的表現形式就是在請求報文首部以if-none-match來告訴服務端客戶端請求資源的校驗,響應報文首部用Etag首部告訴客戶端對應資源的校驗碼,如果兩者相等表示資源沒有發生改變,對應響應碼就是304,如果兩者不等,表示資源發生了改變,響應碼就是200;擴展標記機制通過對比校驗碼的形式來判斷資源是否發生改變;

   提示:從上面的響應報文和請求報文首部的值來對比,很容易判斷該資源沒有發生改變;通常情況下我們只是基於某一種機制來控制緩存就好,如果你想精度高一點,我們直接使用擴展標記機制即可,如果精度沒有那麼高,可以使用基於資源時間戳的機制來控制就好;

  了解了http協議中的緩存控制機制,我們這裡在着重說一下cache-control在請求報文中的值,和響應報文中的值代表意義(如何處理緩存內容)

  http1.1協議中請求首部cache-control的值如果是“no-cache”即表示告訴緩存服務器本次請求不要用緩存里的數據響應;

   提示:以上請求就表示告訴緩存服務器不要用緩存響應本次請求,所以我們能看到本次請求的狀態碼是200而非304;通常我們使用瀏覽器對資源強刷,請求報文中cache-control的值就是”no-cache”

  當然對於請求報文中cache-control的值還有多,但是用的比較少,這裡就不過多強調其他值的意思,我們着中來說說http協議1.1中,響應首部cache-control的值;在響應報文首部中cache-control的值主要是告訴緩存服務器或緩存系統怎麼處理緩存數據;比如在響應報文首部cache-control的值是“public”就表示該數據可以被公用緩存系統或服務器緩存,對於私有緩存服務器或系統當然也是可以緩存該數據;如果響應首部cache-control的值是“private”就表示告訴緩存系統該數據只能用於私有緩存系統中,公有緩存系統不能緩存該數據;如果是“no-cache”就表示告訴緩存系統該數據可緩存,當在響應給客戶端之前需要做條件式請求進行緩存有效性驗證;“no-store”表示告訴緩存系統該資源或數據不允許存儲在緩存中;“must-revalidate”這個意思同“no-cache”一樣表示可緩存,但響應必須做條件式請求驗證緩存的有效性;“max-age”表示告訴緩存系統該資源或數據的緩存時長是多少秒;“s-maxage”表示告訴緩存系統該資源在公有緩存系統上的生命時長(該值表示指定公有緩存系統或者代理緩存服務器上的緩存時長);

   在了解了http1.1協議中是如何控制緩存,接下來我們聊一聊針對web服務緩存應用的開源實現;對於web應用緩存系統開源實現有兩款軟件squid和varnish,這兩款軟件有點像apache httpd 和nginx 關係,他們分別是不同年代的產品,對於varnish是來講,可以說它是squid的替代品,因為varnish相比之下要比squid性能更穩定,響應速度更快,支持的並發連接更多等等;

  varnish的官方站點是http://www.varnish-cache.org,它和其他主流開源產品類似有community和enterprise兩個版本,前者免費,後者你懂的;varnish它是一款高性能的http緩存服務器,其程序架構如下

   提示:varnish程序架構如上圖,主要由四部分組成,配置接口VCL、manager進程、cache進程和共享內存日誌;其中manager進程主要是管控cache進程的,配置文件的編譯並加載,而cache進程包含多種類型的線程,每個線程處理一類事務,如command line處理命令行命令的,log/stats記錄日誌和統計數據,accept用於接收請求,storage/hashing用於管理存儲和緩存中的鍵的,backend communication用於與後端服務器進行通信用的,object expiry用於管理緩存項和過期時間的;對於varnish的日誌,為了更高效的提供服務,它的日誌是記錄在共享內存的,而共享內存的大小是固定的,日誌不會越記越大,它採取的是輪轉機制,日誌記錄滿了就覆蓋最前邊的日誌,是得日誌最大只能佔用給定大小的空間;這也是varnish的日誌管理的獨特地方,如果我們需要保存日誌,需要周期性的去共享內存中把日誌讀出來保存到文件中即可;當然用於日誌管理的工具有很多,varnish提供了五種工具,分別用於管理日誌的,其中varnishlog是把共享內存中的日誌記錄成varnish原始格式的日誌,varnishncsa是把共享內存中的日誌記錄成http combined格式的日誌,varnishtop就是用來對共享內存中的日誌排序用到的工具,varnishhist用於查看日誌歷史信息,varnishstat用於統計數據的;varnish的配置文件有兩個,一個是定義varnish程序自身的工作特性(/etc/varnish/varnish.params),一個是定義緩存工作特性(/etc/varnish/default.vcl),通常情況下配置個child/cache線程的緩存策略,需要用專用的配置語言vcl(varnish configuration lanuage),通常這種配置文件在定義好後,不能直接使用,需要用vcl 編譯器將其編譯成C代碼,然後通過c編譯器編譯編譯成共享對象,提供給子進程中的線程鏈接加載使用;

  varnish安裝

[root@test_node1-centos7 ~]# yum install -y varnish

  提示:安裝可以是編譯也可以是yum安裝,如果是yum安裝,需要提前把epel倉庫配好,varnish包它來源epel倉庫;

  varnish的程序環境說明

[root@test_node1-centos7 ~]# rpm -ql varnish  /etc/logrotate.d/varnish  /etc/varnish  /etc/varnish/default.vcl  /etc/varnish/varnish.params  /run/varnish.pid  /usr/bin/varnishadm  /usr/bin/varnishhist  /usr/bin/varnishlog  /usr/bin/varnishncsa  /usr/bin/varnishstat  /usr/bin/varnishtest  /usr/bin/varnishtop  /usr/lib/systemd/system/varnish.service  /usr/lib/systemd/system/varnishlog.service  /usr/lib/systemd/system/varnishncsa.service  /usr/sbin/varnish_reload_vcl  /usr/sbin/varnishd  ……省略部分內容……  

  提示:/etc/varnish/varnish.params: 配置varnish服務進程的工作特性,例如監聽的地址和端口,緩存機制;/etc/varnish/default.vcl:配置各Child/Cache線程的緩存策略;/usr/sbin/varnishd是主程序,/usr/bin/varnishadm是命令行管理工具;/usr/bin/varnishhist、varnishlog、varnishncsa、varnishstat、varnishtop都是共享內存日誌交互工具;/usr/bin/varnishtest是測試工具程序;/usr/sbin/varnish_reload_vcl是vcl配置文件重載程序;/usr/lib/systemd/system/varnish.service是varnish服務unit文件;/usr/lib/systemd/system/varnishlog.service和varnishncsa.service是日誌持久服務unit文件;

   以上就是http協議中的緩存控制機制說明和varnish程序架構和環境的簡單說明,後續本人會持續更新varnish系列使用說明;有興趣的朋友可以關注、評論,共同探討和學習;