天天看點

面試官:3 種緩存更新政策是怎樣的?

作者:小林coding

計算機八股文網站:https://xiaolincoding.com

大家好,我是小林。

今天跟大家聊聊,常見的緩存更新政策。

  • Cache Aside(旁路緩存)政策;
  • Read/Write Through(讀穿 / 寫穿)政策;
  • Write Back(寫回)政策;

實際開發中,Redis 和 MySQL 的更新政策用的是 Cache Aside,另外兩種政策主要應用在計算機系統裡。

Cache Aside(旁路緩存)政策

Cache Aside(旁路緩存)政策是最常用的,應用程式直接與「資料庫、緩存」互動,并負責對緩存的維護,該政策又可以細分為「讀政策」和「寫政策」。

面試官:3 種緩存更新政策是怎樣的?

寫政策的步驟:

  • 先更新資料庫中的資料,再删除緩存中的資料。

讀政策的步驟:

  • 如果讀取的資料命中了緩存,則直接傳回資料;
  • 如果讀取的資料沒有命中緩存,則從資料庫中讀取資料,然後将資料寫入到緩存,并且傳回給使用者。

注意,寫政策的步驟的順序順序不能倒過來,即不能先删除緩存再更新資料庫,原因是在「讀+寫」并發的時候,會出現緩存和資料庫的資料不一緻性的問題。

舉個例子,假設某個使用者的年齡是 20,請求 A 要更新使用者年齡為 21,是以它會删除緩存中的内容。這時,另一個請求 B 要讀取這個使用者的年齡,它查詢緩存發現未命中後,會從資料庫中讀取到年齡為 20,并且寫入到緩存中,然後請求 A 繼續更改資料庫,将使用者的年齡更新為 21。

面試官:3 種緩存更新政策是怎樣的?

最終,該使用者年齡在緩存中是 20(舊值),在資料庫中是 21(新值),緩存和資料庫的資料不一緻。

為什麼「先更新資料庫再删除緩存」不會有資料不一緻的問題?

繼續用「讀 + 寫」請求的并發的場景來分析。

假如某個使用者資料在緩存中不存在,請求 A 讀取資料時從資料庫中查詢到年齡為 20,在未寫入緩存中時另一個請求 B 更新資料。它更新資料庫中的年齡為 21,并且清空緩存。這時請求 A 把從資料庫中讀到的年齡為 20 的資料寫入到緩存中。

面試官:3 種緩存更新政策是怎樣的?

最終,該使用者年齡在緩存中是 20(舊值),在資料庫中是 21(新值),緩存和資料庫資料不一緻。 從上面的理論上分析,先更新資料庫,再删除緩存也是會出現資料不一緻性的問題,但是在實際中,這個問題出現的機率并不高。

因為緩存的寫入通常要遠遠快于資料庫的寫入,是以在實際中很難出現請求 B 已經更新了資料庫并且删除了緩存,請求 A 才更新完緩存的情況。而一旦請求 A 早于請求 B 删除緩存之前更新了緩存,那麼接下來的請求就會因為緩存不命中而從資料庫中重新讀取資料,是以不會出現這種不一緻的情況。

Cache Aside 政策适合讀多寫少的場景,不适合寫多的場景,因為當寫入比較頻繁時,緩存中的資料會被頻繁地清理,這樣會對緩存的命中率有一些影響。如果業務對緩存命中率有嚴格的要求,那麼可以考慮兩種解決方案:

  • 一種做法是在更新資料時也更新緩存,隻是在更新緩存前先加一個分布式鎖,因為這樣在同一時間隻允許一個線程更新緩存,就不會産生并發問題了。當然這麼做對于寫入的性能會有一些影響;
  • 另一種做法同樣也是在更新資料時更新緩存,隻是給緩存加一個較短的過期時間,這樣即使出現緩存不一緻的情況,緩存的資料也會很快過期,對業務的影響也是可以接受。

Read/Write Through(讀穿 / 寫穿)政策

Read/Write Through(讀穿 / 寫穿)政策原則是應用程式隻和緩存互動,不再和資料庫互動,而是由緩存和資料庫互動,相當于更新資料庫的操作由緩存自己代理了。

Read Through 政策

先查詢緩存中資料是否存在,如果存在則直接傳回,如果不存在,則由緩存元件負責從資料庫查詢資料,并将結果寫入到緩存元件,最後緩存元件将資料傳回給應用。

Write Through 政策

當有資料更新的時候,先查詢要寫入的資料在緩存中是否已經存在:

  • 如果緩存中資料已經存在,則更新緩存中的資料,并且由緩存元件同步更新到資料庫中,然後緩存元件告知應用程式更新完成。
  • 如果緩存中資料不存在,直接更新資料庫,然後傳回;

下面是 Read Through/Write Through 政策的示意圖:

面試官:3 種緩存更新政策是怎樣的?

Read Through/Write Through 政策的特點是由緩存節點而非應用程式來和資料庫打交道,在我們開發過程中相比 Cache Aside 政策要少見一些,原因是我們經常使用的分布式緩存元件,無論是 Memcached 還是 Redis 都不提供寫入資料庫和自動加載資料庫中的資料的功能。而我們在使用本地緩存的時候可以考慮使用這種政策。

Write Back(寫回)政策

Write Back(寫回)政策在更新資料的時候,隻更新緩存,同時将緩存資料設定為髒的,然後立馬傳回,并不會更新資料庫。對于資料庫的更新,會通過批量異步更新的方式進行。

實際上,Write Back(寫回)政策也不能應用到我們常用的資料庫和緩存的場景中,因為 Redis 并沒有異步更新資料庫的功能。

Write Back 是計算機體系結構中的設計,比如 CPU 的緩存、作業系統中檔案系統的緩存都采用了 Write Back(寫回)政策。

Write Back 政策特别适合寫多的場景,因為發生寫操作的時候, 隻需要更新緩存,就立馬傳回了。比如,寫檔案的時候,實際上是寫入到檔案系統的緩存就傳回了,并不會寫磁盤。

但是帶來的問題是,資料不是強一緻性的,而且會有資料丢失的風險,因為緩存一般使用記憶體,而記憶體是非持久化的,是以一旦緩存機器掉電,就會造成原本緩存中的髒資料丢失。是以你會發現系統在掉電之後,之前寫入的檔案會有部分丢失,就是因為 Page Cache 還沒有來得及刷盤造成的。

這裡貼一張 CPU 緩存與記憶體使用 Write Back 政策的流程圖:

面試官:3 種緩存更新政策是怎樣的?

有沒有覺得這個流程很熟悉?因為我在寫 CPU 緩存文章的時候提到過。

系列《圖解Redis》文章

面試篇:

  • 3 萬字 + 40 張圖 | 攻破 40 道 Redis 常見面試題

資料類型篇:

  • 2 萬字 + 30 張圖 | 細說 Redis 九種資料類型和應用場景
  • 2 萬字 + 40 張圖 | 圖解 Redis 九種資料結構的實作

持久化篇:

  • AOF 持久化是怎麼實作的?
  • RDB 快照是怎麼實作的?

功能篇:

  • Redis 過期删除政策和記憶體淘汰政策有什麼差別?

高可用篇:

  • 主從複制是怎麼實作的?
  • 為什麼要有哨兵?

緩存篇:

  • 什麼是緩存雪崩、擊穿、穿透?
  • 資料庫和緩存如何保證一緻性?

微信搜尋公衆号:「小林coding」 ,回複「圖解」即可免費獲得「圖解網絡、圖解系統、圖解MySQL、圖解Redis」PDF 電子書