分佈式緩存數據庫一致性問題

緩存和數據庫一致性問題,有不少解決方案,沒有最完美的方案,只有適合自身業務的儘量完美的方案。redis

緩存因爲其高併發和高性能的特徵,已經在項目中被普遍應用。數據庫

  查詢時通常先查詢緩存,若是緩存命中的話,那麼直接將數據返回。緩存

  若是緩存中沒有數據(如失效,或者根本沒設置數據),那麼,應用程序先從數據庫中查詢數據,若是不爲空,則將數據放在緩存中。併發

那麼更新時,怎麼處理緩存和數據庫呢?先更新數據庫後更新緩存?先更新數據庫後更新緩存?或者先淘汰緩存後更新數據庫?異步

爲何沒有先更新緩存後更新數據庫?ide

  1):若是更新數據庫失敗,那麼就形成了數據不一致高併發

 

先更新數據庫後更新緩存的問題性能

  1):兩個線程併發更新數據庫再更新緩存可能出現緩存更新順序問題spa

  2):若是更新頻繁,讀少的狀況,那麼緩存也被頻繁更新,形成沒必要要的開銷線程

  3):若是緩存的值是須要通過一系列複雜計算的,那麼每次都去更新緩存無疑是浪費性能的

 

先刪緩存後更新數據庫的問題:

  1):線程A刪除緩存更新完數據庫前,線程B沒有命中緩存,從數據庫中查詢到了更新前的值存入緩存中

  解決方案:延時雙刪策略(推薦使用)

  即先刪除緩存,再更新數據庫,休眠一段時間,再刪除緩存

  僞代碼以下:

public void write(String key,Object data){
    redis.delKey(key); 
    db.updateData(data); 
    Thread.sleep(1000); redis.delKey(key);
 }

爲什要休眠1秒鐘?爲了將這1秒內形成的髒數據刪除,可能有線程讀取到了更新前的舊數據還將來得及寫入緩存

休眠的時間多少如何肯定?評估自身項目讀數據業務邏輯的耗時,在這基礎了加100ms便可。能夠確保髒數據已經寫入緩存中

讀寫分離怎麼辦?

  也是採用延時雙刪策略,休眠時間確保完成主從同步

爲了不休眠形成吞吐量下降,能夠將第二次刪除做爲異步操做

第二次刪除失敗怎麼辦?

  刪除在更新期間寫入緩存的舊值失敗

  解決方案:將須要刪除的key發送到消息隊列,而後本身消費消息,得到須要刪除的key,繼續重試刪除操做,直到成功。

先更新數據庫後刪緩存

  即Cache Aside Pattern,即緩存旁路模式

  失效:應用程序先從緩存中取數據,沒有取到,則從數據庫中取數據,成功後,放到緩存中

  命中:應用程序從緩存中渠道數據,而後返回

  更新:先把數據存到數據庫中,成功後,再刪除緩存

相關文章
相關標籤/搜索