tft每日頭條

 > 生活

 > 快速掌握redis緩存

快速掌握redis緩存

生活 更新时间:2025-01-06 13:09:10

快速掌握redis緩存?上一篇講到了緩存擊穿的問題,是說當一個熱點數據在redis過期後,突然有大量請求同時來訪問此數據,此時發現redis沒有數據,這些大量的請求便都會打到數據庫,給數據庫造成壓力這種是針對redis裡沒有這條數據,數據庫裡有這條數據的情況,我們可以用加鎖來保證隻有一個線程可以打到數據庫,這個線程查詢完數據庫後将數據會寫到redis,其它線程就可以直接從redis獲取了,具體細節請查看上一篇:redis使用之四:緩存擊穿但是上一篇同時也遺留了一個問題,就是這條數據在redis和數據都沒有怎麼辦,這時候其它處于等待的線程,在一定時間内從redis中查不到數據就抛出異常,是否不太合理?而且還有一個問題,如果這些線程不是并發的,每個請求都是等前一個請求執行完并且釋放鎖後在發起,那這樣每個請求都能獲取到鎖,并且打到數據庫,仍然會給數據庫造成壓力,這種情況就是常說的緩存穿透,今天小編就來聊一聊關于快速掌握redis緩存?接下來我們就一起去研究一下吧!

快速掌握redis緩存(redis使用之五緩存穿透)1

快速掌握redis緩存

上一篇講到了緩存擊穿的問題,是說當一個熱點數據在redis過期後,突然有大量請求同時來訪問此數據,此時發現redis沒有數據,這些大量的請求便都會打到數據庫,給數據庫造成壓力。這種是針對redis裡沒有這條數據,數據庫裡有這條數據的情況,我們可以用加鎖來保證隻有一個線程可以打到數據庫,這個線程查詢完數據庫後将數據會寫到redis,其它線程就可以直接從redis獲取了,具體細節請查看上一篇:redis使用之四:緩存擊穿。但是上一篇同時也遺留了一個問題,就是這條數據在redis和數據都沒有怎麼辦,這時候其它處于等待的線程,在一定時間内從redis中查不到數據就抛出異常,是否不太合理?而且還有一個問題,如果這些線程不是并發的,每個請求都是等前一個請求執行完并且釋放鎖後在發起,那這樣每個請求都能獲取到鎖,并且打到數據庫,仍然會給數據庫造成壓力,這種情況就是常說的緩存穿透。

緩存穿透的解決,首先要對用戶傳來的參數做檢驗,通常情況下,數據庫中的id,都是從1開始自增的,不可能存在小于1的id,如果用戶傳來了小于1的id,我們就可以參數是不合法的,直接把請求拒絕掉,不需要再去查redis和數據庫。還有,假如我們數據表中隻有一萬條數據,并且不會有新增的數據,但是用戶傳來的id是十幾萬或者更大,那我們也可以認為參數是不合法的,直接把請求拒絕掉。總之,這一步的目的就是盡量把不合法的請求拒絕掉,但是沒辦法把所有不合法請求全部拒絕掉,比如數據表每天新增的數據特别大,這是你是沒有辦法去驗證用戶傳來的id的上限的。

針對這種情況,有人說如果在數據庫查詢不到,也把這條數據存到緩存,隻不過value存個空值,這種思路是正确的,但是問題是這個空值你怎麼存,是存null,還是存空串呢?

首先來說一個存null值的問題,有人說redis的key和value都不能存null,key一定是不能存null的,但是value能不能存null我沒有具體研究過,反正我是從來沒有存過null的,也從來都不會有這樣的需求讓你存null,如果你真的需要null的話,那一定是你的設計有問題。但是話說回來,即使redis允許value存null,我們也不能存null,因為如果你存了null,那我們根據key去獲取value時返回了null,那你怎麼知道是因為key不存在返回了null,還是說key是存在的,隻不過是value為null呢,你沒有辦法去區分這兩種情況,但是你在代碼種,還要根據這兩種情況,做不同的處理,如果是因為key不存在,就需要獲取鎖去查詢數據庫,如果key存在但是value為null,就說明這條數據在數據庫中都是不存在的,直接返回即可。但是你沒辦法區别這兩種情況,就沒辦法處理,也許有人會說redis是有方法可以判斷key是否存在的,但是這樣做就給系統帶來了複雜性,因為你需要兩步操作,第一步判斷key是否存在,第二步根據key獲取value,這樣做就麻煩了,我們沒有必要做這麼麻煩。

綜上所述,value存null是不合理的,那就隻能存個空串,我在實際開發時也是通過存個空串解決的,這樣根據key獲取value時,先判斷返回結果是不是null,如果是null,也去獲取鎖去數據庫查詢,如果不存在,則說明此條數據在數據庫和redis都不存在,直接返回即可,如果此兩種情況都不是,就說明從redis中查到了數據,直接做反序列化,得到真正的實體對象即可。

這樣看起來方案似乎比較完美了,但是實際上還是存在問題的,假如用戶傳來的id,目前在數據庫中是不存在的,存了個空串,這樣後面在根據這個id時,redis直接返回空串,我們就知道數據庫裡沒有這條數據了。但是這個id可能隻是暫時不存在,可能以後随着數據量的增長,這個id又存在了,這就需要在新增數據時,如果數據新增成功,要把redis中對應的數據删除,而且此時為了最大可能的保證數據庫與redis的數據的一緻性,我們需要利用threadlocal做個雙删,具體細節請查看我前面寫的文章,redis緩存使用之三:如何保證數據庫數據與redis數據的一緻性。但是這種雙删的方案仍然有可能删除redis失敗,所以我們在redis存儲空串時,需要給對應的key加個比較短的過期時間,我一般都會加個三分鐘的過期時間。

上面說的這種情況是說id暫時不存在,但是後面可能存在的情況,但是還有一種情況,就是這個id在數據庫裡是有的,隻不過被打上了邏輯删除的标識,這代表着這條數據雖然在數據庫中雖然存在,但是對用戶來說是透明的,用戶通過id查的時候,應該查不到這條數據才對,而且後面不管過了多長時間,通過這個id都是查不到這條數據的。針對這種情況,我們還是在redis中存個空串,隻不過這時,我們在對應的key上加的過期時間會比較長,我通常都會加上一天的過期時間。

上面就是我在工作中,整個的解決redis緩存穿透的方案,大家有什麼不同的看法或者更好的建議,歡迎評論區讨論[微笑]

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved