緩存更新策略 - 一致性

[TOC]

參考

Cache Aside Pattern

究竟先操作緩存竞思,還是數(shù)據(jù)庫(kù)雳殊?

緩存更新的套路

使用緩存的正確姿勢(shì)

緩存的正確使用方式药有,你都會(huì)了嗎联逻?

1. 概要

緩存服務(wù)和數(shù)據(jù)服務(wù)(如數(shù)據(jù)庫(kù))是獨(dú)立的系統(tǒng)搓扯,更新的時(shí)候,無法做到原子性地操作兩個(gè)服務(wù)包归,即有兩步操作來更新緩存服務(wù)和數(shù)據(jù)服務(wù)的數(shù)據(jù)锨推。因此在并發(fā)讀寫以及第二步操作異常時(shí),會(huì)出現(xiàn)各種問題箫踩。

此處說的第二步操作爱态,要么是操作緩存服務(wù),要么是操作數(shù)據(jù)服務(wù)境钟,根據(jù)具體的實(shí)現(xiàn)方式而定锦担。

2. 緩存使用的誤區(qū)

  1. 服務(wù)與服務(wù)之間不要通過緩存?zhèn)鬟f數(shù)據(jù)

  2. 如果緩存掛掉,可能導(dǎo)致雪崩慨削,此時(shí)要做高可用緩存洞渔,或者水平切分

  3. 調(diào)用方不宜再單獨(dú)使用緩存存儲(chǔ)服務(wù)底層的數(shù)據(jù)套媚,容易出現(xiàn)數(shù)據(jù)不一致,以及反向依賴

  4. 不同服務(wù)磁椒,緩存實(shí)例要做垂直拆分

3. 常見更新模式

3.1. cache aside

同時(shí)更新緩存和數(shù)據(jù)庫(kù)
這是最常用的pattern了堤瘤。其具體邏輯如下:

  • 數(shù)據(jù)查詢:應(yīng)用程序先從cache取數(shù)據(jù),沒有得到浆熔,則從數(shù)據(jù)庫(kù)中取數(shù)據(jù)本辐,成功后,放到緩存中医增。
  • 數(shù)據(jù)更新:先把數(shù)據(jù)存到數(shù)據(jù)庫(kù)中慎皱,成功后,再讓緩存失效叶骨。
    此處茫多,更新的時(shí)候是先數(shù)據(jù)庫(kù),后緩存忽刽,也有另一種思路天揖,先緩存,后數(shù)據(jù)庫(kù)跪帝。兩種思路詳見后文分析今膊。

3.1.1. 先數(shù)據(jù)庫(kù)后緩存

這是最常用最常用的pattern。
分析異常情況如下:

  • \color{blue}{并發(fā)讀寫}
    • 一個(gè)是查詢請(qǐng)求歉甚,一個(gè)是更新請(qǐng)求的并發(fā)万细。更新請(qǐng)求在寫完數(shù)據(jù)庫(kù)之后扑眉,讓緩存失效之前纸泄,查詢請(qǐng)求到來,此時(shí)腰素,緩存依然有效聘裁,所以,并發(fā)的查詢請(qǐng)求拿的是沒有更新的數(shù)據(jù)弓千,但是衡便,隨后的更新請(qǐng)求會(huì)馬上讓緩存的失效了,在這之后的查詢請(qǐng)求再把數(shù)據(jù)從數(shù)據(jù)庫(kù)中取出來洋访,放入到緩存镣陕。\color{green}{不會(huì)出現(xiàn)不一致。}
    • 同樣是一個(gè)查詢請(qǐng)求姻政,一個(gè)更新請(qǐng)求的并發(fā)呆抑。查詢請(qǐng)求 cache miss,讀了數(shù)據(jù)庫(kù)汁展,在將數(shù)據(jù)放到緩存之前鹊碍,更新請(qǐng)求到來厌殉,更新了數(shù)據(jù)庫(kù)內(nèi)容且讓緩存失效,此時(shí)查詢請(qǐng)求再將之前讀的老數(shù)據(jù)放入到緩存侈咕。這樣也會(huì)導(dǎo)致緩存和數(shù)據(jù)不一致公罕。\color{red}{出現(xiàn)不一致,只是概率很小耀销。} 為了避免這種情況楼眷,可以采取延遲失效,同時(shí)讀請(qǐng)求回填 cache 的時(shí)候熊尉,如果遇到 key 存在摩桶,則不更新,只能等待超時(shí)失效之后帽揪,讀請(qǐng)求回填的 cache 才可以更新硝清;也可以考慮延遲雙刪,緩存失效后转晰,等待1s 再失效一次緩存芦拿。
  • \color{red}{第二步操作異常}:如果是更新請(qǐng)求在寫完數(shù)據(jù)庫(kù),讓緩存失效之前查邢,更新請(qǐng)求發(fā)起方異常(如宕機(jī))蔗崎,此時(shí)數(shù)據(jù)庫(kù)已經(jīng)更新了,但是緩存一直沒有更新扰藕。導(dǎo)致查詢請(qǐng)求從緩存獲取的數(shù)據(jù)一直都是老數(shù)據(jù)缓苛。為了規(guī)避第二步操作異常,有兩種方法:1. 考慮在緩存上加上失效時(shí)間邓深,但是這和周期性的更新緩存類似未桥,還是會(huì)對(duì)系統(tǒng)性能還是有較大的影響;2. 使用可靠的消息隊(duì)列記錄(如 binlog)更改芥备,然后消費(fèi)消息進(jìn)行緩存失效

這是標(biāo)準(zhǔn)的design pattern冬耿,包括Facebook的論文《Scaling Memcache at Facebook》也使用了這個(gè)策略。

3.1.2. 先緩存后數(shù)據(jù)庫(kù)

分析如下:

  • \color{red}{并發(fā)讀寫}:一個(gè)是查詢請(qǐng)求萌壳,一個(gè)是更新請(qǐng)求的并發(fā)亦镶。在更新請(qǐng)求讓緩存失效之后,寫數(shù)據(jù)庫(kù)之前袱瓮,查詢操作到來缤骨,此時(shí),會(huì)從數(shù)據(jù)庫(kù)讀到老數(shù)據(jù)進(jìn)而寫回到緩存尺借,等更新請(qǐng)求寫完數(shù)據(jù)庫(kù)绊起,\color{red}{就會(huì)出現(xiàn)不一致。}

  • \color{red}{第二步操作異常}:如果是更新請(qǐng)求將緩存失效后褐望,在寫數(shù)據(jù)庫(kù)前勒庄,更新操作發(fā)起方異常(如宕機(jī))串前,此時(shí)僅僅是 cache miss,\color{green}{不會(huì)導(dǎo)致不一致实蔽。}

針對(duì)第二種方案荡碾,我們可以采取以下兩種方案規(guī)避并發(fā)讀寫的問題:

  1. 在使緩存失效的時(shí)候,不是立即失效局装,而是采取延遲失效(比如說設(shè)置緩存失效時(shí)間為1s)坛吁,保證在數(shù)據(jù)庫(kù)更新之前,讀請(qǐng)求依舊能夠命中cache铐尚,進(jìn)而不會(huì)出現(xiàn)讀請(qǐng)求更新 cache 的情況拨脉。這個(gè)方案應(yīng)該是最佳方案。
  2. 延遲雙刪宣增。第一次緩存失效且數(shù)據(jù)庫(kù)操作完成之后玫膀,延遲再失效一次緩存。

3.1.3. 更新緩存還是失效緩存

為什么不是更新緩存爹脾,而是失效緩存帖旨?你可以看一下Quora上的這個(gè)問答《Why does Facebook use delete to remove the key-value pair in Memcached instead of updating the Memcached during write request to the backend?》,主要是\color{red}{怕兩個(gè)并發(fā)的更新操作導(dǎo)致臟數(shù)據(jù).}

3.1.3. 結(jié)論

個(gè)人覺得灵妨,先緩存后數(shù)據(jù)庫(kù)解阅,配合延遲失效的方案最好。歡迎讀者討論泌霍。

3.2. Read/Write Through Pattern

先更新緩存货抄,緩存負(fù)責(zé)同步更新數(shù)據(jù)庫(kù)。

在上面的 Cache Aside 更新模式中朱转,應(yīng)用代碼需要維護(hù)兩個(gè)數(shù)據(jù)存儲(chǔ)蟹地,一個(gè)是緩存(Cache),一個(gè)是數(shù)據(jù)庫(kù)(Repository)肋拔。而在Read/Write Through 更新模式中锈津,應(yīng)用程序只需要維護(hù)緩存呀酸,數(shù)據(jù)庫(kù)的維護(hù)工作由緩存代理了凉蜂。


write/read through流程圖

3.2.1. Read Through

Read Through 模式就是在查詢操作中更新緩存,也就是說性誉,當(dāng)緩存失效的時(shí)候窿吩,Cache Aside 模式是由調(diào)用方負(fù)責(zé)把數(shù)據(jù)加載入緩存,而 Read Through 則用緩存服務(wù)自己來加載错览。

3.2.2. Write Through

Write Through 模式和 Read Through 相仿纫雁,不過是在更新數(shù)據(jù)時(shí)發(fā)生。當(dāng)有數(shù)據(jù)更新的時(shí)候倾哺,如果沒有命中緩存轧邪,直接更新數(shù)據(jù)庫(kù)刽脖,然后返回。如果命中了緩存忌愚,則更新緩存曲管,然后由緩存自己更新數(shù)據(jù)庫(kù)(這是一個(gè)同步操作)。

3.3. Write Behind Caching Pattern

先更新緩存硕糊,緩存定時(shí)異步更新數(shù)據(jù)庫(kù)院水。

Write Behind Caching 更新模式就是在更新數(shù)據(jù)的時(shí)候,只更新緩存简十,不更新數(shù)據(jù)庫(kù)檬某,而我們的緩存會(huì)異步地批量更新數(shù)據(jù)庫(kù)。這個(gè)設(shè)計(jì)的好處就是直接操作內(nèi)存速度快螟蝙。因?yàn)楫惒交帜眨琖rite Behind Caching 更新模式還可以合并對(duì)同一個(gè)數(shù)據(jù)的多次操作到數(shù)據(jù)庫(kù),所以性能的提高是相當(dāng)可觀的胰默。

但其帶來的問題是厅瞎,數(shù)據(jù)不是強(qiáng)一致性的,而且可能會(huì)丟失初坠。另外和簸,Write Behind Caching 更新模式實(shí)現(xiàn)邏輯比較復(fù)雜,因?yàn)樗枰_認(rèn)有哪些數(shù)據(jù)是被更新了的碟刺,哪些數(shù)據(jù)需要刷到持久層上锁保。只有在緩存需要失效的時(shí)候,才會(huì)把它真正持久起來半沽。

write behind 流程圖

3.4. 總結(jié)

三種緩存模式的優(yōu)缺點(diǎn):

  • Cache Aside 更新模式實(shí)現(xiàn)起來比較簡(jiǎn)單爽柒,但是需要維護(hù)兩個(gè)數(shù)據(jù)存儲(chǔ),一個(gè)是緩存(Cache)者填,一個(gè)是數(shù)據(jù)庫(kù)(Repository)浩村。
  • Read/Write Through 更新模式只需要維護(hù)一個(gè)數(shù)據(jù)存儲(chǔ)(緩存),但是實(shí)現(xiàn)起來要復(fù)雜一些占哟。
  • Write Behind Caching 更新模式和Read/Write Through 更新模式類似心墅,區(qū)別是Write Behind Caching 更新模式的數(shù)據(jù)持久化操作是異步的,但是Read/Write Through 更新模式的數(shù)據(jù)持久化操作是同步的榨乎。優(yōu)點(diǎn)是直接操作內(nèi)存速度快怎燥,多次操作可以合并持久化到數(shù)據(jù)庫(kù)。缺點(diǎn)是數(shù)據(jù)可能會(huì)丟失蜜暑,例如系統(tǒng)斷電等铐姚。

緩存是通過犧牲強(qiáng)一致性來提高性能的。所以使用緩存提升性能肛捍,就是會(huì)有數(shù)據(jù)更新的延遲隐绵。這需要我們?cè)谠O(shè)計(jì)時(shí)結(jié)合業(yè)務(wù)仔細(xì)思考是否適合用緩存之众。然后緩存一定要設(shè)置過期時(shí)間,這個(gè)時(shí)間太短太長(zhǎng)都不好依许,太短的話請(qǐng)求可能會(huì)比較多的落到數(shù)據(jù)庫(kù)上酝枢,這也意味著失去了緩存的優(yōu)勢(shì)。太長(zhǎng)的話緩存中的臟數(shù)據(jù)會(huì)使系統(tǒng)長(zhǎng)時(shí)間處于一個(gè)延遲的狀態(tài)悍手,而且系統(tǒng)中長(zhǎng)時(shí)間沒有人訪問的數(shù)據(jù)一直存在內(nèi)存中不過期帘睦,浪費(fèi)內(nèi)存。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坦康,一起剝皮案震驚了整個(gè)濱河市竣付,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滞欠,老刑警劉巖古胆,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異筛璧,居然都是意外死亡逸绎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門夭谤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棺牧,“玉大人,你說我怎么就攤上這事朗儒〖粘耍” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵醉锄,是天一觀的道長(zhǎng)乏悄。 經(jīng)常有香客問我,道長(zhǎng)恳不,這世上最難降的妖魔是什么檩小? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮烟勋,結(jié)果婚禮上规求,老公的妹妹穿的比我還像新娘。我一直安慰自己神妹,他們只是感情好颓哮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著僧免,像睡著了一般尊蚁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上建蹄,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音上真,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛乍楚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播届慈,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼徒溪,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了金顿?” 一聲冷哼從身側(cè)響起臊泌,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揍拆,沒想到半個(gè)月后渠概,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嫂拴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年播揪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筒狠。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猪狈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辩恼,到底是詐尸還是另有隱情罪裹,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布运挫,位于F島的核電站状共,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谁帕。R本人自食惡果不足惜峡继,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望匈挖。 院中可真熱鬧碾牌,春花似錦、人聲如沸儡循。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)择膝。三九已至誓琼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腹侣。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工叔收, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人傲隶。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓饺律,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親跺株。 傳聞我的和親對(duì)象是個(gè)殘疾皇子复濒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353