咱們從近期代碼評審過程當中的一段代碼,開始探討緩存和數據庫的一致性問題。html
通常來講,使用緩存主要爲了提高應用性能和下降DB的直接負載,從場景上來講能夠接受最終一致性方案, 若是業務場景要求 「緩存+數據庫」 必須保持強一致性的話,那麼須要使用同步方案,好比排它鎖或者隊列機制+數據庫事務處理 這樣的話影響系統可用性,簡單狀況下可使用....仍是另選方案吧java
public Ware getById(long id) {
Ware ware = Cache.get(id);
if (ware != null) {
return ware;
}
ware = Db.get(id);
if(ware != null){
//緩存時間12小時,根據具體業務調整
Cache.put(ware,60*60*12);
}
return ware;
}
public void update(Param param) {
Db.update(param);
Cache.del(param.getId());
}
//Cache
public void del(long id) {
//異常 靜默
CacheClient.expire("key1"+id, 0);
CacheClient.expire("key2"+ id, 0);
}
複製代碼
先說說這段代碼已經考慮到的問題,也是使用Cache Aside Pattern的好處git
A: 1. 考慮到 update 方法自己併發執行,Db.update和Cache.update不是原子操做,會出現先更新DB的後更新cache 時序不一致問題(庫存修改存在併發狀況,並要求時序一致性)github
A: 2. 商品的緩存數據可能包含多維度好比庫存和價格,這兒更新了庫存一個字段,若是更新緩存須要查詢多表數據聚合放置緩存shell
A: 3. 這次更新的商品可能不被查詢使用,好比冷數據,採用查的時候緩存起到了懶加載效果數據庫
A: 4. 緩存擊穿問題,這兒的更新是基於單個商品,通常狀況可忽略,請求量若是特別高,好比秒殺商品須要更改緩存結構和特殊的處理方式(好比版本替換機制,隊列扣減機制等等,後續有機會bob再詳解...)緩存
未考慮到的問題架構
看到最後咱們能夠發現與其說是保證了一致性,不如說咱們是在 提升緩存一致性併發
從上面的業務使用場景結合問題分析,咱們也能夠看出在不一樣的場景下爲了達到不一樣的效果(一致性要求、吞吐、併發)咱們有不一樣的方案,這些方案的選擇離不開場景,但同時咱們也要結合技術複雜度和團隊技術水平、開發維護成本綜合考慮來選擇適合團隊的方案。異步
高併發架構系列:Redis緩存和MySQL數據一致性方案詳解