<strong id="ctjbx"></strong>

  1. <strong id="ctjbx"></strong>
    <ruby id="ctjbx"></ruby>

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

    來(lái)源:博客園時(shí)間:2023-07-03 22:30:50

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

    答案2023-07-03:

    數據一致性

    當使用緩存時(shí),無(wú)論是在本地內存中緩存還是使用 Redis 等外部緩存系統,會(huì )引入數據同步的問(wèn)題。下面以 Tomcat 向 MySQL 中進(jìn)行數據的插入、更新和刪除操作為例,來(lái)說(shuō)明具體的過(guò)程。


    【資料圖】

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

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

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

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

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

    新增數據類(lèi)

    對于新增數據的情況,數據會(huì )直接寫(xiě)入數據庫,無(wú)需對緩存進(jìn)行操作。在這種情況下,緩存中本身就沒(méi)有新增數據,而數據庫中保存的是最新值。因此,緩存和數據庫的數據是一致的。

    更新緩存類(lèi)1、先更新緩存,再更新DB

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

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

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

    并發(fā)問(wèn)題:當有請求A和請求B同時(shí)進(jìn)行更新操作時(shí),可能出現以下情況:線(xiàn)程A先更新數據庫,然后線(xiàn)程B也更新了數據庫,隨后線(xiàn)程B更新了緩存,最后線(xiàn)程A也更新了緩存。這導致了請求A應該先更新緩存,但由于網(wǎng)絡(luò )等原因,請求B卻比請求A更早更新了緩存,從而產(chǎn)生臟數據。

    業(yè)務(wù)場(chǎng)景問(wèn)題:如果寫(xiě)數據庫的操作比讀數據的操作更頻繁,采用這種方案會(huì )導致數據還沒(méi)有被讀取,就頻繁更新緩存,從而浪費性能。

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

    刪除緩存類(lèi)3、先刪除緩存,后更新DB

    該方案也會(huì )出問(wèn)題,具體出現的原因如下。

    1、此時(shí)來(lái)了兩個(gè)請求,請求 A(更新操作) 和請求 B(查詢(xún)操作)

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

    3、此時(shí)請求 B 看到 Redis 中的數據時(shí)空的,會(huì )去數據庫中查詢(xún)該值,補錄到 Redis 中;

    4、但是此時(shí)請求 A 并沒(méi)有更新成功,或者事務(wù)還未提交,請求B去數據庫查詢(xún)得到舊值;

    5、那么這時(shí)候就會(huì )產(chǎn)生數據庫和 Redis 數據不一致的問(wèn)題。

    如何解決呢?其實(shí)最簡(jiǎn)單的解決辦法就是延時(shí)雙刪的策略。就是

    (1)先淘汰緩存

    (2)再寫(xiě)數據庫

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

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

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

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

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

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

    但是上述的保證事務(wù)提交完以后再進(jìn)行刪除緩存還有一個(gè)問(wèn)題,就是如果你使用的是** Mysql ****的讀寫(xiě)分離的架構**的話(huà),那么其實(shí)主從同步之間也會(huì )有時(shí)間差。

    此時(shí)來(lái)了兩個(gè)請求,請求 A(更新操作) 和請求 B(查詢(xún)操作)

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

    請求主庫進(jìn)行更新操作,主庫與從庫進(jìn)行同步數據的操作,

    請 B 查詢(xún)操作,發(fā)現 Redis中沒(méi)有數據,

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

    此時(shí)的解決辦法有兩個(gè):

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

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

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

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

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

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

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

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

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

    標簽:

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

    精彩圖集(熱圖)

    熱點(diǎn)圖集

    最近更新

    信用中國

    • 信用信息
    • 行政許可和行政處罰
    • 網(wǎng)站文章

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

      <strong id="ctjbx"></strong>

    1. <strong id="ctjbx"></strong>
      <ruby id="ctjbx"></ruby>