Redis面試篇 -- 如何保證緩存與數據庫的雙寫一致性?

  若是不是嚴格要求「緩存和數據庫」必須保證一致性的話,最好不要作這個方案:即 讀請求和寫請求串行化,串到一個內存隊列裏面去。串行化能夠保證必定不會出現不一致的狀況,但會致使系統吞吐量大幅度下降。
解決這個問題的最經典的模式,就是Cache Aside Pattern
Cache Aside Pattern:
    (1)讀的時候先讀緩存,若是緩存不存在的話就讀數據庫,取出數據庫後更新緩存;若是存在的話直接讀取緩存的信息。
    (2)寫的時候,先更新數據庫,再刪除緩存。
說到這個問題,又會出現不少問題:
    (1)爲何是刪除緩存,而不是更新緩存?
    (2)爲何是先更新數據庫,再刪除緩存?不是先刪除緩存,再更新數據庫?
 

寫的時候爲何是刪除緩存不是更新緩存?

    不少時候複雜的緩存場景,緩存不是僅僅從數據庫中取出來的值。多是關聯多張表的數據並經過計算纔是緩存須要的值。而且,更新緩存的代價有時候很高。對於須要頻繁寫操做,而讀操做不多的時候,每次進行數據庫的修改,緩存也要隨之更新,會形成系統吞吐的降低,但此時緩存並不會被頻繁訪問到,用到的緩存纔去算緩存。
      刪除緩存而不是更新緩存,是一種懶加載的思想,不是每次都重複更新緩存,只有用到的時候纔去更新緩存,同時即便有大量的讀請求,實際也就更新了一次,後面的請求不會重複讀。
 

Cache Aside Pattern存在的問題

問題:先更新數據庫,再刪除緩存,若是更新緩存失敗了,致使數據庫中是新數據,緩存中是舊數據,就出現數據不一致的問題。
解決思路:先刪除緩存,再更新數據庫。
  • 緩存刪除失敗:若是緩存刪除失敗,那麼數據庫信息沒有被修改,保持了數據的一致性;
  • 緩存刪除成功,數據庫更新失敗:此時數據庫裏的是舊數據,緩存是空的,查詢時發現緩存不存在,就查詢數據庫並更新緩存,數據保持一致。
問題:上面的方案存在不足,若是刪除完緩存更新數據庫時,若是一個請求過來查詢數據,緩存不存在,就查詢數據庫的舊數據,更新舊數據到緩存中。隨後數據更新完成,修改了數據庫的數據,此時緩存和數據庫的數據就會出現不一致了。高併發下會出現這種數據庫+緩存不一致的狀況。 若是不採用給緩存設置過時時間策略,該數據永遠都是髒數據。
解決方案:採用雙刪除策略。寫請求先刪除緩存,再去更新數據庫,等待一段時間後異步刪除緩存。這樣能夠保證在讀取錯誤數據時能及時被修正過來。
還有一種策略,就是:寫請求先修改緩存爲指定值,而後再去更新數據庫,再更新緩存。讀請求過來後,會先讀緩存,判斷是指定值後就進入循環讀取狀態,等到寫請求更新緩存。若是循環超時就去數據庫讀取數據,更新緩存
這種方案保證了讀寫的一致性,但因爲讀請求等待寫請求的完成,會下降系統的吞吐量。
相關文章
相關標籤/搜索