通常情況下,我們會優先選擇使用Redis快取來降低資料庫存取負擔。但是也會遇到以下這種情況:大量用戶來訪問我們系統,首先會去查詢緩存, 如果緩存中沒有數據,則去查詢數據庫,然後更新數據到緩存中,並且如果數據庫中的數據發生了改變則需要同步到redis中,同步過程中需要保證MySQL與redis資料一致性問題,在這個同步過程中出現短暫的資料延遲也是正常現象,但最終需要確保mysql與快取中的一致性。
//我们通常使用redis的逻辑 //通常我们是先查询reids String value = RedisUtils.get(key); if (!StringUtils.isEmpty(value)){ return value; } //从数据库中获取数据 value = getValueForDb(key); if (!StringUtils.isEmpty(value)){ RedisUtils.set(key,value); return value; }
延遲雙刪策略是分散式系統中資料庫儲存和快取資料保持一致性的常用策略,但它不是強一致。其實不管哪一種方案,都避免不了Redis存在髒數據的問題,只能減輕這個問題,要徹底解決,得要用到同步鎖和對應的業務邏輯層面解決。
一般我們在更新資料庫資料時,需要同步redis中快取的資料所以我們通常會給出兩種方案:
第一種方案:先執行update操作,再執行快取清除。
第二種方案:先執行快取清除,再執行update操作。
但是這兩種方案在並發請求中容易出現以下問題
第一種方案弊端:當請求1去執行資料庫更新操作之後,還沒執行緩存清除時,請求2就進來了查詢了緩存,此時緩存中數據還是舊數據,還沒來得機刪除導致數據出現問題,但是當t1執行緩存刪除操作之後,後面的請求查詢不到緩存,再到資料中查詢,然後更新到快取中,這種影響是比較小的
#t1線程先更新db;
#t2執行緒查詢命中快取回傳舊的資料;
假設t1執行緒更新完db,預期5毫秒刪除完快取key 在5毫秒內其他執行緒查詢快取結果還是為舊的數據,但是5毫秒後查詢快取結果是為空,在從新將db最新的結果同步到Redis。
在一個專案中出現延遲是很普遍的情況,因此,這種延遲對業務的影響實際上很有限。但是如果發生了,刪除快取失敗呢?
1.不斷重試----如果是在http協定介面中會導致介面回應變慢呼叫該介面會發生回應逾時2.或透過mq非同步的形式同步
第二種方案弊端:當請求1執行清除快取後,還未執行數據更新操作的時,請求2進來查詢到資料庫的舊數據,並寫入了redis,這就導致了資料庫與redis資料不一致問題。
t1執行緒先刪除快取;
t2執行緒讀取快取為null,同步db資料到快取中;
t1執行緒更新db中的資料;
t3執行緒查詢快取中資料是舊資料;
RedisUtils.del(key);// 先删除缓存 updateDB(user);// 更新db中的数据 Thread.sleep(N);// 延迟一段时间,在删除该缓存key RedisUtils.del(key);// 先删除缓存4、需要注意的點#上述中(延遲N秒)的時間要大於一次寫入操作的時間。如果寫入redis的時間早於延遲時間,會導致請求1清除了緩存,但請求2的快取還未寫入,從而出現尷尬情況。 。 。 5、延遲的時間如何確定? 根據業務邏輯執行讀取資料和寫入快取的操作時間進行估算,在業務程序執行時。 「延遲雙刪」是因為該方案在第一次刪除快取值後,會在延遲一段時間後再次進行刪除。
以上是redis延遲雙刪策略怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!