一、背景
在高并發場景中,為防止大量請求直接訪問數據庫,緩解數據庫壓力,常用的方式一般會增加緩存層起到緩沖作用,減少數據庫壓力。引入緩存,就會涉及到緩存與數據庫中數據如何保持一致性問題,本文將對幾種緩存與數據庫保證數據一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。
二、讀取過程
?讀緩存
?如果緩存里沒有值,那就讀取數據庫的值
?同時把這個值寫進緩存中
三、更新過程
更新操作有多種策略,各有優劣,主要針對此場景進行分析
策略 1:先更新 db,再刪除緩存(常用的 Cache-Aside Pattern旁路緩存)
問題:
1. 如果更新 db 成功,刪緩存失敗,將導致數據不一致
2. 極端場景,請求 A 讀,B 寫
1) 此時緩存剛好失效 2)A 查庫得到舊值 3)B 更新 DB 成功
4)B 刪除緩存 5)A 將查到的舊值更新到緩存中
此場景的發生需要步驟 2)查 db 始終慢于 3)的更新 db,才能導致 4)先于 5)執行,通常 db 的查詢是要快于寫入的,所以此極端場景的產生過于嚴格,不易發生
策略 2:先更新 db, 再更新緩存
問題:
1. 并發更新場景下,更新緩存會導致數據不一致
2. 根據讀寫比,考慮是否有必要頻繁同步更新緩存,而且,如果構造緩存中數據過于復雜,或者數據更新頻繁,但是讀取并不頻繁的情況,還會造成不必要的性能損耗
此種方式不推薦
策略 3: 先更新緩存,再更新 db
同上,不推薦
策略 4:先刪緩存,再更新 db
??先刪緩存,雖然解決了策略 1 中,后刪緩存如果失敗的場景,但也會發生不一致的問題
例如:請求 A 刪除緩存,這時請求 B 來查,就會擊穿到數據庫,B 讀取到舊的值后寫入緩存,A 正常更新 db, 由于時間差導致數據不一致的情況
策略 5:緩存延時雙刪
??該策略兼容了策略 1 和策略 4, 解決了先刪緩存還是后刪緩存的問題,如策略 1 中,更新 db 后刪緩存失敗和策略 4 中的不一致場景,該策略可以將延時時間內(比如延時 10ms)所造成的緩存臟數據,再次刪除。但是,如果延時刪緩存失敗,策略 4 中不一致問題還會發生,同時延時的實現,如創建線程,或者引入 mq 異步,可能會增加系統復雜度問題。
策略 6:變種雙刪,前置緩存過期時間
?該策略針對策略 1 中后刪緩存失敗的場景,前置一層緩存數據過期時間(具體時間根據自身系統本身評估,如可覆蓋 db 讀寫耗時或一致性容忍度等),更新 db 后就算刪緩存失敗,在 expire 時間后也能保證緩存中無數據。同時,前置 expire 失敗,或者更新 db 失敗,都不會影響數據一致。
能夠解決策略 4 中的問題:請求 A 刪除緩存,這時請求 B 來查,就會擊穿到數據庫,B 讀取到舊的值后寫入緩存,A 正常更新 db, 由于時間差導致數據不一致的情況,描述圖如下:
??本策略中步驟 1 為 expire 緩存,不會發生擊穿緩存到數據庫的情況,數據將直接返回。除非更極端情況,如下圖:
expire 時間沒有覆蓋住更新 db 的耗時,類似策略 1 中極端場景,此處不贅述
四、總結
對于每種方案策略,各有利弊,但一致性問題始終存在(文章開頭排除了原子性和鎖),只是發生的幾率在一點點慢慢變小了,方案的評估不僅要根據自身系統的業務場景,如讀寫比、并發量、一致性容忍度,還要考慮系統復雜度,投入產出比等,尋找最合適的方案。
審核編輯:劉清
-
數據庫
+關注
關注
7文章
3799瀏覽量
64380
原文標題:緩存與數據庫雙寫一致性幾種策略分析
文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論