什麼是緩存,爲何要緩存 css
在客戶端和原始服務器端之間存在一個能夠本身構建響應報文的服務器,這個服務器一般就是緩存服務器.爲何要緩存服務器?在互聯網上傳輸數據(這裏指web瀏覽),數據傳輸一般有三個階段:第一階段:原始服務器到互聯網;第二階段:網絡間的層層路由;第三階段:網絡到請求數據的客戶端.爲了提升用戶體驗,加速用戶訪問原始服務器,能夠把熱點數據放在緩存服務器上,緩存服務器一般放在離用戶比較近的地方,如:cdn機房等,在同一個網域內客戶端請求相同的數據能夠直接從緩存服務器中取得,減小數據冗餘,用戶請求數據不用去原始服務器了,減小網絡間的路由時間和服務器的壓力.用戶請求的數據有多少是能夠從緩存服務器上取得的,取決於緩存的命中率;命中率一般又分爲文檔命中率和字節命中率(對於中等規模的web來講,40%左右的命中率就能夠了);緩存類型又分爲:私有緩存和公共緩存;用戶訪問互聯網的過程-->檢查私有緩存,有就返回數據,沒有就去請求二級代理,二級代理有就返回數據,沒有就請求一級代理,最後請求原始服務器;若是有多個二級代理或一級代理,而且多個二級代理能夠互相查找數據(需配置)還能夠向一級代理(父代理)查找數據,這個方式叫作內容路由,內容路由須要經過ICP(緩存路由協議)通訊;html
緩存處理的具體步驟:nginx
接受請求-->解析請求(代理功能)-->查詢緩存-->緩存內容的新鮮程度(非必須)-->構建響應報文(緩存服務器有數據)-->發送響應記錄日誌web
緩存內容的過時檢查方式正則表達式
響應首部:文檔過時機制:HTTP/1.0 Expires(過時時間:2014-05-08 19:00:00過時);HTTP/1.1 Cache-Control(max-age = 300s 300s過時)express
請求首部:條件式請求機制:根據時間戳:比較緩存服務器和原始服務器的數據時間戳是否一致(mtime:If-Modified-Since); 根據擴展標記:(If-None-Match):比較緩存服務器和原始服務器的數據擴展標記是否一致apache
結合機制:文檔過時機制+條件式請求機制編程
原始服務器或緩存服務器控制緩存的首部(響應首部)vim
max-age 控制私有緩存的過時時間 如:max-age=3600後端
s-maxage 控制公共緩存,同上
no-store :控制位,表示不能緩存,只要後端服務器的報文首部有no-store首部,緩存服務器就不能緩存,這是遵循了緩存協議的控制規定
no-cache:能緩存,不能直接使用此緩存對象,意思是緩存對象在使用以前必須作新鮮度驗證
must-revalidate:必須進行新鮮度驗證.同上
private : 用戶的私有數據
public: 用戶的公開數據
vanish
varnish是一個輕量級的web的緩存服務器,他對nginx或apache作緩存,單個varnish的鏈接請求併發量大體在5000個左右,因此在大規模的站點中,可能仍是有squie主導.在中小企業的規模中作代理緩存時,varnish比較常見,varnish不支持使用過大的內存空間.
varnish主要運行兩個進程:Management進程和Child進程(也叫Cache進程)。
Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,若是在指定的時長內未獲得Child進程的迴應,Management將會重啓此Child進程。
Child進程包含多種類型的線程,常見的如:
Acceptor線程:接收新的鏈接請求並響應;
Worker線程:child進程會爲每一個會話啓動一個worker線程,所以,在高併發的場景中可能會出現數百個worker線程甚至更多;
Expiry線程:從緩存中清理過時內容;
Varnish依賴「工做區(workspace)」以下降線程在申請或修改內存時出現競爭的可能性。在varnish內部有多種不一樣的工做區,其中最關鍵的當屬用於管理會話數據的session工做區。
如上圖:
Management功能
Command line 提供命令行接口
Chile process mgmt 管理子進程
Initialisation 配置應用初始化
Child/cache
Command line 命令行接口
Storage/hashing 存儲hash功能
Log/stats 日誌
Accept 接受並處理用戶請求
Backend communication 若是本地沒有緩存請求的內容,就本身構建請求報文至原始服務器
Worker threads 負責處理用戶請求
Object expiry 清楚過時緩存對象
varnish管理接口
CLI interface 命令行接口
Telnet interface telnet接口,爲了安全,目前都禁用了
Web interface 基於web界面的監控
Log file 默認狀況下varnish的日誌是存在內存中的,想要存在磁盤中,須要本身配置
vamishlog 日誌格式
vamishstat 獲取當前狀態信息
vamishhist 歷史性信息
vamishtop 監控服務狀態的
vamishncsa 日誌格式
VCL complier VCL編譯器
Varnish Configuration Language (VCL)是varnish配置緩存策略的工具,它是一種基於「域」(domain specific)的簡單編程語言,它支持有限的算術運算和邏輯運算操做、容許使用正則表達式進行字符串匹配、容許用戶使用set自定義變量、支持if判斷語句,也有內置的函數和變量等。使用VCL編寫的緩存策略一般保存至.vcl文件中,其須要編譯成二進制的格式後才能由varnish調用。事實上,整個緩存策略就是由幾個特定的子例程如vcl_recv、vcl_fetch等組成,它們分別在不一樣的位置(或時間)執行,若是沒有事先爲某個位置自定義子例程,varnish將會執行默認的定義。
VCL策略在啓用前,會由management進程將其轉換爲C代碼,然後再由gcc編譯器將C代碼編譯成二進制程序。編譯完成後,management負責將其鏈接至varnish實例,即child進程。正是因爲編譯工做在child進程以外完成,它避免了裝載錯誤格式VCL的風險。所以,varnish修改配置的開銷很是小,其能夠同時保有幾份尚在引用的舊版本配置,也可以讓新的配置即刻生效。編譯後的舊版本配置一般在varnish重啓時纔會被丟棄,若是須要手動清理,則可使用varnishadm的vcl.discard命令完成。
用戶請求數據:
若是請求的數據是緩存服務器不認識的,直接交給pipe;
若是是不可緩存的數據,直接交給pass,pass交給fetdh,由fetch構建請求報文交給後端服務器,後端服務器響應報文後,fetch看該報文是否可緩存,若是可緩存就先緩存而後返回給deliver.若是不能緩存就直接交給deliver
若是是可緩存數據,先查看hash表,若是hash表中有數據,則命中(hit),而後由deliver返回給客戶端
若是是可緩存數據,先查看hash表,若是hash表中沒有數據,則不命中(miss),miss交給fetch,fetch向後端服務器請求數據
從上面能夠知道
緩存服務器的狀態引擎有:vcl_recv,vcl_pass,vcl_hash,vcl_pipe,vcl_hit,vcl_miss,vcl_fetch,vcl_deliver,每個狀態的下一步如何處理由return決定,在vcl_recv階段,return(pipe)就交給vcl_pipe,return(lookup)就交給vcl_hit或vcl_miss
VCL的內置函數
VCL提供了幾個函數來實現字符串的修改,添加bans,重啓VCL狀態引擎以及將控制權轉回Varnish等。
regsub(str,regex,sub) : 將str中的內容,可以被regex匹配到的替換成sub,只替換第一個
regsuball(str,regex,sub):這兩個用於基於正則表達式搜索指定的字符串並將其替換爲指定的字符串;但regsuball()能夠將str中可以被regex匹配到的字符串通通替換爲sub,regsub()只替換一次;
ban(expression):
ban_url(regex):Bans全部其URL可以由regex匹配的緩存對象;
purge:從緩存中挑選出某對象以及其相關變種一併刪除,這能夠經過HTTP協議的PURGE方法完成;
hash_data(str):
return():當某VCL域運行結束時將控制權返回給Varnish,並指示Varnish如何進行後續的動做;其能夠返回的指令包括:lookup、pass、pipe、hit_for_pass、fetch、deliver和hash等;但某特定域可能僅能返回某些特定的指令,而非前面列出的所有指令;
return(restart):從新運行整個VCL,即從新從vcl_recv開始進行處理;每一次重啓都會增長req.restarts變量中的值,而max_restarts參數則用於限定最大重啓次數。
vcl_recv子例程(狀態引擎)
cl_recv是在Varnish完成對請求報文的解碼爲基本數據結構後第一個要執行的子例程,它一般有四個主要用途:
(1)修改客戶端數據以減小緩存對象差別性;好比刪除URL中的www.等字符;
(2)基於客戶端數據選用緩存策略;好比僅緩存特定的URL請求、不緩存POST請求等;
(3)爲某web應用程序執行URL重寫規則;
(4)挑選合適的後端Web服務器;
可使用下面的終止語句,即經過return()向Varnish返回的指示操做:
pass:繞過緩存,即不從緩存中查詢內容或不將內容存儲至緩存中;
pipe:不對客戶端進行檢查或作出任何操做,而是在客戶端與後端服務器之間創建專用「管道」,並直接將數據在兩者之間進行傳送;此時,keep-alive鏈接中後續傳送的數據也都將經過此管道進行直接傳送,並不會出如今任何日誌中;
lookup:在緩存中查找用戶請求的對象,若是緩存中沒有其請求的對象,後續操做極可能會將其請求的對象進行緩存;
error:由Varnish本身合成一個響應報文,通常是響應一個錯誤類信息、重定向類信息或負載均衡器返回的後端web服務器健康狀態檢查類信息;
vcl_recv也能夠經過精巧的策略完成必定意義上的安全功能,以將某些特定的***扼殺於搖籃中。同時,它也能夠檢查出一些拼寫類的錯誤並將其進行修正等。
Varnish默認的vcl_recv專門設計用來實現安全的緩存策略,它主要完成兩種功能:
(1)僅處理能夠識別的HTTP方法,而且只緩存GET和HEAD方法;
(2)不緩存任何用戶特有的數據;
安全起見,通常在自定義的vcl_recv中不要使用return()終止語句,而是再由默認vcl_recv進行處理,並由其作出相應的處理決策。
vcl_fetch子例程(狀態引擎)
如前面所述,相對於vcl_recv是根據客戶端的請求做出緩存決策來講,vcl_fetch則是根據服務器端的響應做出緩存決策。在任何VCL狀態引擎中返回的pass操做都將由vcl_fetch進行後續處理。vcl_fetch中有許多可用的內置變量,好比最經常使用的用於定義某對象緩存時長的beresp.ttl變量。經過return()返回給varnish的操做指示有:
(1)deliver:緩存此對象,並將其發送給客戶端(經由vcl_deliver);
(2)hit_for_pass:不緩存此對象,但能夠致使後續對此對象的請求直接送達到vcl_pass進行處理;
(3)restart:重啓整個VCL,並增長重啓計數;超出max_restarts限定的最大重啓次數後將會返回錯誤信息;
(4)error code [reason]:返回指定的錯誤代碼給客戶端並丟棄此請求;
默認的vcl_fetch放棄了緩存任何使用了Set-Cookie首部的響應。
varnish的後端存儲
varnish支持多種不一樣類型的後端存儲,這能夠在varnishd啓動時使用-s選項指定。後端存儲的類型包括:
(1)file:使用特定的文件存儲所有的緩存數據,並經過操做系統的mmap()系統調用將整個緩存文件映射至內存區域(若是條件容許);
(2)mal loc:使用malloc()庫調用在varnish啓動時向操做系統申請指定大小的內存空間以存儲緩存對象;
(3)persistent(experimental):與file的功能相同,但能夠持久存儲數據(即重啓varnish數據時不會被清除);仍處於測試期;
varnish沒法追蹤某緩存對象是否存入了緩存文件,從而也就無從得知磁盤上的緩存文件是否可用,所以,file存儲方法在varnish中止或重啓時會清除數據。而persistent方法的出現對此有了一個彌補,但persistent仍處於測試階段,例如目前尚沒法有效處理要緩存對象整體大小超出緩存空間的狀況,因此,其僅適用於有着巨大緩存空間的場景。
選擇使用合適的存儲方式有助於提高系統性,從經驗的角度來看,建議在內存空間足以存儲全部的緩存對象時使用malloc的方法,反之,file存儲將有着更好的性能的表現。然而,須要注意的是,varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,通常說來,其須要爲每一個緩存對象多使用差很少1K左右的存儲空間,這意味着,對於100萬個緩存對象的場景來講,其使用的緩存空間將超出指定大小1G左右。另外,爲了保存數據結構等,varnish自身也會佔去不小的內存空間。
爲varnishd指定使用的緩存類型時,-s選項可接受的參數格式以下:
malloc[,size] 或
file[,path[,size[,granularity]]] 或
persistent,path,size {experimental}
file中的granularity用於設定緩存空間分配單位,默認單位是字節,全部其它的大小都會被圓整。
注:爲了增大緩存命中率,要把請求中沒必要要cookie的都移除,響應中沒必要要setcookie都移除要移,除用戶請求中的cookie,要在vcl_recv中進行,要移除set_cookie,要在vcl_fetch中進行
1.安裝varnish
rpm -ivh varnish-3.0.4-1.el6.x86_64.rpm varnish-docs-3.0.4-1.el6.x86_64.rpm varnish-libs-3.0.4-1.el6.x86_64.rpm
rpm -ql varnish
規劃:varnish服務器
公網IP:192.168.1.107
內網IP:172.16.21.1
後端web服務器,web1:172.16.21.2
後端web服務器,web2:172.16.21.3
2.配置varnish
vim /etc/sysconfig/varnish
VARNISH_LISTEN_PORT=80
VARNISH_STORAGE="malloc,100M"
注:修改配置文件後都要從新加載配置文件
vanishadmin -S /etc/varnish/secreet -T 172.0.0.1:6082
varnish>vcl.reload test1 default.vcl
3.定義後端服務器
vim /etc/varnish/default.vcl
backend default {
.host = "172.16.21.3";
.port = "80";
}
4.啓動varnish,訪問192.168.1.107
service varnish start
5.使用varnish的客戶端管理工具
vanishadmin -S /etc/varnish/secreet -T 172.0.0.1:6082
varnish>help
200
help [command]
ping [timestamp]
auth response
quit
banner
status
start
stop
vcl.load <configname> <filename>
vcl.inline <configname> <quoted_VCLstring>
vcl.use <configname>
vcl.discard <configname>
vcl.list
vcl.show <configname>
param.show [-l] [<param>]
param.set <param> <value>
panic.show
panic.clear
storage.list
backend.list
backend.set_health matcher state
ban.url <regexp>
ban <field> <operator> <arg> [&& <field> <oper> <arg>]...
ban.list
6.查看緩存是否命中,而且從哪裏命中
sub vcl_deliver {
if (obj.hits > 0){
set resp.http.X-Cache = "HIT" + server.ip; resp表示響應,http首部,名稱X-Cache
} else {
set resp.http.X-Cache = "MISS";
}
}
7.對指定網頁不作緩存,如test.html
sub vcl_recv {
if (req.url ~ "test.html"){
return(pass);
}
}
8.自定義緩存時長
sub vcl_fetch {
if (req.url ~ "\.(jpg|png|gif|jpeg)$") {
set beresp.ttl = 7200s;
}
if (req.url ~ "\.(html|css|js)$") {
set beresp.ttl = 1200s;
}
}
9.清除緩存
acl purger {
"127.0.0.1";
"192.168.0.0"/16;
}
sub vcl_recv {
if (req.request == "QC") {
if (!client.ip ~ purger) {
error 405 "error";
}
return(lookup);
}
}
sub vcl_hit {
if (req.request == "QC"){
purge;
error 200 "sesscee";
}
}
sub vcl_miss {
if (req.request == "QC"){
error 404 "error miss";
}
}
sub vcl_pass {
if (req.request == "QC"){
error 502 "502";
}
10.後端主機健康狀態檢測
backend web2{
.host = "www.a.com";
.probe = {
.url = "/.test.html"; 沒有指定具體的內容表示請求到此網頁就表明後端服務器正常
.interval = 1s;
.window = 5; 一共測試5次
.threshold = 2; 5次中有兩次錯誤就認爲是失敗的
}
}
11.多臺後端主機
backend web1 {
.host = "backweb1.magedu.com";
.port = "80";
}
director webservers random { random:調度方法,加權隨機
.retries = 5; 重試次數,每一個主機健康狀態檢測的重試次數
{
.backend = web1; 後端real server
.weight = 2; 權重
}
{
.backend = {
.host = "backweb2.magedu.com";
.port = "80";
}
.weight = 3;
}
}
backend web1 {
.host = "172.16.21.2"
.port = "80";
}
backend web2 {
.host = "172.16.21.3";
.weight = "80";
}
director webserver random {
{
.backend = web1;
.weight = 2;
}
{
.backend = web2;
.weight = 3;
}
}
sub vcl_recv {
set req.backend = webser; 上面設置了必定要引用,不然會報錯
}
12.動靜分離雛形
backend web1 {
.host = "172.16.21.2";
.port = "80" ;
}
backend web2 {
.host = "172.16.21.3";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "\.(html|css|js)$"){
set req.backend = web1;
}else{
set req.backend = web2;
}
}
13.varnishadm命令
vanishadm
varnish> storage.list
varnish> backend.list
varnish> ban.url ^/shop/.* 清理緩存,ban.url後面跟一個正則表達式,慎用,任何清理緩存的操做都要慎用
14.varnishstats命令
varnishstat --help
varnishstat: invalid option -- '-'
usage: varnishstat [-1lV] [-f field_list] [-n varnish_name] [-w delay]
-1 # Print the statistics to stdout.
-f field_list # Comma separated list of fields to display.
# If it starts with '^' it is used as an exclusion list
-l # Lists the available fields to use with the -f option
-n varnish_name # The varnishd instance to get logs from
-V # Display the version number and exit
-w delay # Wait delay seconds between updates. Default is 1 second. Can also be be used with -1, -x or -j for repeated output.
-x # Print statistics to stdout as XML.
-j # Print statistics to stdout as JSON.
14.把內存中的日誌保存到磁盤中
service varnishlog start
tail /var/log/varnish/varnish.log
15.防止盜鏈
if (req.http.referer) {
if ( !(req.http.referer ~ "http://.*a\.com"
|| req.http.referer ~ "http://.*b\.com\.cn"
|| req.http.referer ~ "http://.*c\.cn"
|| req.http.referer ~ "http://.*google\.com"
|| req.http.referer ~ "http://.*yahoo\.cn"
|| req.http.referer ~ "http://.*google\.cn"
)) {
set req.http.host = "img.test.com";
set req.url = "/images/default.jpg";
}
}
else { lookup; }