快取的設計方式

語言: CN / TW / HK

theme: scrolls-light

問題情況:

當有大量的請求到內部系統時,若每一個請求都需要我們操作資料庫,例如查詢操作,那麼對於那種資料基本不怎麼變動的資料來說,每一次都去資料庫裡面查詢,是很消耗我們的效能

尤其是對於在海量資料中進行資料操作的時候,如果都是從 DB 中進行載入,那這是在挑戰使用者的耐性

簡單來看,例如我們要去小區裡面瞭解一個人在不在家,當沒有通訊工具的前提下,我們每一次都要經過小區們的保安,然後再到具體的單元樓,最終到了這家門口,最終才知道在不在家

如果我們換了一個比較優秀的保安,他知道當前小區裡面的特定的家裡面是否有人,那這個時候,如果我們直接去問小區保安,自然就無需跑冤枉路了,自然就提高了效率

此處簡單的就可以將優秀保安看做是一個快取,我們每一次去訪問,就會先去訪問快取 , 這樣就能極大的提高訪問效率和系統性能

可以看出,有一個優秀的保安相當重要

快取的基本設計方式是什麼樣的

設計快取自然也是為了解決系統是的低效問題,讓系統可以高效能,高併發

例如我們直接訪問單機的資料庫如mysql 也就是上千級別的 qps,如果是訪問 快取的時候,就能達到上萬,上十幾萬,這差距不是一點半點,是一個質的飛越

快取的設計實際上就是 DB 和 快取操作順序以及誰來操作的事情,大體分為如下 4 種模式

  • Cache Aside
  • Read Through
  • Write Through
  • Write Behind Caching

上述四種模式, Cache Aside 用的方式是最常使用的,咱們後續細說

後續三種模式的含義是

Read Through

  • 是在查詢操作的時候更新快取,若快取失效了,則是由快取伺服器自己將資料載入到快取中

Write Through

  • 是在更新資料庫的時候,如果命中了快取,則先更新快取,再由快取伺服器自己去更新資料,
  • 如果是沒有命中快取,那麼就直接更新資料庫

Write Behind Caching 通過名字我們知道,是在寫到快取操作之後才做些操作,實際上這種模式只更新快取,不會更新資料庫,快取伺服器會以非同步的方式將資料批量更新到資料庫中

很明顯,這種,模式速度自然會更快,可這種模式對於保證資料庫和快取資料一致性問題,是個硬傷,且還會存在丟資料的情況,比如,咱們的快取伺服器掛掉了

Cache Aside 讀寫快取模式是怎麼玩的

Cache Aside 讀寫模式快取又是如何去處理的呢,一起來看看

Cache Aside 模式讀取資料的邏輯是這個樣子的:

讀取資料時

  • 先讀取快取中的資料,如果快取中有資料,則直接返回
  • 若快取中沒有資料,則去讀資料庫中的資料,並將資料同步到快取中

寫入資料時

  • 寫入資料庫,寫入成功時,將快取的資料刪除掉

仔細的同學可能會思考並提出這樣的問題,如果我一個查詢操作,現在快取中無資料,此時會去資料庫中查詢,在這個過程中,另外有一個寫入資料庫的操作,且操作完畢後,刪除了快取,這個時候,第一個操作實際上從資料庫拿到的還是之前的老資料,並且會將資料放到快取中,那麼此時的資料實際上是一個老資料,也可以理解是在髒資料

這個點其實我們就無需擔心了,大佬們已經論證過這種情況出現的概率極低

因為咱們的寫表操作是要鎖表的,且我們知道資料庫寫入操作比讀取操作要慢,也就是說,當同時有一個讀取和寫入 DB 的操作時,自然是寫入的操作是要後返回結果的,此處不要槓啥讀寫資料量不一致的情況,咱們做對比,自然是在同等條件下比較咯

從圖中我們知道,同等條件下,先進行查詢 DB 的操作,過程中,來了一個寫入 DB 操作,自然是 查詢操作先返回,寫入操作再返回結果

其實此處,有的做法是,寫入資料的時候,寫入成功,同時也會將資料同步到快取中

那麼這種方式的引入,實際上從資料庫到快取就有了 2 種情況了,一個是查詢操作,一個是寫入操作,那麼在實際操作中,我是可以加入分散式鎖來進行處理,保證寫入資料庫的時候,同時也要寫入快取,資料才可訪問,當然查詢 DB 操作也是一樣

快取帶來了哪些問題?

那麼引入快取除了可以帶來高效能,高併發,自然也是有會帶來一些問題的,例如:

  • 快取擊穿
  • 快取穿透
  • 快取雪崩

如上 3 中情況,都是由於快取這一層防線失守了,導致外部請求以各種各樣的形式,各種各樣的原因打到了資料庫上,導致出現的問題,詳細的 快取擊穿,快取穿透,快取雪崩的出現情況,解決方式可以檢視歷史文章 redis 快取穿透,快取擊穿,快取雪崩

感謝閱讀,歡迎交流,點個贊,關注一波 再走吧

我正在參與掘金技術社群創作者簽約計劃招募活動,點選連結報名投稿