快取架構設計細節二三事

2021-08-07 03:37:17 字數 3379 閱讀 1721

本文主要討論這麼幾個問題:

(1)「快取與資料庫」需求緣起

(2)「淘汰快取」還是「更新快取」

(3)快取和資料庫的操作時序

(4)快取和資料庫架構簡析

一、需求緣起

場景介紹

快取是一種提高系統讀效能的常見技術,對於讀多寫少的應用場景,我們經常使用快取來進行優化。

例如對於使用者的餘額資訊表account(uid, money),業務上的需求是:

(1)查詢使用者的餘額,select money from account where uid=***,佔99%的請求

(2)更改使用者餘額,update account set money=*** where uid=***,佔1%的請求

由於大部分的請求是查詢,我們在快取中建立

uid到

money

的鍵值對,能夠極大降低資料庫的壓力。

讀操作流程

有了資料庫和快取兩個地方存放資料之後(uid->money),每當需要讀取相關資料時(money),操作流程一般是這樣的:

(1)讀取快取中是否有相關資料,uid->money

(2)如果快取中有相關資料money,則返回【這就是所謂的資料命中「hit」】

(3)如果快取中沒有相關資料money,則從資料庫讀取相關資料money【這就是所謂的資料未命中「miss」】,放入快取中uid->money,再返回

快取的命中率 = 命中快取請求個數/總快取訪問請求個數 = hit/(hit+miss)

上面舉例的餘額場景,99%的讀,1%的寫,這個快取的命中率是非常高的,會在95%以上。

那麼問題來了

當資料money發生變化的時候:

(1)是更新快取中的資料,還是淘汰快取中的資料呢?

(2)是先操縱資料庫中的資料再操縱快取中的資料,還是先操縱快取中的資料再操縱資料庫中的資料呢?

(3)快取與資料庫的操作,在架構上是否有優化的空間呢?

這是本文關注的三個核心問題。

二、更新快取

vs 淘汰快取

什麼是更新快取:資料不但寫入資料庫,還會寫入快取

什麼是淘汰快取:資料只會寫入資料庫,不會寫入快取,只會把資料淘汰掉

更新快取的優點:快取不會增加一次miss,命中率高

淘汰快取的優點:簡單(我去,更新快取我也覺得很簡單呀,樓主你太敷衍了吧)

那到底是選擇更新快取還是淘汰快取呢,主要取決於「更新快取的複雜度」。

例如,上述場景,只是簡單的把餘額

money

設定成乙個值

,那麼:

(1)淘汰快取的操作為deletecache(uid)

(2)更新快取的操作為setcache(uid, money)

更新快取的代價很小,此時我們應該更傾向於更新快取,以保證更高的快取命中率

如果餘額是通過很複雜的資料計算得出來的

,例如業務上除了賬戶表account,還有商品表product,折扣表discount

account(uid, money)

product(pid, type, price, pinfo)

discount(type, zhekou)

業務場景是使用者買了乙個商品product,這個商品的**是price,這個商品從屬於type類商品,type類商品在做**活動要打折扣zhekou,購買了商品過後,這個餘額的計算就複雜了,需要:

(1)先把商品的品類,**取出來:select type, price from product where pid=***

(2)再把這個品類的折扣取出來:select zhekou from discount where type=***

(3)再把原有餘額從快取中查詢出來money = getcache(uid)

(4)再把新的餘額寫入到快取中去setcache(uid, money-price*zhekou)

更新快取的代價很大,此時我們應該更傾向於淘汰快取。

however,淘汰快取操作簡單,並且帶來的***只是增加了一次cache miss,建議作為通用的處理方式。

三、先運算元據庫

vs 先操作快取

ok,當寫操作發生時,假設淘汰快取作為對快取通用的處理方式,又面臨兩種抉擇:

(1)先寫資料庫,再淘汰快取

(2)先淘汰快取,再寫資料庫

究竟採用哪種時序呢?

「究竟先寫正表還是先寫反表」的結論麼?

對於乙個不能保證事務性的操作,一定涉及「哪個任務先做,哪個任務後做」的問題,解決這個問題的方向是:

如果出現不一致,誰先做對業務的影響較小,就誰先執行。

由於寫資料庫與淘汰快取不能保證原子性,誰先誰後同樣要遵循上述原則。

假設先寫資料庫,再淘汰快取

:第一步寫資料庫操作成功,第二步淘汰快取失敗,則會出現

db中是新資料,

cache

中是舊資料,資料不一致。

假設先淘汰快取,再寫資料庫

:第一步淘汰快取成功,第二步寫資料庫失敗,則

只會引發一次

cache miss。

結論:資料和快取的操作時序,結論是清楚的:先淘汰快取,再寫資料庫。

四、快取架構優化

上述快取架構有乙個缺點:

業務方需要同時關注快取與db

,有沒有進一步的優化空間呢?有兩種常見的方案,一種主流方案,一種非主流方案(一家之言,勿拍)。

主流優化方案

是服務化:加入乙個服務層,向上游提供帥氣的資料訪問介面,向上游遮蔽底層資料儲存的細節,這樣業務線不需要關注資料是來自於

cache

還是db。

非主流方案

是非同步快取更新:業務線所有的寫操作都走資料庫,所有的讀操作都總快取,由乙個非同步的工具來做資料庫與快取之間資料的同步,具體細節是:

(1)要有乙個init cache的過程,將需要快取的資料全量寫入cache

(2)如果db有寫操作,非同步更新程式讀取binlog,更新cache

在(1)和(2)的合作下,cache中有全部的資料,這樣:

(a)業務線讀cache,一定能夠hit(很短的時間內,可能有髒資料),無需關注資料庫

(b)業務線寫db,cache中能得到非同步更新,無需關注快取

這樣將大大簡化業務線的呼叫邏輯,

存在的缺點是,如果快取的資料業務邏輯比較複雜,

async-update

非同步更新的邏輯可能也會比較複雜。

五、其他未盡事宜

本文只討論了快取架構設計中需要注意的幾個細節點,如果資料庫架構採用了一主多從,讀寫分離的架構,在特殊時序下,還很可能引發資料庫與快取的不一致,這個不一致如何優化,後續的文章再討論吧。

六、結論強調

(1)淘汰快取是一種通用的快取處理方式

(2)先淘汰快取,再寫資料庫的時序是毋庸置疑的

(3)服務化是向業務方遮蔽底層資料庫與快取複雜性的一種通用方式

快取架構設計細節二三事

1 快取與資料庫 需求緣起 2 淘汰快取 還是 更新快取 3 快取和資料庫的操作時序 4 快取和資料庫架構簡析 一 需求緣起 場景介紹 快取是一種提高系統讀效能的常見技術,對於讀多寫少的應用場景,我們經常使用快取來進行優化。例如對於使用者的餘額資訊表account uid,money 業務上的需求是...

快取架構設計

快取架構設計 需求分析 快取是一種提高系統讀效能的常見技術,對於讀多寫少的應用場景,我們經常使用快取來進行優化。例如對於使用者的餘額資訊表account uid,money 業務上的需求是 查詢使用者的餘額,select money from account where uid 佔99 的請求 更改...

快取架構設計

1 快取技術和框架的重要性 網際網路的一些高併發,高效能的專案和系統中,快取技術是起著功不可沒的作用。快取不僅僅是key value的簡單訪問,它在具體的業務場景中,還是很複雜的,需要很強的架構設計能力。我曾經就遇到過因為快取架構設計不到位,導致了系統崩潰的案例。2 快取的技術方案分類 1 是做實時...