更新時間:2023年05月15日11時29分 來源:傳智教育 瀏覽次數(shù):
緩存穿透是指查詢一個一定不存在的數(shù)據(jù),如果從存儲層查不到數(shù)據(jù)則不寫入緩存,這將導致這個不存在的數(shù)據(jù)每次請求都要到 DB 去查詢,可能導致 DB 掛掉。這種情況大概率是遭到了攻擊。
通常都會用布隆過濾器來解決它,
布隆過濾器主要是用于檢索一個元素是否在一個集合中。我們當時使用的是redisson實現(xiàn)的布隆過濾器。
它的底層主要是先去初始化一個比較大數(shù)組,里面存放的二進制0或1。在一開始都是0,當一個key來了之后經(jīng)過3次hash計算,模于數(shù)組長度找到數(shù)據(jù)的下標然后把數(shù)組中原來的0改為1,這樣的話,三個數(shù)組的位置就能標明一個key的存在。查找的過程也是一樣的。
當然是有缺點的,布隆過濾器有可能會產(chǎn)生一定的誤判,我們一般可以設置這個誤判率,大概不會超過5%,其實這個誤判是必然存在的,要不就得增加數(shù)組的長度,其實已經(jīng)算是很劃分了,5%以內(nèi)的誤判率一般的項目也能接受,不至于高并發(fā)下壓倒數(shù)據(jù)庫。
緩存擊穿的意思是對于設置了過期時間的key,緩存在某個時間點過期的時候,恰好這時間點對這個Key有大量的并發(fā)請求過來,這些請求發(fā)現(xiàn)緩存過期一般都會從后端 DB 加載數(shù)據(jù)并回設到緩存,這個時候大并發(fā)的請求可能會瞬間把 DB 壓垮。
解決方案有兩種方式:
第一可以使用互斥鎖:當緩存失效時,不立即去load db,先使用如 Redis 的 setnx 去設置一個互斥鎖,當操作成功返回時再進行 load db的操作并回設緩存,否則重試get緩存的方法。
第二種方案可以設置當前key邏輯過期,大概是思路如下:
①:在設置key的時候,設置一個過期時間字段一塊存入緩存中,不給當前key設置過期時間
②:當查詢的時候,從redis取出數(shù)據(jù)后判斷時間是否過期
③:如果過期則開通另外一個線程進行數(shù)據(jù)同步,當前線程正常返回數(shù)據(jù),這個數(shù)據(jù)不是最新
當然兩種方案各有利弊:
如果選擇數(shù)據(jù)的強一致性,建議使用分布式鎖的方案,性能上可能沒那么高,鎖需要等,也有可能產(chǎn)生死鎖的問題如果選擇key的邏輯刪除,則優(yōu)先考慮的高可用性,性能比較高,但是數(shù)據(jù)同步這塊做不到強一致。