Cache Aside Pattern:糾結(jié)個(gè)啥?旁路緩存就這么用!
有不少朋友問我,緩存到底怎么操作?
有些成熟的技術(shù)方案,用不著創(chuàng)新,固化下來的模式(pattern),學(xué)就完了。Cache Aside Pattern 就是旁路緩存的行業(yè)最佳實(shí)踐。大部分情況下,照著用就完了。

什么是“Cache Aside Pattern”?
旁路緩存方案的經(jīng)驗(yàn)實(shí)踐,這個(gè)實(shí)踐又分讀實(shí)踐,寫實(shí)踐。
畫外音:與旁路緩存對應(yīng)的,是穿透緩存。
讀實(shí)踐是怎么樣的?
對于讀請求:

- 先讀cache,再讀db;
- 如果,cache hit,則直接返回?cái)?shù)據(jù);
- 如果,cache miss,則訪問db,并將數(shù)據(jù)set回緩存;
寫實(shí)踐是怎么樣的?
對于寫請求:

- 淘汰緩存,而不是更新緩存;
- 先操作數(shù)據(jù)庫,再淘汰緩存;
Cache Aside Pattern為什么建議淘汰緩存,而不是更新緩存?
如果更新緩存,在并發(fā)寫時(shí),可能出現(xiàn)數(shù)據(jù)不一致。

如上圖所示,如果采用set緩存。
在1和2兩個(gè)并發(fā)寫發(fā)生時(shí),由于無法保證時(shí)序,此時(shí)不管先操作緩存還是先操作數(shù)據(jù)庫,都可能出現(xiàn):
- 請求1先操作數(shù)據(jù)庫,請求2后操作數(shù)據(jù)庫;
- 請求2先set了緩存,請求1后set了緩存;
導(dǎo)致,數(shù)據(jù)庫與緩存之間的數(shù)據(jù)不一致。
所以,Cache Aside Pattern建議,delete緩存,而不是set緩存。
Cache Aside Pattern為什么建議先操作數(shù)據(jù)庫,再操作緩存?
如果先操作緩存,在讀寫并發(fā)時(shí),可能出現(xiàn)數(shù)據(jù)不一致。

如上圖所示,如果先操作緩存。
在1和2并發(fā)讀寫發(fā)生時(shí),由于無法保證時(shí)序,可能出現(xiàn):
- 寫請求淘汰了緩存;
- 寫請求操作了數(shù)據(jù)庫(主從同步?jīng)]有完成);
- 讀請求讀了緩存(cache miss);
- 讀請求讀了從庫(讀了一個(gè)舊數(shù)據(jù));
- 讀請求set回緩存(set了一個(gè)舊數(shù)據(jù));
- 數(shù)據(jù)庫主從同步完成;
導(dǎo)致,數(shù)據(jù)庫與緩存的數(shù)據(jù)不一致。
所以,Cache Aside Pattern建議,先操作數(shù)據(jù)庫,再操作緩存。
Cache Aside Pattern方案存在什么問題?
如果先操作數(shù)據(jù)庫,再淘汰緩存,在原子性被破壞時(shí):
- 修改數(shù)據(jù)庫成功了;
- 淘汰緩存失敗了;
導(dǎo)致,數(shù)據(jù)庫與緩存的數(shù)據(jù)不一致。
Cache Aside Pattern總結(jié):
(1) 對于讀請求:
- 先讀cache,再讀db;
- 如果,cache hit,則直接返回?cái)?shù)據(jù);
- 如果,cache miss,則訪問db,并將數(shù)據(jù)set回緩存;
(2) 對于寫請求:
- 淘汰緩存,而不是更新緩存;
- 先操作數(shù)據(jù)庫,再淘汰緩存;
(3) 潛在問題:寫操作原子性被破壞時(shí),數(shù)據(jù)庫與緩存的數(shù)據(jù)不一致。
知其然,知其所以然。
思路比結(jié)論更重要。






















