穿透類緩存Cache使用,這一篇就夠了!
有些成熟的技術方案,用不著創新,固化下來的模式(pattern),學就完了。例如,穿透類緩存的使用,“Cache Aside Pattern”就是很好的實踐沉淀,故今天聊一聊Cache Aside Pattern。
畫外音:就好像“設計模式”,它就是沉淀下來的設計方法。
什么是“Cache Aside Pattern”?
旁路緩存方案的經驗實踐,這個實踐又分讀實踐,寫實踐。
畫外音:與旁路緩存對應的,是穿透緩存。
讀實踐是怎么樣的?
對于讀請求:
(1)先讀cache,再讀db;
(2)如果,cache hit,則直接返回數據;
(3)如果,cache miss,則訪問db,并將數據set回緩存;
如上圖:
(1)先從cache中嘗試get數據,結果miss了;
(2)再從db中讀取數據,從庫,讀寫分離;
(3)最后把數據set回cache,方便下次讀命中;
寫實踐是怎么樣的?
對于寫請求:
(1)淘汰緩存,而不是更新緩存;
(2)先操作數據庫,再淘汰緩存;
如上圖:
(1)第一步要操作數據庫,第二步操作緩存;
(2)緩存,采用delete淘汰,而不是set更新;
Cache Aside Pattern為什么建議淘汰緩存,而不是更新緩存?
如果更新緩存,在并發寫時,可能出現數據不一致。
如上圖所示,如果采用set緩存。
在1和2兩個并發寫發生時,由于無法保證時序,此時不管先操作緩存還是先操作數據庫,都可能出現:
(1)請求1先操作數據庫,請求2后操作數據庫;
(2)請求2先set了緩存,請求1后set了緩存;
導致,數據庫與緩存之間的數據不一致。
所以,Cache Aside Pattern建議,delete緩存,而不是set緩存。
Cache Aside Pattern為什么建議先操作數據庫,再操作緩存?
如果先操作緩存,在讀寫并發時,可能出現數據不一致。
如上圖所示,如果先操作緩存。
在1和2并發讀寫發生時,由于無法保證時序,可能出現:
(1)寫請求淘汰了緩存;
(2)寫請求操作了數據庫(主從同步沒有完成);
(3)讀請求讀了緩存(cache miss);
(4)讀請求讀了從庫(讀了一個舊數據);
(5)讀請求set回緩存(set了一個舊數據);
(6)數據庫主從同步完成;
導致,數據庫與緩存的數據不一致。
所以,Cache Aside Pattern建議,先操作數據庫,再操作緩存。
Cache Aside Pattern方案存在什么問題?
答:如果先操作數據庫,再淘汰緩存,在原子性被破壞時:
(1)修改數據庫成功了;
(2)淘汰緩存失敗了;
導致,數據庫與緩存的數據不一致。
Cache Aside Pattern總結:
對于讀請求:
(1)先讀cache,再讀db;
(2)如果,cache hit,則直接返回數據;
(3)如果,cache miss,則訪問db,并將數據set回緩存;
對于寫請求:
(1)淘汰緩存,而不是更新緩存;
(2)先操作數據庫,再淘汰緩存;
任何技術方案的設計,都是折衷。
【本文為51CTO專欄作者“58沈劍”原創稿件,轉載請聯系原作者】