深入探讨Varnish缓存命中率
也許你還在為剛才動態(tài)內(nèi)容獲得7336.76 reqs/s的吞吐率感到振奮,等等,理想和現(xiàn)實是有差距的,你要忍受現(xiàn)實的殘酷,別忘了,我們壓力測試中的動態(tài)內(nèi)容都處于全緩存情況下,也就是每次請求都命中緩存,這在現(xiàn)實中往往是不可能的。
首先,緩存區(qū)空間大小是有限的,而我們的站點可能有大量的內(nèi)容需要被緩存,而不像前邊壓力測試時只有一個內(nèi)容。一旦緩存區(qū)被裝滿,那么緩存管理器便會淘汰一些它認為不再需要的緩存內(nèi)容,比如通過LRU(最近最少使用算法)將使用頻率較低的緩存內(nèi)容淘汰出去,但是,這里判斷“不常使用”的標準是不嚴格的,也許被淘汰的內(nèi)容就是你將要訪問的下一個內(nèi)容,這便影響了它的命中率。
其次,緩存的過期時間也影響到它的命中率,假如有效期很短,為10秒,那么最少10秒便會有一次無法命中。
還有,有些內(nèi)容可能根本沒有被代理服務器緩存,比如這些內(nèi)容包含了set-cookie等不可緩存的HTTP頭信息,導致反向代理不會緩存它們,并且在瀏覽器請求它們的時候也不會去緩存區(qū)查找。這是影響命中率的一個重要因素,但往往被我們所忽略。
幸運的是,這些問題我們都可以輕松的解決,前提是,我們需要了解反向代理緩存的實時工作狀態(tài),比如Varnish便提供了一個命令行的狀態(tài)監(jiān)控程序varnishstat,我們打開它,便看到了當前時刻的狀態(tài),如下:
client_conn 9908723 94.05 Client connections accepted client_drop 0 0.00 Connection dropped, no sess/wrk client_req 16433490 155.99 Client requests received cache_hit 8751732 83.07 Cache hits cache_hitpass 42592 0.40 Cache hits for pass cache_miss 7573389 71.89 Cache misses backend_conn 3889845 36.92 Backend conn. success backend_unhealthy 220 0.00 Backend conn. not attempted backend_busy 0 0.00 Backend conn. too many backend_fail 4536 0.04 Backend conn. failures backend_reuse 3780212 35.88 Backend conn. reuses backend_toolate 3866687 36.70 Backend conn. was closed backend_recycle 7646677 72.58 Backend conn. recycles backend_unused 0 0.00 Backend conn. unused fetch_head 57 0.00 Fetch head fetch_length 155097 1.47 Fetch with Length fetch_chunked 7508522 71.27 Fetch chunked fetch_eof 0 0.00 Fetch EOF fetch_bad 0 0.00 Fetch had bad headers fetch_close 3982 0.04 Fetch wanted close fetch_oldhttp 0 0.00 Fetch pre HTTP/1.1 closed fetch_zero 0 0.00 Fetch zero len fetch_failed 0 0.00 Fetch failed n_sess_mem 1033 . N struct sess_mem n_sess 633 . N struct sess n_object 1016443 . N struct object n_vampireobject 0 . N unresurrected objects n_objectcore 1017564 . N struct objectcore n_objecthead 982903 . N struct objecthead n_smf 2647421 . N struct smf n_smf_frag 622470 . N small free smf n_smf_large 3 . N large free smf n_vbe_conn 12 . N struct vbe_conn n_wrk 8000 . N worker threads n_wrk_create 8000 0.08 N worker threads created n_wrk_failed 0 0.00 N worker threads not created n_wrk_max 11021 0.10 N worker threads limited n_wrk_queue 0 0.00 N queued work requests n_wrk_overflow 2441 0.02 N overflowed work requests n_wrk_drop 0 0.00 N dropped work requests n_backend 4 . N backends n_expired 6344546 . N expired objects n_lru_nuked 183957 . N LRU nuked objects n_lru_saved 0 . N LRU saved objects n_lru_moved 3692170 . N LRU moved objects n_deathrow 0 . N objects on deathrow losthdr 84 0.00 HTTP header overflows n_objsendfile 0 0.00 Objects sent with sendfile n_objwrite 15466812 146.81 Objects sent with write n_objoverflow 0 0.00 Objects overflowing workspace s_sess 9906155 94.03 Total Sessions s_req 16433490 155.99 Total Requests s_pipe 37 0.00 Total pipe s_pass 108252 1.03 Total pass s_fetch 7667658 72.78 Total fetch s_hdrbytes 7187255662 68221.35 Total header bytes s_bodybytes 111592032839 1059230.32 Total body bytes sess_closed 1905544 18.09 Session Closed sess_pipeline 0 0.00 Session Pipeline sess_readahead 0 0.00 Session Read Ahead sess_linger 15277717 145.02 Session Linger sess_herd 13547370 128.59 Session herd shm_records 1028855796 9765.89 SHM records shm_writes 77957008 739.97 SHM writes shm_flushes 131005 1.24 SHM flushes due to overflow shm_cont 144281 1.37 SHM MTX contention shm_cycles 427 0.00 SHM cycles through buffer sm_nreq 15306717 145.29 allocator requests sm_nobj 2024948 . outstanding allocations sm_balloc 13595295744 . bytes allocated sm_bfree 40091795456 . bytes free sma_nreq 0 0.00 SMA allocator requests sma_nobj 0 . SMA outstanding allocations sma_nbytes 0 . SMA outstanding bytes sma_balloc 0 . SMA bytes allocated sma_bfree 0 . SMA bytes free sms_nreq 14062 0.13 SMS allocator requests sms_nobj 0 . SMS outstanding allocations sms_nbytes 487 . SMS outstanding bytes sms_balloc 6844837 . SMS bytes allocated sms_bfree 6846298 . SMS bytes freed backend_req 7668789 72.79 Backend requests made n_vcl 1 0.00 N vcl total n_vcl_avail 1 0.00 N vcl available n_vcl_discard 0 0.00 N vcl discarded n_purge 740577 . N total active purges n_purge_add 905392 8.59 N new purges added n_purge_retire 164815 1.56 N old purges deleted n_purge_obj_test 13397373 127.17 N objects tested n_purge_re_test 131875330367 1251759.15 N regexps tested against n_purge_dups 240655 2.28 N duplicate purges removed hcb_nolock 0 0.00 HCB Lookups without lock hcb_lock 0 0.00 HCB Lookups with lock hcb_insert 0 0.00 HCB Inserts esi_parse 0 0.00 Objects ESI parsed (unlock) esi_errors 0 0.00 ESI parse errors (unlock) accept_fail 2553 0.02 Accept failures client_drop_late 0 0.00 Connection dropped late uptime 105352 1.00 Client uptime
看起來很強大,的確,它幫我們獲得了很多重要的信息,包括了三個重要的統(tǒng)計項:
N struct object
當前被cache的條目
Client requests received
代表到目前為止,瀏覽器向反向代理服務器發(fā)送的HTTP請求累積次數(shù),由于可能使用長連接,所以它可能會大于上邊的Client connections accepted。
Cache hits
代表在這些請求中,反向代理服務器在緩存區(qū)中查找并且命中緩存的次數(shù)。
Cache misses
代表在這些請求中,反向代理服務器在緩存區(qū)中查找但是沒有命中緩存的次數(shù)。
N expired objects
代表過期的緩存內(nèi)容個數(shù)
N LRU nuked objects
由于cache空間滿而不得不扔掉的cache條目,如果這個數(shù)字是0,就沒必要增加cache的大小了。
N LRU moved objects
代表被淘汰的緩存內(nèi)容個數(shù)
Total header bytes
代表緩存區(qū)中所有緩存內(nèi)容的HTTP頭信息長度
Total body bytes
代表緩存區(qū)中所有緩存內(nèi)容的正文長度
通過以上這些統(tǒng)計項,我們還可以知道更多,比如Cache hits和Cache misses的總和代表了反向代理服務器在緩存區(qū)中查找內(nèi)容的總次數(shù);而用Client requests received減去這個總次數(shù),便大概等于沒有查找緩存的請求數(shù);Total body bytes和Total body bytes的總和則代表了緩存區(qū)當前的空間使用量。
了解了這些后,我們回頭看前邊的三個問題,都很容易分析和解決。
對于緩存區(qū)空間大小的問題,我們可以通過監(jiān)視它的使用量以及緩存淘汰個數(shù),在必要的時候分配更多的緩存區(qū)空間,但是這可能需要重新啟動反向代理服務器。當然,我們應該首先根據(jù)站點的規(guī)模,來估算出大概的緩存區(qū)空間,并且分配出大約為它5倍以上的緩存區(qū)空間,以適應一段時期內(nèi)的內(nèi)容數(shù)量增長。
其次,是緩存有效期取值的問題,但這本身不是一個問題,它取決于后端Web服務器的承受能力,以及你對站點內(nèi)容實時性的要求,我們在前邊介紹動態(tài)內(nèi)容緩存的章節(jié)中曾經(jīng)探討過緩存有效期的取值,實質(zhì)上是一個尋找“過”與“不及”之間平衡的長期過程,但在動態(tài)程序?qū)崿F(xiàn)的內(nèi)容緩存機制中,我們還可以通過主動刪除緩存的方法來實現(xiàn)緩存到期之前的更新,而基于HTTP協(xié)議的反向代理緩存機制則不容易做到這一點,后端的動態(tài)程序無法主動刪除某個緩存內(nèi)容,除非我們清空反向代理服務器上的緩存區(qū)。
在尋找平衡的過程中,有時候?qū)崟r性需求可能要向緩存有效期適當讓步,當我們的站點面臨較大的壓力時,我們不得不暫時以犧牲實時性作為代價,適當?shù)难娱L緩存有效期,直到我們有了成熟的性能擴展方案。
在初步評估緩存有效期的時候,我們可以通過一些量化的計算來得出理論數(shù)值,舉個例子,假如我們的站點有60000個動態(tài)內(nèi)容處于頻繁訪問的狀態(tài),我們通過Cache-Control將它們在反向代理服務器上的緩存有效期都設置為60秒,這樣一樣來,后端服務器將必須承受最多每秒處理1000個動態(tài)內(nèi)容的工作量,如果這些動態(tài)內(nèi)容都進行完整的計算,比如訪問數(shù)據(jù)庫,那么顯然后端服務器是無法承受的,這時候我們可以將緩存有效期延長到300秒,即5分鐘,這使得后端服務器只需要每秒處理200個動態(tài)內(nèi)容,大大減少了工作量。
那么,如果從緩存命中率的角度來分析緩存有效期取值的時候,有一點需要明白,當我們看到緩存的命中率非常低時,有時并不代表我們需要馬上延長緩存有效期,這時候還要觀察當前的站點實際吞吐率,舉個極端的例子,假如你發(fā)現(xiàn)你的站點1個小時內(nèi)只有1次訪問,而緩存有效期為半個小時,那緩存命中率必然會非常低,但即便是每次緩存都不命中,也不會對后端帶來什么壓力,實際上如果你的站點只有一臺Web服務器,并且站點的實際吞吐率遠遠低于它的處理能力時,完全沒有必要使用反向代理服務器。
最后關(guān)于內(nèi)容沒有被緩存的問題,我們也可以在Varnish的狀態(tài)監(jiān)視中找到線索,比如有一個用Varnish加速第三方應用wordpress的例子,得到的Varnish狀態(tài)如下:
4+10:37:44 my.server.com Hitrate ratio: 1 1 1 Hitrate avg: 0.0364 0.0364 0.0364 2324 0.00 0.01 Client connections accepted 6191 0.00 0.02 Client requests received 12 0.00 0.00 Cache hits 7 0.00 0.00 Cache hits for pass 318 0.00 0.00 Cache misses 6179 0.00 0.02 Backend connections success 0 0.00 0.00 Backend connections not attempted 0 0.00 0.00 Backend connections too many 0 0.00 0.00 Backend connections failures 4057 0.00 0.01 Backend connections reuses 6151 0.00 0.02 Backend connections recycles ...
我們看到,Varnish一共處理了來自瀏覽器的6191個請求,其中命中緩存的有12個,真是太少了,而沒有命中緩存的有318個,奇怪,剩下的那么多請求根本就沒有去緩存區(qū)檢查,也就是說,Varnish認為那些內(nèi)容不能被緩存。不能被緩存總是有原因的,你需要根據(jù)反向代理緩存的規(guī)則,來進一步的檢查。而我們這個例子中,都是cookies惹得禍,因為在wordpress中由于我們會安裝一些各種各樣的插件,有些插件會使得wordpress的每個頁面都帶有寫入cookies的set-cookie標記,而我們前邊在vcl_fetch函數(shù)中禁止了這類內(nèi)容的緩存,問題就在這里了,我們希望將這些多余的cookie關(guān)閉掉,但是,wordpress自身的登錄和管理頁面是需要cookies才可以正常工作的,所以我們還需要讓反向代理不緩存這些頁面,我們使用以下VCL配置:
sub vcl_recv
{
if (!(req.url ~ "wp-(login|admin)"))
{
unset req.http.cookie;
}
}
sub vcl_fetch
{
if (!(req.url ~ "wp-(login|admin)"))
{
unset obj.http.set-cookie;
}
}
可以看到,除了wordpress自身的登錄和管理頁面以外,我們將其它內(nèi)容的HTTP頭信息中有關(guān)cookie的標記全部都清除掉,這使得Varnish可以將大部分內(nèi)容緩存起來,提高緩存命中率,同時不影響我們登錄和管理wordpress。
這個例子給了我們一些啟示,對于我們自己的站點,如果從長遠考慮,那么在規(guī)劃的時候就要費點心思,我們可以根據(jù)內(nèi)容是否可以緩存在反向代理服務器上,將它們置于不同的主機,這樣便可以在必要的時候?qū)⒖梢跃彺娴膬?nèi)容快速與反向代理服務器對接,獲得較好的加速效果。
總結(jié)
以上是生活随笔為你收集整理的深入探讨Varnish缓存命中率的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最近到底有什么事 为什么写手开始黑林黛玉
- 下一篇: 富贵烟有几种?