關于如何更新緩存的探討

寫這篇文章的原因

現(xiàn)在我們的系統(tǒng)都需要使用緩存提高性能醋界,使用緩存就需要對緩存進行維護竟宋,那么當數(shù)據(jù)發(fā)生變化時我們應該先操作緩存還是先操作數(shù)據(jù)庫呢?網(wǎng)上有兩篇很好的文章形纺,一篇是來自58沈劍的架構師之路系列之緩存架構設計緩存架構設計丘侠,一篇來自于左耳朵耗子陳皓的緩存更新的套路,兩位老師給出了很好的分析逐样,這里分別總結一下蜗字,希望能對看過的同學有所幫助。

架構師之路

先來說一下沈劍老師的文章脂新。

當數(shù)據(jù)庫執(zhí)行更新操作時挪捕,我們會進行緩存的淘汰,由于操作緩存與操作數(shù)據(jù)庫并不能保證原子性争便,所以解題思路就是:如果出現(xiàn)不一致级零,誰先做對業(yè)務的影響較小,就誰先執(zhí)行滞乙。分別分析下

先寫數(shù)據(jù)庫的情況:第一步寫數(shù)據(jù)庫操作成功奏纪,第二步淘汰緩存失敗鉴嗤,則會出現(xiàn)DB中是新數(shù)據(jù),Cache中是舊數(shù)據(jù)序调,數(shù)據(jù)不一致躬窜。

先淘汰緩存的情況:第一步淘汰緩存成功,第二步寫數(shù)據(jù)庫失敗炕置,則只會引發(fā)一次Cache miss。

所以結論是:先淘汰緩存男韧,再寫數(shù)據(jù)庫

陳皓-酷殼

剛開始看的時候讓我驚訝的是朴摊,陳皓老師文章開篇就指出了先淘汰緩存再更新數(shù)據(jù)庫的做法是錯誤的。

給出的理由如下:兩個并發(fā)操作此虑,一個是更新操作甚纲,另一個是查詢操作,更新操作刪除緩存后朦前,查詢操作沒有命中緩存介杆,先把老數(shù)據(jù)讀出來后放到緩存中,然后更新操作更新了數(shù)據(jù)庫韭寸。于是春哨,在緩存中的數(shù)據(jù)還是老的數(shù)據(jù),導致緩存中的數(shù)據(jù)是臟的恩伺,而且還一直這樣臟下去了(好像沒毛哺氨场)

接下來列舉了幾個常用的緩存模式

首先是Cache aside

以下是對Cache aside幾種緩存狀態(tài)的處理:

失效:應用程序先從cache取數(shù)據(jù),沒有得到晶渠,則從數(shù)據(jù)庫中取數(shù)據(jù)凰荚,成功后,放到緩存中褒脯。

命中:應用程序從cache中取數(shù)據(jù)便瑟,取到后返回。

更新:先把數(shù)據(jù)存到數(shù)據(jù)庫中番川,成功后到涂,再讓緩存失效。

這個更新操作就不會發(fā)生陳皓老師開篇時提到的問題爽彤。舉個??养盗,一個查詢操作和一個更新操作的并發(fā),首先适篙,沒有了刪除cache數(shù)據(jù)的操作了往核,而是先更新了數(shù)據(jù)庫中的數(shù)據(jù),此時嚷节,緩存依然有效聂儒,所以虎锚,并發(fā)的查詢操作拿的是沒有更新的數(shù)據(jù),但是衩婚,更新操作馬上讓緩存的失效了窜护,后續(xù)的查詢操作再把數(shù)據(jù)從數(shù)據(jù)庫中拉出來。這樣后續(xù)的查詢操作就會拉取最新的數(shù)據(jù)非春。

并且陳皓老師也指出柱徙,F(xiàn)acebook的論文《Scaling Memcache at Facebook》也使用了這個策略。這樣做的目的主要是避免兩個并發(fā)的寫操作導致臟數(shù)據(jù)奇昙。

但是隨后又指出這個模式也會出現(xiàn)不一致的情況护侮,舉個??,一個是讀操作储耐,但是沒有命中緩存羊初,然后就到數(shù)據(jù)庫中取數(shù)據(jù),此時來了一個寫操作什湘,寫完數(shù)據(jù)庫后长赞,讓緩存失效,然后闽撤,之前的那個讀操作再把老的數(shù)據(jù)放進去得哆,所以,會造成臟數(shù)據(jù)腹尖。這個case理論上會出現(xiàn)柳恐,不過出現(xiàn)的概率可能非常低,因為這個條件需要發(fā)生在讀緩存時緩存失效热幔,而且并發(fā)著有一個寫操作乐设。而實際上數(shù)據(jù)庫的寫操作會比讀操作慢得多,而且還要鎖表绎巨,而讀操作必需在寫操作前進入數(shù)據(jù)庫操作近尚,而又要晚于寫操作更新緩存,所有的這些條件都具備的概率基本并不大场勤。

所以使用先操作數(shù)據(jù)庫后操作緩存的方法會大大降低并發(fā)時臟數(shù)據(jù)的概率戈锻,并且為了盡量避免上文的低概率事件,最好為緩存設置過期時間和媳。

這里陳皓老師得出了與沈劍老師相反的結論格遭,陳皓老師在文章的末尾給出了答案“上面,我們沒有考慮緩存(Cache)和持久層(Repository)的整體事務的問題”留瞳,假設原子性得以保障(可以使用2PC拒迅,3PC,Paxos等算法進行保障),那么先操作數(shù)據(jù)庫則是最優(yōu)的選擇璧微。兩位老師的結論先放一邊作箍,繼續(xù)。

陳皓老師又給我們開了點小灶前硫,介紹了其他常用的緩存模式胞得。

Read/Write Through Pattern

Read Through 套路就是在查詢操作中更新緩存,也就是說屹电,當緩存失效的時候(過期或LRU換出)阶剑,Cache Aside是由調(diào)用方負責把數(shù)據(jù)加載入緩存,而Read Through則用緩存服務自己來加載危号,從而對應用方是透明的个扰。

Write Through 套路和Read Through相仿,不過是在更新數(shù)據(jù)時發(fā)生葱色。當有數(shù)據(jù)更新的時候,如果沒有命中緩存娘香,直接更新數(shù)據(jù)庫苍狰,然后返回。如果命中了緩存烘绽,則更新緩存淋昭,然后再由Cache自己更新數(shù)據(jù)庫(這是一個同步操作)

Write Behind Caching Pattern

Write Behind 又叫 Write Back。Write Back一句說就是安接,在更新數(shù)據(jù)的時候翔忽,只更新緩存,不更新數(shù)據(jù)庫盏檐,而我們的緩存會異步地批量更新數(shù)據(jù)庫歇式。這個設計的好處就是讓數(shù)據(jù)的I/O操作飛快無比,因為異步胡野,write backg還可以合并對同一個數(shù)據(jù)的多次操作材失,所以性能的提高是相當可觀的。

但是硫豆,其帶來的問題是龙巨,數(shù)據(jù)不是強一致性的,而且可能會丟失(我們知道Unix/Linux非正常關機會導致數(shù)據(jù)丟失熊响,就是因為這個事)旨别。另外,Write Back實現(xiàn)邏輯比較復雜汗茄,因為他需要track有哪數(shù)據(jù)是被更新了的秸弛,需要刷到持久層上。操作系統(tǒng)的write back會在僅當這個cache需要失效的時候,才會被真正持久起來胆屿,比如奥喻,內(nèi)存不夠了,或是進程退出了等情況非迹,這又叫l(wèi)azy write环鲤。

轉(zhuǎn)折

本來看到這里我本以為沈劍老師沒有考慮到并發(fā)讀寫的問題,導致文章出了紕漏憎兽,直到我看到了他的第二篇文章數(shù)據(jù)與緩存一致性優(yōu)化冷离。

文章開頭給出了讀寫并發(fā)時導致數(shù)據(jù)不一致的case,同陳皓老師舉的??一樣纯命,就不多說了西剥。不過文章后半部分對于先操作緩存,后操作數(shù)據(jù)庫的做法給出了優(yōu)化亿汞。

讓同一個數(shù)據(jù)的訪問能串行化

在一個服務中如何做到“讓同一個數(shù)據(jù)的訪問串行化”瞭空,只需要“讓同一個數(shù)據(jù)的訪問通過同一條DB連接執(zhí)行”就行。如何做到“讓同一個數(shù)據(jù)的訪問通過同一條DB連接執(zhí)行”疗我,只需要“在DB連接池層面稍微修改咆畏,按數(shù)據(jù)取連接即可”。將從連接池獲取數(shù)據(jù)庫連接的操作修改為CPool.GetDBConnection(longid)【返回id取模相關聯(lián)的DB連接】吴裤。

當有多份服務時旧找,方案同上,想辦法讓對同一數(shù)據(jù)的訪問落在同一服務上即可麦牺。同樣CPool.GetServiceConnection(longid)【返回id取模相關聯(lián)的Service連接】钮蛛。

總結一下:

(1)修改服務Service連接池,id取模選取服務連接剖膳,能夠保證同一個數(shù)據(jù)的讀寫都落在同一個后端服務上

(2)修改數(shù)據(jù)庫DB連接池魏颓,id取模選取DB連接,能夠保證同一個數(shù)據(jù)的讀寫在數(shù)據(jù)庫層面是串行的

自己的一些思考

總結完了兩位老師的文章吱晒,最后是自己的一些感悟與思考琼开。

因為我上學的時候就已經(jīng)看過沈劍老師的第一篇文章,當時看完有種豁然開朗枕荞,吊吊吊的感覺柜候,從那以后就一直把先操作緩存后更新數(shù)據(jù)的做法當做了最標準的做法(實際上工作之后發(fā)現(xiàn)項目里也基本都是這樣做的)。直到有一天看到了酷殼上陳皓老師的文章躏精,和我認為的“標準做法”完全相反啊渣刷,這是怎么回事?后來經(jīng)過對文章的仔細閱讀才理清楚矗烛,看到了沈劍老師的第二篇文章也才明白第一篇文章只是個上集辅柴,原來還有下集箩溃。總結一點碌嘀,學知識不能快餐文化涣旨,也不能“逆來順受”,更不能“淺嘗輒止”股冗,我們需要有自己的思考霹陡,需要自己的總結。(寫博客就是挺好的一種總結方式)

最后關于緩存更新倆種方案該選擇哪一種止状,我認為烹棉,如果系統(tǒng)并發(fā)量較小,那么選擇先淘汰緩存的做法(不做后續(xù)連接取模等操作)是比較好的怯疤。如果并發(fā)量較大浆洗,并且緩存系統(tǒng)做了集群,網(wǎng)絡極少發(fā)生抖動(也就是極大程度可以保證原子性)集峦,那么選擇先操作數(shù)據(jù)庫后操作緩存的做法較好伏社。而關于做連接取模與使用2PC等方案保證數(shù)據(jù)一致性,個人感覺沒有必要塔淤,徒增復雜性洛口,因為涉及庫存等重要的數(shù)據(jù)操作無論如何最后都要查詢真實的DB,給緩存數(shù)據(jù)設置過期時間減少不一致發(fā)生的概率與存在時間即可凯沪。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市买优,隨后出現(xiàn)的幾起案子妨马,更是在濱河造成了極大的恐慌,老刑警劉巖杀赢,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烘跺,死亡現(xiàn)場離奇詭異,居然都是意外死亡脂崔,警方通過查閱死者的電腦和手機滤淳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砌左,“玉大人脖咐,你說我怎么就攤上這事』愦酰” “怎么了屁擅?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長产弹。 經(jīng)常有香客問我派歌,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任胶果,我火速辦了婚禮匾嘱,結果婚禮上,老公的妹妹穿的比我還像新娘早抠。我一直安慰自己霎烙,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布贝或。 她就那樣靜靜地躺著吼过,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咪奖。 梳的紋絲不亂的頭發(fā)上盗忱,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音羊赵,去河邊找鬼趟佃。 笑死,一個胖子當著我的面吹牛昧捷,可吹牛的內(nèi)容都是我干的闲昭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼靡挥,長吁一口氣:“原來是場噩夢啊……” “哼序矩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跋破,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤簸淀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后毒返,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體租幕,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年拧簸,在試婚紗的時候發(fā)現(xiàn)自己被綠了劲绪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡盆赤,死狀恐怖贾富,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情牺六,我是刑警寧澤祷安,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站兔乞,受9級特大地震影響汇鞭,放射性物質(zhì)發(fā)生泄漏凉唐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一霍骄、第九天 我趴在偏房一處隱蔽的房頂上張望台囱。 院中可真熱鬧,春花似錦读整、人聲如沸簿训。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽强品。三九已至,卻和暖如春屈糊,著一層夾襖步出監(jiān)牢的瞬間的榛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工逻锐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夫晌,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓昧诱,卻偏偏與公主長得像晓淀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子盏档,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

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