一般,咱們會使用緩存用於緩衝對 DB 的衝擊,若是緩存宕機,全部請求將直接打在 DB,形成 DB 宕機——從而致使整個系統宕機。html
如何解決呢?面試
2 種策略(同時使用):shell
解釋 1:緩存查詢一個沒有的 key,同時數據庫也沒有,若是黑客大量的使用這種方式,那麼就會致使 DB 宕機。數據庫
解決方案:咱們可使用一個默認值來防止,例如,當訪問一個不存在的 key,而後再去訪問數據庫,仍是沒有,那麼就在緩存裏放一個佔位符,下次來的時候,檢查這個佔位符,若是發生時佔位符,就不去數據庫查詢了,防止 DB 宕機。緩存
解釋 2: 大量請求查詢一個剛剛失效的 key,致使 DB 壓力倍增,可能致使宕機,但實際上,查詢的都是相同的數據。架構
解決方案:能夠在這些請求代碼加上雙重檢查鎖。可是那個階段的請求會變慢。不過總比 DB 宕機好。併發
解釋:多個客戶端寫一個 key,若是順序錯了,數據就不對了。可是順序咱們沒法控制。異步
解決方案:使用分佈式鎖,例如 zk,同時加入數據的時間戳。同一時刻,只有搶到鎖的客戶端才能寫入,同時,寫入時,比較當前數據的時間戳和緩存中數據的時間戳。分佈式
解釋:連續寫數據庫和緩存,可是操做期間,出現併發了,數據不一致了。 一般,更新緩存和數據庫有如下幾種順序:ide
三種方式的優劣來看一下:
先更新數據庫,再更新緩存。 這麼作的問題是:當有 2 個請求同時更新數據,那麼若是不使用分佈式鎖,將沒法控制最後緩存的值究竟是多少。也就是併發寫的時候有問題。
先刪緩存,再更新數據庫。 這麼作的問題:若是在刪除緩存後,有客戶端讀數據,將可能讀到舊數據,並有可能設置到緩存中,致使緩存中的數據一直是老數據。 有 2 種解決方案:1. 使用「雙刪」,即刪更刪,最後一步的刪除做爲異步操做,就是防止有客戶端讀取的時候設置了舊值。2. 使用隊列,當這個 key 不存在時,將其放入隊列,串行執行,必須等到更新數據庫完畢才能讀取數據。
總的來說,比較麻煩。
還有一種可能,若是執行更新數據庫,準備執行刪除緩存時,服務掛了,執行刪除失敗怎麼辦??? 這就坑了!!! 不過能夠經過訂閱數據庫的 binlog 來刪除。
緩存更新的套路 原創 分佈式之數據庫和緩存雙寫一致性方案解析 Cache-Aside pattern
歡迎工做一到五年的 Java 的工程師朋友們加入的 Java 架構開發:685-167-672
本羣提供免費的學習指導架構資料以及免費的解答
不懂得問題均可以在本羣提出來以後還會有職業生涯規劃以及面試指導