作者:京東零售 于瀧
一、背景
在高并發場景中,為防止大量請求直接訪問資料庫,緩解資料庫壓力,常用的方式一般會增加快取層起到緩沖作用,減少資料庫壓力,引入快取,就會涉及到快取與資料庫中資料如何保持一致性問題,本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析,為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性,
二、讀取程序
? 讀快取
? 如果快取里沒有值,那就讀取資料庫的值
? 同時把這個值寫進快取中
三、更新程序
更新操作有多種策略,各有優劣,主要針對此場景進行分析
策略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中極端場景,此處不贅述
四、總結
對于每種方案策略,各有利弊,但一致性問題始終存在(文章開頭排除了原子性和鎖),只是發生的幾率在一點點慢慢變小了,方案的評估不僅要根據自身系統的業務場景,如讀寫比、并發量、一致性容忍度,還要考慮系統復雜度,投入產出比等,尋找最合適的方案,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/550604.html
標籤:其他
上一篇:sql陳述句優化
下一篇:day02-短信登錄