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