Linux進(jìn)階之Varnish 4.0 詳解

簡介:

Varnish 是一款高性能且開源的反向代理服務(wù)器和 HTTP 加速器饶碘,其采用全新的軟件體系機(jī)構(gòu)目尖,和現(xiàn)在的硬件體系緊密配合,與傳統(tǒng)的 squid 相比扎运,varnish 具有性能更高瑟曲、速度更快饮戳、管理更加方便等諸多優(yōu)點(diǎn);

Varnish與Squid的對比

相同點(diǎn)

都是一個(gè)反向代理服務(wù)器洞拨;
都是開源軟件扯罐;

Varnish的優(yōu)勢:

Varnish的穩(wěn)定性很高,兩者在完成相同負(fù)荷的工作時(shí)烦衣,Squid服務(wù)器發(fā)生故障的幾率要高于Varnish歹河,因?yàn)槭褂肧quid要經(jīng)常重啟;
Varnish訪問速度更快花吟,因?yàn)椴捎昧恕癡isual Page Cache”技術(shù)秸歧,所有緩存數(shù)據(jù)都直接從內(nèi)存讀取,而squid是從硬盤讀取示辈,因而Varnish在訪問速度方面會更快寥茫;
Varnish可以支持更多的并發(fā)連接,因?yàn)閂arnish的TCP連接釋放要比Squid快矾麻,因而在高并發(fā)連接情況下可以支持更多TCP連接纱耻;
Varnish可以通過管理端口,使用正則表達(dá)式批量的清除部分緩存险耀,而Squid是做不到的弄喘;
squid屬于是單進(jìn)程使用單核CPU,但Varnish是通過fork形式打開多進(jìn)程來做處理甩牺,所以可以合理的使用所有核來處理相應(yīng)的請求蘑志;

Varnish的劣勢

varnish進(jìn)程一旦Hang、Crash或者重啟贬派,緩存數(shù)據(jù)都會從內(nèi)存中完全釋放急但,此時(shí)所有請求都會發(fā)送到后端服務(wù)器,在高并發(fā)情況下搞乏,會給后端服務(wù)器造成很大壓力波桩;
在varnish使用中如果單個(gè)url的請求通過HA/F5等負(fù)載均衡,則每次請求落在不同的varnish服務(wù)器中请敦,造成請求都會被穿透到后端镐躲;而且同樣的請求在多臺服務(wù)器上緩存,也會造成varnish的緩存的資源浪費(fèi)侍筛,造成性能下降萤皂;

Varnish劣勢的解決方案

針對劣勢一:在訪問量很大的情況下推薦使用varnish的內(nèi)存緩存方式啟動,而且后面需要跟多臺squid服務(wù)器匣椰。主要為了防止前面的varnish服 務(wù)裆熙、服務(wù)器被重啟的情況下,大量請求穿透varnish,這樣squid可以就擔(dān)當(dāng)?shù)诙覥ACHE弛车,而且也彌補(bǔ)了varnish緩存在內(nèi)存中重啟都會釋 放的問題齐媒;
針對劣勢二:可以在負(fù)載均衡上做url哈希,讓單個(gè)url請求固定請求到一臺varnish服務(wù)器上;

Varnish 進(jìn)程的工作模式:

(1)Varnish 啟動或有2個(gè)進(jìn)程 master(management) 進(jìn)程和 child(worker) 進(jìn)程纷跛。master 讀入存儲配置命令,進(jìn)行初始化邀杏,然后 fork贫奠,監(jiān)控 child。child 則分配線程進(jìn)行 cache 工作望蜡,child 還會做管理線程和生成很多 worker 線程唤崭。
(2)child 進(jìn)程主線程初始化過程中,將存儲大文件整個(gè)加載到內(nèi)存中脖律,如果該文件超出系統(tǒng)的虛擬內(nèi)存谢肾,則會減少原來配置 mmap 大小,然后繼續(xù)加載小泉,這時(shí)候創(chuàng)建并初始化空閑存儲結(jié)構(gòu)體芦疏,放在存儲管理的 struct 中,等待分配微姊。
接著 Varnish 某個(gè)負(fù)責(zé)接受新 http 連接的線程開始等待用戶酸茴,如果有新的 http 連接,但是這個(gè)線程只負(fù)責(zé)接收兢交,然后喚醒等待線程池中的 work 線程薪捍,進(jìn)行請求處理。
worker 線程讀入 uri 后配喳,將會查找已有的 object酪穿,命中直接返回,沒有命中晴裹,則會從后端服務(wù)器中取出來被济,放到緩存中。如果緩存已滿息拜,會根據(jù) LRU 算法溉潭,釋放舊的 object。對于釋放緩存少欺,有一個(gè)超時(shí)線程會檢測緩存中所有 object 的生命周期喳瓣,如果緩存過期 (ttl),則刪除赞别,釋放相應(yīng)的存儲內(nèi)存畏陕。

Child進(jìn)程特點(diǎn):

Child 進(jìn)程分配若干線程進(jìn)行工作,主要包括一些管理線程和很多 worker 線程仿滔,可分為:
(1)Accept線程:接受請求惠毁,將請求掛在overflow隊(duì)列上犹芹;
(2)Work線程:有多個(gè),負(fù)責(zé)從overflow隊(duì)列上摘除請求鞠绰,對請求進(jìn)行處理腰埂,直到完成,然后處理下一個(gè)請求蜈膨;
(3)Epoll線程:一個(gè)請求處理稱為一個(gè)session屿笼,在session周期內(nèi),處理完請求后翁巍,會交給Epoll處理驴一,監(jiān)聽是否還有事件發(fā)生;
(5)Expire線程:對于緩存的object灶壶,根據(jù)過期時(shí)間肝断,組織成二叉堆,該線程周期檢查該堆的根驰凛,處理過期的文件胸懈,對過期的數(shù)據(jù)進(jìn)行刪除或重取操作;

Varnish 處理 HTTP 請求的過程如下


1.Receive 狀態(tài)(vcl_recv):也就是請求處理的入口狀態(tài)洒嗤,根據(jù) VCL 規(guī)則判斷該請求應(yīng)該 pass(vcl_pass)或是 pipe(vcl_pipe)箫荡,還是進(jìn)入 lookup(本地查詢);

2.Lookup 狀態(tài):進(jìn)入該狀態(tài)后渔隶,會在 hash 表中查找數(shù)據(jù)羔挡,若找到,則進(jìn)入 hit(vcl_hit)狀態(tài)间唉,否則進(jìn)入 miss(vcl_miss)狀態(tài)绞灼;

3.Pass(vcl_pass)狀態(tài):在此狀態(tài)下,會直接進(jìn)入后端請求呈野,即進(jìn)入 fetch(vcl_fetch)狀態(tài)低矮;

4.Fetch(vcl_fetch)狀態(tài):在 fetch 狀態(tài)下,對請求進(jìn)行后端獲取被冒,發(fā)送請求军掂,獲得數(shù)據(jù),并根據(jù)設(shè)置進(jìn)行本地存儲昨悼;

5.Deliver(vcl_deliver)狀態(tài):將獲取到的數(shù)據(jù)發(fā)給客戶端蝗锥,然后完成本次請求;
注:Varnish4中在vcl_fetch部分略有出入率触,已獨(dú)立為vcl_backend_fetch和vcl_backend_response2個(gè)函數(shù)终议;

內(nèi)置函數(shù)(也叫子例程)

  • vcl_recv:用于接收和處理請求;當(dāng)請求到達(dá)并成功接收后被調(diào)用,通過判斷請求的數(shù)據(jù)來決定如何處理請求穴张;
  • vcl_pipe:此函數(shù)在進(jìn)入pipe模式時(shí)被調(diào)用细燎,用于將請求直接傳遞至后端主機(jī),并將后端響應(yīng)原樣返回客戶端皂甘;
  • vcl_pass:此函數(shù)在進(jìn)入pass模式時(shí)被調(diào)用玻驻,用于將請求直接傳遞至后端主機(jī),但后端主機(jī)的響應(yīng)并不緩存直接返回客戶端偿枕;
  • vcl_hit:在執(zhí)行 lookup 指令后击狮,在緩存中找到請求的內(nèi)容后將自動調(diào)用該函數(shù);
  • vcl_miss:在執(zhí)行 lookup 指令后益老,在緩存中沒有找到請求的內(nèi)容時(shí)自動調(diào)用該方法,此函數(shù)可用于判斷是否需要從后端服務(wù)器獲取內(nèi)容寸莫;
  • vcl_hash:在vcl_recv調(diào)用后為請求創(chuàng)建一個(gè)hash值時(shí)捺萌,調(diào)用此函數(shù);此hash值將作為varnish中搜索緩存對象的key膘茎;
  • vcl_purge:pruge操作執(zhí)行后調(diào)用此函數(shù)桃纯,可用于構(gòu)建一個(gè)響應(yīng);
  • vcl_deliver:將在緩存中找到請求的內(nèi)容發(fā)送給客戶端前調(diào)用此方法披坏;
  • vcl_backend_fetch:向后端主機(jī)發(fā)送請求前态坦,調(diào)用此函數(shù),可修改發(fā)往后端的請求棒拂;
  • vcl_backend_response:獲得后端主機(jī)的響應(yīng)后伞梯,可調(diào)用此函數(shù);
  • vcl_backend_error:當(dāng)從后端主機(jī)獲取源文件失敗時(shí)帚屉,調(diào)用此函數(shù)谜诫;
  • vcl_init:VCL加載時(shí)調(diào)用此函數(shù),經(jīng)常用于初始化varnish模塊(VMODs)
  • vcl_fini:當(dāng)所有請求都離開當(dāng)前VCL攻旦,且當(dāng)前VCL被棄用時(shí)喻旷,調(diào)用此函數(shù),經(jīng)常用于清理varnish模塊牢屋;

VCL中內(nèi)置公共變量

變量(也叫object)適用范圍



req:The request object且预,請求到達(dá)時(shí)可用的變量
bereq:The backend request object,向后端主機(jī)請求時(shí)可用的變量
beresp:The backend response object烙无,從后端主機(jī)獲取內(nèi)容時(shí)可用的變量
resp:The HTTP response object锋谐,對客戶端響應(yīng)時(shí)可用的變量
obj:存儲在內(nèi)存中時(shí)對象屬性相關(guān)的可用的變量

優(yōu)雅模式(Garce mode)

Varnish中的請求合并

  • 當(dāng)幾個(gè)客戶端請求同一個(gè)頁面的時(shí)候,varnish只發(fā)送一個(gè)請求到后端服務(wù)器皱炉,然后讓其他幾個(gè)請求掛起并等待返回結(jié)果怀估;獲得結(jié)果后,其它請求再復(fù)制后端的結(jié)果發(fā)送給客戶端;
    但如果同時(shí)有數(shù)以千計(jì)的請求多搀,那么這個(gè)等待隊(duì)列將變得龐大歧蕉,這將導(dǎo)致2類潛在問題:

  • 驚群問題(thundering herd problem)贼急,即突然釋放大量的線程去復(fù)制后端返回的結(jié)果珠洗,將導(dǎo)致負(fù)載急速上升;

  • 沒有用戶喜歡等待
    故為了解決這類問題咒锻,可以配置varnish在緩存對象因超時(shí)失效后再保留一段時(shí)間从藤,以給那些等待的請求返回過去的文件內(nèi)容(stale content)催跪,配置案例如下:

    sub vcl_recv {
    if (! req.backend.healthy) {
    set req.grace = 5m;
    } else {
    set req.grace = 15s;
    }
    }
    sub vcl_fetch {
    set beresp.grace = 30m;
    }
    以上配置表示varnish將會將失效的緩存對象再多保留30分鐘,此值等于最大的req.grace值即可夷野;而根據(jù)后端主機(jī)的健康狀況懊蒸,varnish可向前端請求分別提供5分鐘內(nèi)或15秒內(nèi)的過期內(nèi)容

安裝配置

安裝包下載地址:http://repo.varnish-cache.org/redhat/varnish-4.0/el6/

yum localinstall --nogpgcheck varnish-4.0.0-1.el6.x86_64.rpm varnish-libs-4.0.0-1.el6.x86_64.rpm varnish-docs-4.0.0-1.el6.x86_64.rpm
vim /etc/sysconfig/varnish # 編輯配置文件,修改如下項(xiàng)
VARNISH_STORAGE_SIZE=100M # 此值根據(jù)自身情況調(diào)整悯搔,測試環(huán)境可調(diào)低此值
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}" # Varnish 4中默認(rèn)使用malloc(即內(nèi)存)作為緩存對象存儲方式骑丸;
systemctl start varnish  # 啟動varnish,默認(rèn)外部請求的監(jiān)聽端口6081妒貌,管理端口6082通危,后端主機(jī)127.0.0.1:80
===========
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 # 登錄管理命令行
varnish> vcl.list                 # 列出所有的配置
varnish> vcl.load test1 test.vcl  # 加載編譯新配置,test1是配置名灌曙,test.vcl是配置文件
varnish> vcl.use test1            # 使用配置菊碟,需指定配置名,當(dāng)前使用的配置以最后一次vcl.use為準(zhǔn)
varnish> vcl.show test1           # 顯示配置內(nèi)容在刺,需指定配置名

實(shí)例解析

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.
# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;
import directors;
probe backend_healthcheck { # 創(chuàng)建健康監(jiān)測
    .url = /health.html;
    .window = 5;
    .threshold = 2;
    .interval = 3s;
}
backend web1 {    # 創(chuàng)建后端主機(jī)
    .host = "static1.lnmmp.com";
    .port = "80";
    .probe = backend_healthcheck;
}
backend web2 {
    .host = "static2.lnmmp.com";
    .port = "80";
    .probe = backend_healthcheck;
}
backend img1 {
    .host = "img1.lnmmp.com";
    .port = "80";
    .probe = backend_healthcheck;
}
backend img2 {
    .host = "img2.lnmmp.com";
    .port = "80";
    .probe = backend_healthcheck;
}
vcl_init {    # 創(chuàng)建后端主機(jī)組逆害,即directors
    new web_cluster = directors.random();
    web_cluster.add_backend(web1);
    web_cluster.add_backend(web2);
    new img_cluster = directors.random();
    img_cluster.add_backend(img1);
    img_cluster.add_backend(img2);
}
acl purgers {    # 定義可訪問來源IP
        "127.0.0.1";
        "192.168.0.0"/24;
}
sub vcl_recv {
    if (req.request == "GET" && req.http.cookie) {    # 帶cookie首部的GET請求也緩存
        return(hash);
}
    if (req.url ~ "test.html") {    # test.html文件禁止緩存
        return(pass);
    }
    if (req.request == "PURGE") {    # PURGE請求的處理
        if (!client.ip ~ purgers) {
            return(synth(405,"Method not allowed"));
        }
        return(hash);
    }
    if (req.http.X-Forward-For) {    # 為發(fā)往后端主機(jī)的請求添加X-Forward-For首部
        set req.http.X-Forward-For = req.http.X-Forward-For + "," + client.ip;
    } else {
        set req.http.X-Forward-For = client.ip;
    }
    if (req.http.host ~ "(?i)^(www.)?lnmmp.com$") {    # 根據(jù)不同的訪問域名,分發(fā)至不同的后端主機(jī)組
        set req.http.host = "www.lnmmp.com";
        set req.backend_hint = web_cluster.backend();
      } elsif (req.http.host ~ "(?i)^images.lnmmp.com$") {
            set req.backend_hint = img_cluster.backend();
      }
        return(hash);
    }
sub vcl_hit { # PURGE請求的處理
    if (req.request == "PURGE") {  
        purge;
        return(synth(200,"Purged"));
    }
}
sub vcl_miss {    # PURGE請求的處理
    if (req.request == "PURGE") {
        purge;
        return(synth(404,"Not in cache"));
    }
}
sub vcl_pass {    # PURGE請求的處理
    if (req.request == "PURGE") {
        return(synth(502,"PURGE on a passed object"));
    }
}
sub vcl_backend_response { # 自定義緩存文件的緩存時(shí)長增炭,即TTL值
    if (req.url ~ "\.(jpg|jpeg|gif|png)$") {
        set beresp.ttl = 7200s;
    }
    if (req.url ~ "\.(html|css|js)$") {
        set beresp.ttl = 1200s;
    }
    if (beresp.http.Set-Cookie) { # 定義帶Set-Cookie首部的后端響應(yīng)不緩存忍燥,直接返回給客戶端
        return(deliver);
    }
}
sub vcl_deliver {
    if (obj.hits > 0) {    # 為響應(yīng)添加X-Cache首部,顯示緩存是否命中
        set resp.http.X-Cache = "HIT from " + server.ip;
    } else {
        set resp.http.X-Cache = "MISS";
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隙姿,一起剝皮案震驚了整個(gè)濱河市梅垄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌输玷,老刑警劉巖队丝,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異欲鹏,居然都是意外死亡机久,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門赔嚎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膘盖,“玉大人胧弛,你說我怎么就攤上這事∠琅希” “怎么了结缚?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長软棺。 經(jīng)常有香客問我红竭,道長,這世上最難降的妖魔是什么喘落? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任茵宪,我火速辦了婚禮,結(jié)果婚禮上瘦棋,老公的妹妹穿的比我還像新娘稀火。我一直安慰自己,他們只是感情好赌朋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布憾股。 她就那樣靜靜地躺著,像睡著了一般箕慧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茴恰,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天颠焦,我揣著相機(jī)與錄音,去河邊找鬼往枣。 笑死伐庭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的分冈。 我是一名探鬼主播圾另,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雕沉!你這毒婦竟也來了集乔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坡椒,失蹤者是張志新(化名)和其女友劉穎扰路,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體倔叼,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汗唱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丈攒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哩罪。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡授霸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出际插,到底是詐尸還是另有隱情碘耳,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布腹鹉,位于F島的核電站藏畅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏功咒。R本人自食惡果不足惜愉阎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望力奋。 院中可真熱鬧榜旦,春花似錦、人聲如沸景殷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猿挚。三九已至咐旧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绩蜻,已是汗流浹背铣墨。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留办绝,地道東北人伊约。 一個(gè)月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像孕蝉,于是被迫代替她去往敵國和親屡律。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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

  • 緩存的基礎(chǔ)知識 1降淮、程序本身具有局部性 時(shí)間局部性過去訪問到的數(shù)據(jù)超埋,也有可能被兩次訪問 空間局部性一個(gè)數(shù)據(jù)被訪問到...
    魏鎮(zhèn)坪閱讀 2,028評論 1 3
  • 本文編譯自:users-guide 本節(jié)講述如何使用 VCL 編寫處理 HTTP 流量的策略。 Varnish 的...
    C86guli閱讀 3,184評論 0 1
  • 1.介紹 運(yùn)維日常: 2.Web Page Cache: varnish2.0,3.0處理過程 varnish4....
    尛尛大尹閱讀 3,361評論 0 0
  • 圖/網(wǎng)絡(luò) 諾貝爾物理學(xué)獎(jiǎng)得主猶太人拉比獲獎(jiǎng)后,有人向他請教:“你是怎么獲得諾貝爾物理學(xué)獎(jiǎng)的呢腋颠?”他回答說:“我獲得...
    近視看客閱讀 786評論 0 2
  • 我畫不出你的樣子 說不出你的名字 卻能描繪我們未來的日子 我們深深相愛 會經(jīng)常擁抱彼此 我們一起教育孩子 會撤背桑回家...
    Rebecca球閱讀 163評論 0 2