web緩存入門了解
能解決問(wen)題的(de)緩存就(jiu)(jiu)是(shi)好(hao)緩存。這句話(hua)簡直(zhi)就(jiu)(jiu)是(shi)廢話(hua),相當于白貓、黑貓,抓(zhua)住老鼠(shu)的(de)就(jiu)(jiu)是(shi)好(hao)貓。
那在(zai)解(jie)決問(wen)(wen)題(ti)前提(ti)下(xia),哪個緩(huan)(huan)(huan)存(cun)才是好(hao)緩(huan)(huan)(huan)存(cun)呢? 這(zhe)個問(wen)(wen)題(ti)我的答(da)案(an)是:緩(huan)(huan)(huan)存(cun)命(ming)中率高(gao)的緩(huan)(huan)(huan)存(cun)是好(hao)緩(huan)(huan)(huan)存(cun)。
在解決問題前(qian)提下,命中(zhong)(zhong)率(lv)高(gao)(gao)的(de)(de)緩存比(bi)(bi)命中(zhong)(zhong)率(lv)低的(de)(de)緩存,在硬件投入上可能(neng)會比(bi)(bi)較(jiao)小,同時緩存的(de)(de)數(shu)量比(bi)(bi)命中(zhong)(zhong)率(lv)低的(de)(de)緩存數(shu)量也可能(neng)少,這樣尋址(zhi)的(de)(de)速(su)度 肯定比(bi)(bi)較(jiao)快(kuai)。所以命中(zhong)(zhong)率(lv)高(gao)(gao)的(de)(de)緩存是好(hao)緩存。
緩存的命中率
一個(ge)緩(huan)(huan)存(cun)(cun)(cun)的(de)實體(ti)在(zai)被丟到(dao)緩(huan)(huan)存(cun)(cun)(cun)中后,在(zai)這(zhe)(zhe)個(ge)實體(ti)被緩(huan)(huan)存(cun)(cun)(cun)的(de)期間(這(zhe)(zhe)個(ge)實體(ti)被緩(huan)(huan)存(cun)(cun)(cun)的(de)生命(ming)周期內),如果(guo)外部一次都沒有使用過它,這(zhe)(zhe)個(ge)緩(huan)(huan)存(cun)(cun)(cun)實體(ti)的(de)命(ming)中率 就是0。這(zhe)(zhe)個(ge)實體(ti)被請(qing)求的(de)次數(shu)越多(duo),它的(de)緩(huan)(huan)存(cun)(cun)(cun)命(ming)中率越高。
上(shang)面說的(de)是緩存中(zhong)一個實體(ti)的(de)命(ming)中(zhong)率(lv)。對于緩存整體(ti)來說,它的(de)命(ming)中(zhong)率(lv)則是上(shang)面各(ge)個被(bei)緩存的(de)個體(ti)的(de)命(ming)中(zhong)率(lv)分(fen)布圖。
對于緩存來說:通(tong)常(chang)(chang)最(zui)常(chang)(chang)使用(yong)的個體之占總(zong)體的很小一部分。最(zui)不常(chang)(chang)使用(yong)的占整體的很大一部分。
所(suo)以我們(men)經常會看到類(lei)似這(zhe)樣的數據:
緩存(cun)的(de)(de)1萬個(ge)元素中,有100個(ge)被(bei)(bei)頻繁的(de)(de)使(shi)用,幾乎每(mei)分(fen)鐘都會被(bei)(bei)使(shi)用一次。2000個(ge)數(shu)據,每(mei)小時(shi)被(bei)(bei)請求(qiu)一次。3000個(ge)數(shu)據,每(mei)天被(bei)(bei)請求(qiu)一 次,剩下的(de)(de)數(shu)據,被(bei)(bei)丟到緩存(cun)中后一次都沒有被(bei)(bei)使(shi)用過(guo)。
現(xian)在硬件發(fa)(fa)展很快,如(ru)果(guo)我(wo)們只(zhi)是需(xu)要(yao)緩存1萬(wan)個數(shu)(shu)據的話,我(wo)們完全可(ke)以做(zuo)到不(bu)管這1萬(wan)個數(shu)(shu)據是否被使用到,全部丟到緩存,這樣只(zhi)要(yao)找數(shu)(shu)據,肯定 緩存中有這個數(shu)(shu)據。而不(bu)需(xu)要(yao)作額外的運算(suan),或者(zhe)不(bu)需(xu)要(yao)向數(shu)(shu)據庫(ku)發(fa)(fa)出請求。
但是(shi)(shi)(shi):硬件發展快,數(shu)(shu)(shu)據(ju)量(liang)發展也快。小型(xing)(xing)的(de)網站,緩(huan)(huan)存(cun)1萬條數(shu)(shu)(shu)據(ju),也就(jiu)(jiu)全部緩(huan)(huan)存(cun)了(le)。但是(shi)(shi)(shi)大型(xing)(xing)網站最少也是(shi)(shi)(shi)上(shang)百萬的(de)數(shu)(shu)(shu)據(ju)量(liang)或者上(shang)T級別的(de)數(shu)(shu)(shu)據(ju),這(zhe) 些(xie)數(shu)(shu)(shu)據(ju)量(liang)顯然不能(neng)都丟到緩(huan)(huan)存(cun)。這(zhe)時候設計一個合理的(de)緩(huan)(huan)存(cun)方案,提高緩(huan)(huan)存(cun)的(de)命中率(lv),就(jiu)(jiu)非(fei)常重要。而且(qie)是(shi)(shi)(shi)必須的(de)。
提高緩(huan)存(cun)命中率的一些(xie)常(chang)見方法
純技術的角度(du)來說,我(wo)們只有記(ji)錄了用戶的單(dan)位時(shi)間的請求數,并依照這(zhe)個信息(xi)來把最(zui)常被(bei)使用的數據緩存起來。
但更多的(de)時(shi)候,我們是根(gen)據業務邏輯來(lai)提(ti)高緩(huan)存命中(zhong)率的(de)。比如:去年,前年發表的(de)博(bo)客,這類文章的(de)瀏覽請求,一般一天至少可憐的(de)幾次。一般不應該(gai) 緩(huan)存到內(nei)存中(zhong)。
又比如,回(hui)復數(shu)(shu)多的帖子,一般被請求數(shu)(shu)會比回(hui)復數(shu)(shu)少的帖子會被更多人(ren)次看到。
我(wo)們(men)應該通過上(shang)面邏輯(ji),根據我(wo)們(men)實(shi)際業務(wu)邏輯(ji),提供(gong)一個緩存(cun)(cun)算法,提高緩存(cun)(cun)的命(ming)中率。讓(rang)在我(wo)們(men)硬件允許的條件下,緩存(cun)(cun)適(shi)當的數(shu)據,而不是所有數(shu) 據。
一個反面的(de)例子(zi)就(jiu)是:不管三七二十一,一個大型的(de)博客站點,一篇文章被用戶請(qing)求的(de)時候(hou),發(fa)現不在內存(cun)緩存(cun)中(zhong),就(jiu)從數據庫(ku)中(zhong)讀出(chu),然后丟到緩存(cun)。
要知道(dao),現在爬(pa)蟲程序很(hen)多的(de)。另(ling)外,博客(ke)這類搜索引(yin)擎(qing)友(you)好(hao)的(de)站點,決(jue)大多數的(de)訪(fang)問壓力是搜索引(yin)擎(qing)搜索過來的(de)。而這些訪(fang)問一般(ban)都是1小時,或(huo)者1 天之內,對(dui)某篇文章只有(you)(you)幾(ji)次甚至1次請求,之后再也沒有(you)(you)了。上面(mian)作緩存的(de)方法,命中(zhong)率會非(fei)常低的(de)。
這里也許就有人會問,郭紅俊,既(ji)然你(ni)不(bu)建議我(wo)緩(huan)存這些博客的(de)內容,但是我(wo)如何(he)提高我(wo)站點的(de)性能呀,我(wo)至少(shao)得保證我(wo)博客站點不(bu)會速度慢的(de)無(wu)法(fa)響(xiang)應(ying) 用(yong)戶請求呀。
這(zhe)個(ge)問(wen)題的(de)(de)解決方(fang)案有很多,一個(ge)最簡單的(de)(de)方(fang)法就是(shi)把(ba)這(zhe)些(xie)博(bo)客做(zuo)成靜態Html頁面,也就是(shi)文件系統的(de)(de)緩存(cun),文件系統因為硬盤的(de)(de)原(yuan)因,可以(yi)簡單理 解成可以(yi)無限擴容,這(zhe)樣就可以(yi)把(ba)很多命中率低的(de)(de)內容進行緩存(cun)。
如果(guo)你的(de)(de)頁(ye)面需要一些動態邏輯(ji)判(pan)斷,你可以把數據(ju)緩(huan)存成(cheng)xml文(wen)件(jian),然后服(fu)務器(qi)段整合這(zhe)些XML文(wen)件(jian),或者(zhe)是(shi)(shi)包含文(wen)件(jian)。這(zhe)也是(shi)(shi)種不錯的(de)(de)方法。
說(shuo)了(le)這么多(duo)緩(huan)存命中(zhong)率(lv)(lv)的問(wen)題,簡單匯總(zong)一下緩(huan)存命中(zhong)率(lv)(lv)的觀點:
小型網站可以全部數據緩存,一般壓力也不會很大,可以忽略緩存命中率問題。
大型服務無法全部數據緩存,只能部分數據緩存,這時候就需要架構師設計出對該業務邏輯適用的緩存方法,盡可能的提高緩存的命中率。
提高命中率的方法大多是跟業務邏輯捆綁的,需要跟具體問題具體分析
對于不能被內存緩存的數據,最簡單的提高性能方法就是使用文件緩存。
文件緩存可以整個內容緩存成一個靜態文件;也可以是整個頁面的一個區域被緩存成一個文件,然后被包含;也可以是把一個實體序列化成XML 文件進行緩存。
下面(mian)我們看看緩存的(de)其他幾個(ge)不那么重(zhong)要的(de)方面(mian):
緩存的(de)生命周(zhou)期(qi)內的(de)活(huo)動
永(yong)久(jiu)(jiu)不過期,永(yong)久(jiu)(jiu)不變更的內(nei)容,這類東(dong)西就不應該放在緩(huan)存。緩(huan)存是臨(lin)時的存儲,而不是永(yong)久(jiu)(jiu)的,所(suo)以緩(huan)存的生(sheng)命周(zhou)期是有(you)限的。
它依次(ci)可能會經歷如下(xia)活動(dong):
進入緩存。(進入緩存的時候,可能需要指定它以后的過期策略,如果不指定,需要使用系統默認的過期策略)
從緩存中獲得它,注意,這時候需要處理線程安全的問題。
更新緩存,注意,也需要考慮線程安全問題
離開緩存,這個可能是外部請求,也可能是緩存根據過期策略把它清理掉。
緩存的過期策略
一般我會問,你所接觸的緩存(cun)中,碰到過(guo)(guo)那些緩存(cun)過(guo)(guo)期策(ce)略?
最常見的幾種(zhong)過期策略如下:
多(duo)長時間沒有被請求(qiu),則過(guo)期,最典型的(de)就(jiu)是asp和asp.net 提供(gong)的(de) Section 功(gong)能。其實它(ta)就(jiu)是一個(ge)緩存。
依賴(lai)于文(wen)件(jian)變更的緩存,一(yi)旦文(wen)件(jian)被(bei)修改,緩存則過期,典型的是 WEB站點的 Web.config ,一(yi)旦這個文(wen)件(jian)變更,不但緩存重(zhong)起,IIS進程(cheng)也(ye)會進行一(yi)次釋(shi)放工作。
在此基礎上,可能看到很(hen)多依賴關系的(de)緩(huan)存過期(qi)策略。比(bi)如(ru)依賴于數據庫的(de)緩(huan)存過期(qi)策略。
當(dang)然(ran),業務(wu)邏輯里可能會(hui)有更(geng)復雜(za)的過期策略(lve),必(bi)須(xu)CSDN新版(ban)積分制論(lun)壇(tan)中,帖子列(lie)(lie)表(biao)緩存會(hui)在(zai)列(lie)(lie)表(biao)數據緩存達到600時,把它(ta)清理到550條數 據。
又比如新積分制論壇帖(tie)子(zi)的緩存過期,則是沒有任何(he)列表引用這個帖(tie)子(zi)后,則這個帖(tie)子(zi)過期。
緩存的同步問題
使用緩(huan)存(cun),則意味(wei)著(zhu)同樣(yang)的數據(ju),可能(neng)有(you)多份(fen)并存(cun)。如果你的代碼沒有(you)考(kao)慮某種(zhong)情況,導致了這兩份(fen)數據(ju)不一致了。這時候就會有(you)問題發生。
解(jie)決方法(fa)很簡單,把你的(de)業務邏(luo)輯(ji),代碼(ma)觸(chu)(chu)發情況都考(kao)慮清楚,不要遺留沒有觸(chu)(chu)底(di)的(de)地方。
簡單的方法會(hui)導致你(ni)的代碼邏輯變得(de)非常復雜(za)。
這也(ye)就是有(you)些(xie)人,在非必要的時候,建議你(ni)不要用緩存的原因。一旦開始使用緩存,你(ni)就應該(gai)準(zhun)備增加大量的代碼來處理數(shu)據同步的問題。
初始化填(tian)充緩存(cun)數據(ju)
有時候在緩(huan)存被(bei)初始化(hua)后,還需要預先填充一些數據到緩(huan)存中。這就(jiu)是緩(huan)存數據的初始化(hua)操作。
緩存數(shu)據的初始化操(cao)作需要考(kao)慮以下問(wen)題:
需要多長時間進行初始化,一般如果是站點的話,我們可能在 Global.asa 的 application_OnStart 中處理這個初始化工作。初始化的一般不能太久,這時候就是考驗我們代碼優化的能力了。
初始化的時候,一般是批量導入數據,而不是我們正常使用的時候,一次處理一個數據。
總結:
本文介(jie)紹了(le)我(wo)對緩存(cun)的一些觀點,而沒有深入涉及到具(ju)體的緩存(cun)技術。希望通(tong)過本文的講述(shu),讓只(zhi)會緩存(cun)用法(fa)不懂緩存(cun)思想的人有初步的了(le)解。
文(wen)章來源于縱橫數(shu)據(

