<samp id="tgzrj"><video id="tgzrj"><nav id="tgzrj"></nav></video></samp>

    <samp id="tgzrj"></samp>
    <legend id="tgzrj"><font id="tgzrj"><tr id="tgzrj"></tr></font></legend>

      2023-07-03:講一講Redis緩存的數據一致性問題和處理方案。

      來源:博客園時間:2023-07-03 22:30:50

      2023-07-03:講一講Redis緩存的數據一致性問題和處理方案。

      答案2023-07-03:

      數據一致性

      當使用緩存時,無論是在本地內存中緩存還是使用 Redis 等外部緩存系統,會引入數據同步的問題。下面以 Tomcat 向 MySQL 中進行數據的插入、更新和刪除操作為例,來說明具體的過程。


      【資料圖】

      分析下面幾種解決方案的數據同步方案:

      1.先更新緩存,再更新數據庫:先更新緩存可以提高讀取性能,但如果更新緩存成功而更新數據庫失敗,可能導致數據不一致。

      2.先更新數據庫,再更新緩存:確保數據的持久性,但如果更新數據庫成功而更新緩存失敗,也可能導致數據不一致。

      3.先刪除緩存,后更新數據庫:通過先刪除緩存,再更新數據庫的方式,可以在數據更新后保證數據的一致性,但會降低讀取操作的性能。

      4.先更新數據庫,后刪除緩存:確保數據的持久性,并在更新數據庫成功后再刪除緩存,以保持數據的一致性。

      新增數據類

      對于新增數據的情況,數據會直接寫入數據庫,無需對緩存進行操作。在這種情況下,緩存中本身就沒有新增數據,而數據庫中保存的是最新值。因此,緩存和數據庫的數據是一致的。

      更新緩存類1、先更新緩存,再更新DB

      我們通常不考慮這個方案,因為存在以下問題:即使在更新緩存成功后,若出現更新數據庫時的異常,會導致緩存中的數據與數據庫數據完全不一致。由于緩存數據一直存在,這種不一致性很難察覺到。

      2、先更新DB,再更新緩存

      我們一般不考慮先更新數據庫再更新緩存的方案,與第一個方案存在相同的問題。數據庫更新成功但緩存更新失敗時,仍然會導致數據不一致的問題。此外,這種方案還存在以下問題:

      并發問題:當有請求A和請求B同時進行更新操作時,可能出現以下情況:線程A先更新數據庫,然后線程B也更新了數據庫,隨后線程B更新了緩存,最后線程A也更新了緩存。這導致了請求A應該先更新緩存,但由于網絡等原因,請求B卻比請求A更早更新了緩存,從而產生臟數據。

      業務場景問題:如果寫數據庫的操作比讀數據的操作更頻繁,采用這種方案會導致數據還沒有被讀取,就頻繁更新緩存,從而浪費性能。

      除了更新緩存,我們還可以考慮刪除緩存的方案。具體選擇更新緩存還是淘汰緩存取決于“更新緩存的復雜度”。如果更新緩存的成本較低,我們更傾向于更新緩存以提高緩存命中率;而如果更新緩存的代價較高,我們則更傾向于淘汰緩存。

      刪除緩存類3、先刪除緩存,后更新DB

      該方案也會出問題,具體出現的原因如下。

      1、此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)

      2、請求 A 會先刪除 Redis 中的數據,然后去數據庫進行更新操作;

      3、此時請求 B 看到 Redis 中的數據時空的,會去數據庫中查詢該值,補錄到 Redis 中;

      4、但是此時請求 A 并沒有更新成功,或者事務還未提交,請求B去數據庫查詢得到舊值;

      5、那么這時候就會產生數據庫和 Redis 數據不一致的問題。

      如何解決呢?其實最簡單的解決辦法就是延時雙刪的策略。就是

      (1)先淘汰緩存

      (2)再寫數據庫

      (3)休眠1秒,再次淘汰緩存

      這段偽代碼就是“延遲雙刪”

      redis.delKey(X)db.update(X)Thread.sleep(N)redis.delKey(X)

      這么做,可以將1秒內所造成的緩存臟數據,再次刪除。

      那么,這個1秒怎么確定的,具體該休眠多久呢?

      針對上面的情形,讀該自行評估自己的項目的讀數據業務邏輯的耗時。然后寫數據的休眠時間則在讀數據業務邏輯的耗時基礎上,加幾百ms即可。這么做的目的,就是確保讀請求結束,寫請求可以刪除讀請求造成的緩存臟數據。

      但是上述的保證事務提交完以后再進行刪除緩存還有一個問題,就是如果你使用的是** Mysql ****的讀寫分離的架構**的話,那么其實主從同步之間也會有時間差。

      此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)

      請求 A 更新操作,刪除了Redis,

      請求主庫進行更新操作,主庫與從庫進行同步數據的操作,

      請 B 查詢操作,發現 Redis中沒有數據,

      去從庫中拿去數據,此時同步數據還未完成,拿到的數據是舊數據。

      此時的解決辦法有兩個:

      1、還是使用雙刪延時策略。只是,睡眠時間修改為在主從同步的延時時間基礎上,加幾百ms。

      2、就是如果是對 Redis進行填充數據的查詢數據庫操作,那么就強制將其指向主庫進行查詢。

      繼續深入,采用這種同步淘汰策略,吞吐量降低怎么辦?

      那就將第二次刪除作為異步的。自己起一個線程,異步刪除。這樣,寫的請求就不用沉睡一段時間后了,再返回。這么做,加大吞吐量。

      繼續深入,第二次刪除,如果刪除失敗怎么辦?

      所以,我們引出了,下面的第四種策略,先更新數據庫,再刪緩存。

      4、先更新DB,后刪除緩存

      Cache Aside模式是一種常用的緩存處理方式。在讀取數據時,先檢查緩存,如果緩存中存在數據,則直接返回;如果緩存中不存在,則從數據庫中讀取,并將數據寫入緩存,最后返回響應。在更新數據時,先更新數據庫,然后再刪除緩存。

      通常情況下,我們更傾向于使用刪除緩存的操作,因為刪除緩存的速度比在數據庫中更新數據的速度更快,能更有效地避免數據不一致的問題。通過延時雙刪的處理方式,可以進一步減少緩存不一致性的可能性。

      標簽:

      責任編輯:FD31
      上一篇:傳多家公司擬收購繁德信息技術(FIS.US)旗下Worldpay 盤初漲超4% 世界資訊
      下一篇:最后一頁

      精彩圖集(熱圖)

      熱點圖集

      最近更新

      信用中國

      • 信用信息
      • 行政許可和行政處罰
      • 網站文章

      久爱免费观看在线精品_亚洲综合一区二区三区_最新国产国模无码视频在线_中文字幕无码精品亚洲资源网久久

      <samp id="tgzrj"><video id="tgzrj"><nav id="tgzrj"></nav></video></samp>

      <samp id="tgzrj"></samp>
      <legend id="tgzrj"><font id="tgzrj"><tr id="tgzrj"></tr></font></legend>