緩存數(shù)據(jù)更新與飽和替換的設(shè)計(jì)模式

1- 緩存與數(shù)據(jù)庫(kù)

應(yīng)用程序通常使用緩存來(lái)提高系統(tǒng)系能,特別是對(duì)于只讀事務(wù)來(lái)說(shuō)。當(dāng)數(shù)據(jù)發(fā)生變化時(shí)筹裕,這些應(yīng)用程序會(huì)直接更新數(shù)據(jù)庫(kù)醋闭。問(wèn)題在于隨著負(fù)載的增加,響應(yīng)時(shí)間將會(huì)增加朝卒,響應(yīng)時(shí)間將隨著更新的增長(zhǎng)而延長(zhǎng)证逻。關(guān)系型數(shù)據(jù)庫(kù)其實(shí)并不擅長(zhǎng)大量處理少量記錄的并發(fā)事務(wù)(多而分散),處理批量事務(wù)才是數(shù)據(jù)庫(kù)的強(qiáng)項(xiàng)(少而集中)抗斤。

1.1- 緩存更新的必要性

由于硬件內(nèi)存空間的限制囚企,以及滿足JVM的空余內(nèi)存空間的限制,內(nèi)存中緩存的數(shù)據(jù)的上限是一定的豪治,所以需要不停的釋放舊數(shù)據(jù)洞拨,才能持續(xù)不斷的加載數(shù)據(jù)到內(nèi)存

1.2- 緩存的實(shí)現(xiàn)方式

JVM 堆內(nèi)存的實(shí)現(xiàn) 基于SoftReference或者WeakReference

使用堆內(nèi)存實(shí)現(xiàn)的方式,其緩存大小受制于JVM堆空間的大小

內(nèi)存服務(wù)器如Redis

不受JVM堆內(nèi)存大小的限制负拟,但是受制于操作系統(tǒng)總的內(nèi)存大小的限制。

2- 緩存更新的設(shè)計(jì)模式

當(dāng)數(shù)據(jù)時(shí)效性要求很高時(shí)歹河,需要保證緩存中的數(shù)據(jù)與緩存中的保持一致掩浙,而且需要保證緩存節(jié)點(diǎn)和副本中的數(shù)據(jù)也保持一致,不能出現(xiàn)差異現(xiàn)象秸歧。這就比較依賴緩存的過(guò)期和更新策略厨姚。一般會(huì)在數(shù)據(jù)發(fā)生更改的時(shí),主動(dòng)更新緩存中的數(shù)據(jù)或者移除對(duì)應(yīng)的緩存键菱。

2.1- 引子:在更新緩存時(shí)谬墙,到底是,先刪除緩存经备,然后再更新數(shù)據(jù)庫(kù)拭抬,還是先更新數(shù)據(jù)庫(kù),然后再刪除緩存侵蒙?
  1. 先刪后更:考慮并發(fā)的情況(只讀緩存):兩個(gè)并發(fā)請(qǐng)求造虎,一個(gè)是要更新操作,另一個(gè)是查詢操作纷闺,更新操作會(huì)致使當(dāng)前緩存失效算凿,刪除緩存后;這時(shí)查詢操作沒(méi)有命中緩存犁功,就會(huì)將數(shù)據(jù)庫(kù)中的數(shù)據(jù)讀出來(lái)放到緩存中氓轰,然后更新操作更新了數(shù)據(jù)庫(kù)。于是此時(shí)緩存中數(shù)據(jù)并不是更新操作的新值浸卦,而是原來(lái)的數(shù)據(jù)庫(kù)中的值署鸡。所以說(shuō)這種更新策略是錯(cuò)誤的
  2. 先更后刪:如果更新數(shù)據(jù)庫(kù)的時(shí)候,正好有讀請(qǐng)求到達(dá)储玫,此時(shí)讀到的數(shù)據(jù)將是臟數(shù)據(jù)侍筛,但是當(dāng)更新完數(shù)據(jù)庫(kù),會(huì)刪除舊的緩存撒穷,等下次讀請(qǐng)求到達(dá)時(shí)匣椰,沒(méi)有命中緩存,會(huì)從數(shù)據(jù)庫(kù)重新load到內(nèi)存中端礼,保證只出現(xiàn)因此臟數(shù)據(jù)禽笑,之后都是正確的數(shù)據(jù)

以下將介紹四種緩存更新的四種設(shè)計(jì)模式蛤奥,遵循最佳實(shí)踐少走彎路

Cache Aside Pattern(常用)
  • 失效:程序先從緩存中讀數(shù)據(jù)佳镜,沒(méi)有命中緩存,則程序從數(shù)據(jù)庫(kù)中l(wèi)oad到內(nèi)存中凡桥。
  • 命中:程序先從緩存中讀數(shù)據(jù)蟀伸,正好命中緩存,則程序?qū)⒕彺嬷械臄?shù)組直接返回缅刽。
  • 更新:程序?qū)懖僮飨劝褦?shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中啊掏,成功后,程序再讓緩存失效衰猛。(可能會(huì)出現(xiàn)幾次臟讀)
Read/Write Through Pattern(讀寫(xiě)穿透模式)

Cache Aside模式中迟蜜,同是要維護(hù)兩個(gè)數(shù)據(jù)存儲(chǔ),一個(gè)是緩存啡省,一個(gè)是數(shù)據(jù)庫(kù)娜睛。所以比較啰嗦。而 Read/Write Through模式是將把數(shù)據(jù)庫(kù)的操作由緩存自己代理了卦睹,所以就將緩存和數(shù)據(jù)庫(kù)的操作合并在一次畦戒,對(duì)于數(shù)據(jù)訪問(wèn)來(lái)說(shuō)面對(duì)的是單一存儲(chǔ),所以對(duì)于存儲(chǔ)來(lái)說(shuō)要同時(shí)維護(hù)自己的緩存分预。

Read Through

讀操作中更新緩存:用緩存服務(wù)自己加載兢交,對(duì)程序調(diào)用來(lái)說(shuō)是透明的(不許要像Cache Aside模式程序還要自己加載數(shù)據(jù)到緩存),當(dāng)讀操作沒(méi)有命中緩存時(shí)將觸發(fā)Read Through

Write Through

寫(xiě)操作中更新緩存:當(dāng)數(shù)據(jù)進(jìn)行更新時(shí)笼痹,如果沒(méi)有命中緩存配喳,直接更新數(shù)據(jù)庫(kù),然后返回凳干。如果命中了緩存晴裹,則更新緩存,然后再由緩存自己更新數(shù)據(jù)庫(kù)(這是同步操作)

Write Behind Caching Pattern

在更新數(shù)據(jù)的時(shí)候救赐,只更新緩存涧团,不更新數(shù)據(jù)庫(kù)只磷,而我們的緩存會(huì)異步地批量更新數(shù)據(jù)庫(kù),優(yōu)點(diǎn)是將緩存與數(shù)據(jù)庫(kù)的同步異步化泌绣,帶來(lái)飛快的數(shù)據(jù)I/O操作钮追,而且可以將數(shù)據(jù)庫(kù)的讀寫(xiě)合并,所以對(duì)性能的會(huì)有較大的顯著(特別是大數(shù)據(jù)量阿迈,數(shù)據(jù)庫(kù)讀寫(xiě)成為性能瓶頸你能過(guò)得時(shí)候)元媚,當(dāng)緩存需要失效的時(shí)候,才會(huì)真正的進(jìn)行持久化苗沧。

可能會(huì)出現(xiàn)數(shù)據(jù)不一致的情況:當(dāng)系統(tǒng)掉電刊棕,緩存中數(shù)據(jù)還沒(méi)有來(lái)得及寫(xiě)到數(shù)據(jù)庫(kù),則會(huì)造成一定的數(shù)據(jù)丟失待逞,數(shù)據(jù)不是強(qiáng)一致的甥角。但是性能和強(qiáng)一致性往往需要權(quán)衡。

注意
  1. 上面的緩存更新的設(shè)計(jì)模式還沒(méi)有考慮緩存和數(shù)據(jù)庫(kù)的整體事務(wù)的問(wèn)題识樱,比如更新了緩存嗤无,但是數(shù)據(jù)庫(kù)更新失敗了怎么辦?或者數(shù)據(jù)庫(kù)更新失敗牺荠,但是緩存load失敗了怎么辦翁巍?解決方法是就是使用“兩階段提交協(xié)議”——prepare,commit/rollback休雌。當(dāng)然這樣保證數(shù)據(jù)強(qiáng)一致性將導(dǎo)致性能的下降,實(shí)際設(shè)計(jì)時(shí)還需要權(quán)衡一下肝断。
  2. 從上面的緩存更新的策略杈曲,也能看出來(lái)當(dāng)只是查詢數(shù)據(jù)時(shí),緩存能抵擋絕大多數(shù)的DB查詢胸懈,但是如果都是插入或者修改的操作業(yè)務(wù)(如秒殺等)担扑,每一次都將命中DB,這時(shí)候?yàn)榱似交查g并發(fā)DB操作趣钱,應(yīng)該采用異步+消息隊(duì)列的形式涌献,或者使用Write Behind Caching Pattern。不管使用哪種方式首有,必須保證高可用燕垃,實(shí)時(shí)的將內(nèi)存操作的數(shù)據(jù)刷盤(pán)。

3- 緩存飽和替換策略

探討的是緩存中的數(shù)據(jù)達(dá)到緩存設(shè)定的內(nèi)存使用上限井联,新插入的數(shù)據(jù)時(shí)卜壕,替選擇什么樣的原來(lái)的舊數(shù)據(jù)來(lái)替換的問(wèn)題。

  1. Least Frequently Used(LFU)

每個(gè)緩存對(duì)象計(jì)算他們被使用的頻率烙常,把最不常用的緩存對(duì)象替換掉轴捎。

  1. Least Recently User(LRU):

把最近最少使用的緩存對(duì)象給替換,實(shí)現(xiàn)上會(huì)把最新被訪問(wèn)的緩存對(duì)象,放到緩存隊(duì)列的頂部侦副,可基于array 或者是LinkedHashMap來(lái)實(shí)現(xiàn)侦锯。

  1. Least Recently Used 2(LRU2):

也叫最近最少使用 twice。把被兩次訪問(wèn)過(guò)的對(duì)象放入緩存隊(duì)列中秦驯,當(dāng)緩存池滿了之后尺碰,會(huì)把有兩次最少使用的緩存對(duì)象替換掉。因?yàn)樾枰檶?duì)象2次汇竭,訪問(wèn)負(fù)載就會(huì)隨著緩存池的增加而增加葱蝗。在大容量的緩存池中,就會(huì)有較高性能開(kāi)銷問(wèn)題细燎。另外两曼,還需要跟蹤那些不在緩存的對(duì)象,因?yàn)樗麄冞€沒(méi)有被第二次讀取玻驻。效果比LRU好悼凑,但是性能開(kāi)銷也大。

  1. Two Queues(2Q):

把被訪問(wèn)的數(shù)據(jù)放到 LRU 的緩存中璧瞬,如果這個(gè)對(duì)象再一次被訪問(wèn)户辫,我就把他轉(zhuǎn)移到第二個(gè)、更大的 LRU 緩存嗤锉。轉(zhuǎn)移緩存對(duì)象是為了保持第一個(gè)緩存池是第二個(gè)緩存池的1/3渔欢。當(dāng)緩存的訪問(wèn)負(fù)載是固定的時(shí)候,把 LRU 換成 LRU2瘟忱,就比增加緩存的容量更好奥额。這種機(jī)制使得我比 LRU2 更好,改善了LRU2的性能访诱。

  1. Adaptive Replacement Cache(ARC):

介于 LRU 和 LFU 之間垫挨,為了提高效果。由2個(gè) LRU 組成: L1触菜,包含的條目是最近只被使用過(guò)一次的九榔; L2,包含的是最近被使用過(guò)兩次的條目涡相。因此哲泊, L1 放的是新的對(duì)象,而 L2 放的是常用的對(duì)象漾峡。被認(rèn)為是性能最好的緩存算法之一攻旦,能夠自調(diào),并且是低負(fù)載的生逸、很快牢屋,適用性也強(qiáng)且预。

  1. Most Recently Used(MRU):

和 LRU 相對(duì)應(yīng)會(huì)移除最近最多被使用的對(duì)象。作用:接下來(lái)訪問(wèn)的隨機(jī)性烙无,并且在緩存系統(tǒng)中找出最少最近使用的對(duì)象是一項(xiàng)時(shí)間復(fù)雜度非常高的運(yùn)算锋谐,這就是MRU存在的原因。

  1. First in First out(FIFO):

先進(jìn)先出截酷,是一個(gè)低負(fù)載的算法涮拗,并且對(duì)緩存對(duì)象的管理要求不高。通過(guò)一個(gè)隊(duì)列去跟蹤所有的緩存對(duì)象迂苛,最近最常用的緩存對(duì)象放在后面三热,而更早的緩存對(duì)象放在前面,當(dāng)緩存容量滿時(shí)三幻,排在前面的緩存對(duì)象會(huì)被替換就漾,然后把新的緩存對(duì)象加進(jìn)去。很快念搬,但是并不適用抑堡。

  1. Second Chance:

通過(guò) FIFO 修改而來(lái)的,改善了 FIFO 的成本朗徊。在替換緩存首妖,移除隊(duì)首元素式,會(huì)檢查即將要被移除的對(duì)象有沒(méi)有之前被使用過(guò)的標(biāo)志(1一個(gè) bit 表示)爷恳,沒(méi)有被使用過(guò)有缆,就把他移除;否則温亲,會(huì)把這個(gè)標(biāo)志位清除妒貌,然后把這個(gè)緩存對(duì)象當(dāng)做新增緩存對(duì)象加入隊(duì)列。這就像一個(gè)環(huán)隊(duì)列铸豁。當(dāng)再一次在隊(duì)頭碰到這個(gè)對(duì)象時(shí),由于他已經(jīng)沒(méi)有這個(gè)標(biāo)志位了菊碟,所以立刻就把他踢開(kāi)了节芥,在速度上比 FIFO 快。

  1. CLock

持有一個(gè)裝有緩存對(duì)象的環(huán)形列表逆害,頭指針指向列表中最老的緩存對(duì)象头镊。當(dāng)緩存 miss 發(fā)生并且沒(méi)有新的緩存空間時(shí),會(huì)問(wèn)問(wèn)指針指向的緩存對(duì)象的標(biāo)志位去決定應(yīng)該怎么做魄幕。如果標(biāo)志是0相艇,我會(huì)直接用新的緩存對(duì)象替代這個(gè)緩存對(duì)象;如果標(biāo)志位是1纯陨,會(huì)把頭指針遞增坛芽,然后重復(fù)這個(gè)過(guò)程留储,直到新的緩存對(duì)象能夠被放入,比 second chance 更快咙轩。

  1. Simple time-based:

通過(guò)絕對(duì)的時(shí)間周期去失效那些緩存對(duì)象获讳。對(duì)于新增的對(duì)象,會(huì)保存特定的時(shí)間活喊。很快丐膝,但是并不適用。

  1. Extended time-based expiration:

通過(guò)相對(duì)時(shí)間去失效緩存對(duì)象的钾菊;對(duì)于新增的緩存對(duì)象帅矗,會(huì)保存特定的時(shí)間,比如是每5分鐘煞烫,每天的12點(diǎn)浑此。

  1. Sliding time-based expiration:

與前面不同的是,被管理的緩存對(duì)象的生命起點(diǎn)是在這個(gè)緩存的最后被訪問(wèn)時(shí)間算起的红竭,很快尤勋,但是也不太適用。

其他需要注意的:
  1. 成本:如果緩存對(duì)象有不同的成本茵宪,應(yīng)該把那些難以獲得的對(duì)象保存下來(lái)最冰。

  2. 容量:如果緩存對(duì)象有不同的大小,應(yīng)該把那些大的緩存對(duì)象清除稀火,這樣就可以讓更多的小緩存對(duì)象進(jìn)來(lái)了暖哨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凰狞,隨后出現(xiàn)的幾起案子篇裁,更是在濱河造成了極大的恐慌,老刑警劉巖赡若,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件达布,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡逾冬,警方通過(guò)查閱死者的電腦和手機(jī)黍聂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)身腻,“玉大人产还,你說(shuō)我怎么就攤上這事∴痔耍” “怎么了脐区?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)她按。 經(jīng)常有香客問(wèn)我牛隅,道長(zhǎng)炕柔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任倔叼,我火速辦了婚禮汗唱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丈攒。我一直安慰自己哩罪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布巡验。 她就那樣靜靜地躺著际插,像睡著了一般。 火紅的嫁衣襯著肌膚如雪显设。 梳的紋絲不亂的頭發(fā)上框弛,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音捕捂,去河邊找鬼瑟枫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛指攒,可吹牛的內(nèi)容都是我干的慷妙。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼允悦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼膝擂!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起隙弛,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤架馋,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后全闷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體叉寂,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年总珠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了办绝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姚淆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屡律,到底是詐尸還是另有隱情腌逢,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布超埋,位于F島的核電站搏讶,受9級(jí)特大地震影響佳鳖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜媒惕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一系吩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妒蔚,春花似錦穿挨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至菜皂,卻和暖如春贞绵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恍飘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工榨崩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人章母。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓母蛛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胳施。 傳聞我的和親對(duì)象是個(gè)殘疾皇子溯祸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,846評(píng)論 25 707
  • 需要原文的可以留下郵箱我給你發(fā),這里的文章少了很多圖舞肆,懶得網(wǎng)上粘啦 1數(shù)據(jù)庫(kù)基礎(chǔ) 1.1數(shù)據(jù)庫(kù)定義 1)數(shù)據(jù)庫(kù)(D...
    極簡(jiǎn)純粹_閱讀 7,406評(píng)論 0 46
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理焦辅,服務(wù)發(fā)現(xiàn),斷路器椿胯,智...
    卡卡羅2017閱讀 134,637評(píng)論 18 139
  • 作者:清風(fēng)悲秋云冷漠的籠罩在山谷夜也不會(huì)再離去了此時(shí)已經(jīng)入冬一切又趨于平靜 沒(méi)有誰(shuí)會(huì)留在這山谷里農(nóng)夫壓彎腰挑去稻子...
    清風(fēng)悲秋閱讀 336評(píng)論 0 0
  • 生活中總是不缺這樣的人:他們覺(jué)得生活哪哪都不如意哩盲,卻又不愿意做出改變前方。他們負(fù)能量爆棚,整天把憤懣的槍口對(duì)準(zhǔn)別人廉油,覺(jué)...
    不等于閱讀 496評(píng)論 4 2