System Design 緩存 - 學(xué)習(xí)筆記

引用:
系統(tǒng)設(shè)計(jì)入門
緩存架構(gòu)設(shè)計(jì)細(xì)節(jié)二三事

有哪些緩存級(jí)別

客戶端緩存

緩存可以位于客戶端(操作系統(tǒng)或者瀏覽器)。

CDN 緩存

CDN 也被視為一種緩存悯嗓。

CDN邊緣節(jié)點(diǎn)緩存策略因服務(wù)商不同而不同拒迅,但一般都會(huì)遵循 HTTP 標(biāo)準(zhǔn)協(xié)議骚秦,通過 HTTP 響應(yīng)頭中的 Cache-control: max-age 的字段來設(shè)置CDN邊緣節(jié)點(diǎn)數(shù)據(jù)緩存時(shí)間。

當(dāng)客戶端向CDN節(jié)點(diǎn)請(qǐng)求數(shù)據(jù)時(shí)璧微,CDN節(jié)點(diǎn)會(huì)判斷緩存數(shù)據(jù)是否過期作箍,若緩存數(shù)據(jù)并沒有過期,則直接將緩存數(shù)據(jù)返回給客戶端前硫;否則胞得,CDN節(jié)點(diǎn)就會(huì)向源站發(fā)出回源請(qǐng)求,從源站拉取最新數(shù)據(jù)开瞭,更新本地緩存懒震,并將最新數(shù)據(jù)返回給客戶端。

CDN服務(wù)商一般會(huì)提供基于文件后綴嗤详、目錄多個(gè)維度來指定CDN緩存時(shí)間,為用戶提供更精細(xì)化的緩存管理瓷炮。

CDN緩存時(shí)間會(huì)對(duì)“回源率”產(chǎn)生直接的影響葱色。若CDN緩存時(shí)間較短,CDN邊緣節(jié)點(diǎn)上的數(shù)據(jù)會(huì)經(jīng)常失效娘香,導(dǎo)致頻繁回源苍狰,增加了源站的負(fù)載,同時(shí)也增大的訪問延時(shí)烘绽;若CDN緩存時(shí)間太長(zhǎng)淋昭,會(huì)帶來數(shù)據(jù)更新時(shí)間慢的問題。開發(fā)者需要增對(duì)特定的業(yè)務(wù)安接,來做特定的數(shù)據(jù)緩存時(shí)間管理翔忽。

Web 服務(wù)器緩存

反向代理和緩存可以直接提供靜態(tài)和動(dòng)態(tài)內(nèi)容。Web 服務(wù)器同樣也可以緩存請(qǐng)求盏檐,返回相應(yīng)結(jié)果而不必連接應(yīng)用服務(wù)器歇式。

參見 NGINX緩存使用官方指南

數(shù)據(jù)庫(kù)緩存

數(shù)據(jù)庫(kù)的默認(rèn)配置中通常包含緩存級(jí)別,針對(duì)一般用例進(jìn)行了優(yōu)化胡野。調(diào)整配置材失,在不同情況下使用不同的模式可以進(jìn)一步提高性能。

當(dāng)有很多相同的查詢被執(zhí)行了多次的時(shí)候硫豆,這些查詢結(jié)果會(huì)被放到一個(gè)緩存中龙巨。
這樣笼呆,后續(xù)的相同的查詢就不用操作表而直接訪問緩存結(jié)果了。

// 查詢緩存不開啟
$r = mysql_query("SELECT * FROM student WHERE signup_date = CURDATE()");

// 開啟查詢緩存
$today = date("Y-m-d");
$r = mysql_query("SELECT * FROM student WHERE signup_date = '$today'");

像 CURDATE(), NOW() 和 RAND() 或是其它的諸如此類的SQL函數(shù)都不會(huì)開啟查詢緩存旨别。
因?yàn)檫@些函數(shù)的返回值是不定的诗赌。

應(yīng)用緩存

基于內(nèi)存的緩存比如 Memcached 和 Redis 是應(yīng)用程序和數(shù)據(jù)存儲(chǔ)之間的一種鍵值存儲(chǔ)。由于數(shù)據(jù)保存在 RAM 中昼榛,它比存儲(chǔ)在磁盤上的典型數(shù)據(jù)庫(kù)要快多了境肾。

Redis 有下列附加功能:

  • 持久性選項(xiàng)
  • 內(nèi)置數(shù)據(jù)結(jié)構(gòu)比如有序集合和列表

參見 Spring 緩存開發(fā)實(shí)踐 & Redis 集成

何時(shí)更新緩存

由于你只能在緩存中存儲(chǔ)有限的數(shù)據(jù),所以你需要選擇一個(gè)適用于你用例的緩存更新策略胆屿。

緩存模式

緩存模式

應(yīng)用從存儲(chǔ)器讀寫邢羔。緩存不和存儲(chǔ)器直接交互躏率,應(yīng)用執(zhí)行以下操作:

  • 在緩存中查找記錄,如果所需數(shù)據(jù)不在緩存中
  • 從數(shù)據(jù)庫(kù)中加載所需內(nèi)容
  • 將查找到的結(jié)果存儲(chǔ)到緩存中
  • 返回所需內(nèi)容

Memcached 通常用這種方式使用。
添加到緩存中的數(shù)據(jù)讀取速度很快攘轩。緩存模式也稱為延遲加載。只緩存所請(qǐng)求的數(shù)據(jù)撑蚌,這避免了沒有被請(qǐng)求的數(shù)據(jù)占滿了緩存空間挠说。

缺點(diǎn):

  • 請(qǐng)求的數(shù)據(jù)如果不在緩存中就需要經(jīng)過三個(gè)步驟來獲取數(shù)據(jù),這會(huì)導(dǎo)致明顯的延遲纯命。
  • 如果數(shù)據(jù)庫(kù)中的數(shù)據(jù)更新了會(huì)導(dǎo)致緩存中的數(shù)據(jù)過時(shí)西剥。這個(gè)問題需要通過設(shè)置TTL強(qiáng)制更新緩存或者直寫模式來緩解這種情況。

直寫模式

直寫模式

應(yīng)用使用緩存作為主要的數(shù)據(jù)存儲(chǔ)亿汞,將數(shù)據(jù)讀寫到緩存中瞭空,而緩存負(fù)責(zé)從數(shù)據(jù)庫(kù)中讀寫數(shù)據(jù):

  • 應(yīng)用向緩存中添加/更新數(shù)據(jù)
  • 緩存同步地寫入數(shù)據(jù)存儲(chǔ)
  • 返回所需內(nèi)容

由于存寫操作所以直寫模式整體是一種很慢的操作,但是讀取剛寫入的數(shù)據(jù)很快疗我。相比讀取數(shù)據(jù)咆畏,用戶通常比較能接受更新數(shù)據(jù)時(shí)速度較慢。緩存中的數(shù)據(jù)不會(huì)過時(shí)吴裤。

缺點(diǎn):

  • 由于故障或者縮放而創(chuàng)建的新的節(jié)點(diǎn)旧找,新的節(jié)點(diǎn)不會(huì)緩存,直到數(shù)據(jù)庫(kù)更新為止麦牺。

回寫模式

回寫模式

在回寫模式中钮蛛,應(yīng)用執(zhí)行以下操作:

  • 在緩存中增加或者更新條目
  • 異步寫入數(shù)據(jù),提高寫入性能枕面。

缺點(diǎn):

  • 緩存可能在其內(nèi)容成功存儲(chǔ)之前丟失數(shù)據(jù)愿卒。

緩存的缺點(diǎn):

  • 需要保持緩存和真實(shí)數(shù)據(jù)源之間的一致性。
  • 需要改變應(yīng)用程序比如增加 Redis 或者 memcached潮秘。
  • 無(wú)效緩存是個(gè)難題琼开,什么時(shí)候更新緩存是與之相關(guān)的復(fù)雜問題。

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

緩存是一種提高系統(tǒng)讀性能的常見技術(shù)枕荞,對(duì)于讀多寫少的應(yīng)用場(chǎng)景柜候,我們經(jīng)常使用緩存來進(jìn)行優(yōu)化搞动。
例如對(duì)于用戶的余額信息表 account(uid, money),業(yè)務(wù)上的需求是:

  1. 查詢用戶的余額渣刷,SELECT money FROM account WHERE uid=XXX鹦肿,占 99% 的請(qǐng)求
  • 更改用戶余額,UPDATE account SET money=XXX WHERE uid=XXX辅柴,占 1% 的請(qǐng)求

由于大部分的請(qǐng)求是查詢箩溃,我們?cè)诰彺嬷薪?uidmoney 的鍵值對(duì)(uid -> money),能夠極大降低數(shù)據(jù)庫(kù)的壓力碌嘀。

讀操作流程:

  1. 讀取緩存中是否有相關(guān)數(shù)據(jù)涣旨,uid -> money
  • 如果緩存中有相關(guān)數(shù)據(jù) money,則返回【數(shù)據(jù)命中 hit】
  • 如果緩存中沒有相關(guān)數(shù)據(jù) money股冗,則從數(shù)據(jù)庫(kù)讀取相關(guān)數(shù)據(jù) money【數(shù)據(jù)未命中 miss】霹陡,放入緩存中 uid -> money,再返回
    緩存的命中率 = 命中緩存請(qǐng)求個(gè)數(shù)/總緩存訪問請(qǐng)求個(gè)數(shù) = hit / (hit + miss)

問題來了:
當(dāng)余額數(shù)據(jù) money 發(fā)生變化的時(shí)候:

  1. 是更新緩存中的數(shù)據(jù)止状,還是淘汰緩存中的數(shù)據(jù)呢烹棉?
  • 是先操縱數(shù)據(jù)庫(kù)中的數(shù)據(jù)再操縱緩存中的數(shù)據(jù),還是先操縱緩存中的數(shù)據(jù)再操縱數(shù)據(jù)庫(kù)中的數(shù)據(jù)呢怯疤?
  • 緩存與數(shù)據(jù)庫(kù)的操作浆洗,在架構(gòu)上是否有優(yōu)化的空間呢?

是更新緩存中的數(shù)據(jù)集峦,還是淘汰緩存中的數(shù)據(jù)呢辅髓?

更新緩存

  • 數(shù)據(jù)不但寫入數(shù)據(jù)庫(kù),還會(huì)寫入緩存
  • 優(yōu)點(diǎn):緩存不會(huì)增加一次 cache miss少梁,命中率高

淘汰緩存

  • 數(shù)據(jù)只會(huì)寫入數(shù)據(jù)庫(kù),不會(huì)寫入緩存矫付,只會(huì)把數(shù)據(jù)淘汰掉
  • 優(yōu)點(diǎn):簡(jiǎn)單
  • 缺點(diǎn):增加了一次 cache miss

取決于 更新緩存的復(fù)雜度
例如凯沪,上述場(chǎng)景,只是簡(jiǎn)單的把余額 money 設(shè)置成一個(gè)值买优,那么:

  1. 淘汰緩存的操作為 deleteCache(uid)
  • 更新緩存的操作為 setCache(uid, money)

更新緩存的代價(jià)很小妨马,此時(shí)我們應(yīng)該更傾向于更新緩存,以保證更高的緩存命中率杀赢。

如果余額是通過很復(fù)雜的數(shù)據(jù)計(jì)算得出來的烘跺,例如業(yè)務(wù)上除了賬戶表 account,還有商品表 product脂崔,折扣表 discount滤淳。
業(yè)務(wù)場(chǎng)景是用戶買了一個(gè)商品 product,這個(gè)商品的價(jià)格是 price砌左,這個(gè)商品從屬于 type 類商品脖咐,type類商品在做促銷活動(dòng)要打折扣 zhekou铺敌,購(gòu)買了商品過后,這個(gè)余額的計(jì)算就復(fù)雜了屁擅,需要:

  1. 先把商品的品類偿凭,價(jià)格取出來:SELECT type, price FROM product WHERE pid=XXX
  • 再把這個(gè)品類的折扣取出來:SELECT zhekou FROM discount WHERE type=XXX
  • 再把原有余額從緩存中查詢出來 money = getCache(uid)
  • 再把新的余額寫入到緩存中去 setCache(uid, money - price * zhekou)

更新緩存的代價(jià)很大,此時(shí)我們應(yīng)該更傾向于淘汰緩存派歌。

先操作數(shù)據(jù)庫(kù) VS 先操作緩存

當(dāng)寫操作發(fā)生時(shí)弯囊,假設(shè) 淘汰緩存 作為對(duì)緩存通用的處理方式,又面臨兩種抉擇:

  1. 先寫數(shù)據(jù)庫(kù)胶果,再淘汰緩存
  • 先淘汰緩存匾嘱,再寫數(shù)據(jù)庫(kù)

對(duì)于一個(gè)不能保證事務(wù)性的操作,一定涉及 哪個(gè)任務(wù)先做稽物,哪個(gè)任務(wù)后做 的問題奄毡,解決這個(gè)問題的方向是:
如果出現(xiàn)不一致,誰(shuí)先做對(duì)業(yè)務(wù)的影響較小贝或,就誰(shuí)先執(zhí)行吼过。

假設(shè)先寫數(shù)據(jù)庫(kù),再淘汰緩存:

  1. 更新數(shù)據(jù)庫(kù)操作成功咪奖,將編號(hào) 001 的賬號(hào)的余額從 50 元更新為 100 元
  • 可是淘汰緩存操作失敗盗忱,緩存中是舊數(shù)據(jù) 50 元,從而造成了 數(shù)據(jù)不一致羊赵,用戶查詢時(shí)趟佃,在緩存中命中,返回 50 塊的錯(cuò)誤余額

結(jié)論是:應(yīng)該先淘汰緩存昧捷,再寫數(shù)據(jù)庫(kù)闲昭。
這樣即使第二步寫數(shù)據(jù)庫(kù)失敗,則只會(huì)引發(fā)一次 cache miss靡挥。

緩存架構(gòu)優(yōu)化

傳統(tǒng)架構(gòu):如下所示序矩。缺點(diǎn):業(yè)務(wù)方需要同時(shí)關(guān)注緩存與 數(shù)據(jù)庫(kù)。

傳統(tǒng)架構(gòu)

主流優(yōu)化方案是 服務(wù)化:加入一個(gè)服務(wù)層跋破,向上游提供數(shù)據(jù)訪問接口簸淀,向上游屏蔽底層數(shù)據(jù)存儲(chǔ)的細(xì)節(jié),這樣業(yè)務(wù)線不需要關(guān)注數(shù)據(jù)是來自于緩存還是數(shù)據(jù)庫(kù)毒返。

服務(wù)化架構(gòu)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末租幕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拧簸,更是在濱河造成了極大的恐慌劲绪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異珠叔,居然都是意外死亡蝎宇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門祷安,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姥芥,“玉大人,你說我怎么就攤上這事汇鞭×固疲” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵霍骄,是天一觀的道長(zhǎng)台囱。 經(jīng)常有香客問我,道長(zhǎng)读整,這世上最難降的妖魔是什么簿训? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮米间,結(jié)果婚禮上强品,老公的妹妹穿的比我還像新娘。我一直安慰自己屈糊,他們只是感情好的榛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逻锐,像睡著了一般夫晌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昧诱,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天晓淀,我揣著相機(jī)與錄音,去河邊找鬼盏档。 笑死要糊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妆丘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼局劲,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼勺拣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鱼填,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤药有,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愤惰,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苇经,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宦言。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扇单。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖奠旺,靈堂內(nèi)的尸體忽然破棺而出蜘澜,到底是詐尸還是另有隱情,我是刑警寧澤响疚,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布鄙信,位于F島的核電站,受9級(jí)特大地震影響忿晕,放射性物質(zhì)發(fā)生泄漏装诡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一践盼、第九天 我趴在偏房一處隱蔽的房頂上張望鸦采。 院中可真熱鬧,春花似錦宏侍、人聲如沸赖淤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)咱旱。三九已至,卻和暖如春绷耍,著一層夾襖步出監(jiān)牢的瞬間吐限,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工褂始, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诸典,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓崎苗,卻偏偏與公主長(zhǎng)得像狐粱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胆数,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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