網(wǎng)站建設人才百度云怎么找資源
?參考:面試官:為什么 Redis 不立刻刪除已經(jīng)過期的數(shù)據(jù)?
目錄
1.Redis 給緩存數(shù)據(jù)設置過期時間有什么用?
2.Redis 是如何判斷數(shù)據(jù)是否過期的呢?
3.Redis 過期 key 刪除策略了解么?
4.大量 key 集中過期怎么辦?
1.Redis 給緩存數(shù)據(jù)設置過期時間
- 在日常中,短信驗證碼一般只在 1 分鐘內(nèi)有效,用戶登錄的 Token 可能只在 1 天內(nèi)有效,超過過期時間就會失效。
- 上面的例子就是Redis 給緩存數(shù)據(jù)設置過期時間的一個業(yè)務場景,那么Redis 給緩存數(shù)據(jù)設置過期時間有什么好處?
- 因為內(nèi)存是有限且珍貴的,如果不對緩存數(shù)據(jù)設置過期時間,那內(nèi)存占用就會一直增長,最終可能會導致 OOM 問題。通過設置合理的過期時間,Redis 會自動刪除暫時不需要的數(shù)據(jù),為新的緩存數(shù)據(jù)騰出空間。?有助于緩解內(nèi)存的消耗。
#設置過期時間命令 expire命令,setex 命令expire?key?60? #?數(shù)據(jù)在?60s?后過期pexpire key 60000 # 命令 pexpire 設置 key 在 60000 毫秒(即 60 秒)后過期#設置過期時間命令 setex 命令setex?key?60?value ?#?數(shù)據(jù)在?60s?后過期, seyex 將 "key" 設置為 "value",并在 60 秒后過期psetex key 60000 value #使用 PSETEX 指定毫秒為單位的過期時間#查看過期時間命令ttl命令ttl?key?#?查看數(shù)據(jù)還有多久過期# 移除一個鍵的過期時間,使其永久存儲,有效,persist 命令persist my_key
?注:Redis 中除了字符串類型有自己獨有設置過期時間的命令
setex
外,其他方法都需要依靠expire
命令來設置過期時間 。
OOM 問題(Out Of Memory)
當 JVM 因為沒有足夠的內(nèi)存來為對象分配空間,并且垃圾回收器也已經(jīng)沒有空間可回收時,就會拋出這個錯誤。
分配過少:JVM 初始化內(nèi)存小,業(yè)務使用了大量內(nèi)存;或者不同 JVM 區(qū)域分配內(nèi)存不合理
代碼漏洞:某一個對象被頻繁申請,不用了之后卻沒有被釋放,導致內(nèi)存耗盡
內(nèi)存泄漏:申請使用完的內(nèi)存沒有釋放,導致虛擬機不能再次使用該內(nèi)存,此時這段內(nèi)存就泄露了。因為申請者不用了,而又不能被虛擬機分配給別人用,久而久之內(nèi)存空間會越來越小。
內(nèi)存溢出:申請的內(nèi)存超出了 JVM 能提供的內(nèi)存大小,此時稱之為溢出,如果內(nèi)存泄漏持續(xù)存在,最后一定會溢出,兩者是因果關系。
?
?
2.Redis 判斷數(shù)據(jù)是否過期
- Redis 通過一個叫做過期字典(redisDB 結構的 expires 字典保存了數(shù)據(jù)庫中所有鍵的過期時間,該字典被稱為過期字典,可以看作是 hash 表)來保存數(shù)據(jù)過期的時間。
- 過期字典的鍵(一個指針)指向 redisDB中的某個 key(鍵對象),過期字典的值是一個 long long 類型的整數(shù),這個整數(shù)保存了 key 所指向的數(shù)據(jù)庫鍵的過期時間(毫秒精度的 UNIX 時間戳)。?
- 在查詢一個 key 的時候,Redis 首先檢查該 key 是否存在于過期字典中(時間復雜度為 O(1)),如果不在就直接返回,在的話需要判斷一下這個 key 是否過期,過期直接刪除 key 然后返回 null。
?
3.Redis 過期 key 刪除策略
?
常用的過期數(shù)據(jù)的刪除策略:
惰性刪除:只會在取出/查詢 key 的時候才對數(shù)據(jù)進行過期檢查。這種方式對 CPU 最友好,但是可能會造成太多過期 key 沒有被刪除。? ??好處是:如果我們設置了過期時間的key 數(shù)量非常龐大的話,挨個遍歷檢查是非常耗時的,會嚴重影響性能。Redis 設計這種策略的目的是為了平衡內(nèi)存和性能。
定期刪除:周期性地隨機從設置了過期時間的 key 中抽查一批,然后逐個檢查這些 key 是否過期,過期就刪除 key。相比于惰性刪除,定期刪除對內(nèi)存更友好,對 CPU 不太友好。
延遲隊列:把設置過期時間的 key 放到一個延遲隊列里,到期之后就刪除 key。這種方式可以保證每個過期 key 都能被刪除,但維護延遲隊列太麻煩,隊列本身也要占用資源。? ? ?因為在key 多的情況下,一個延遲隊列可能無法容納;修改 key 的過期時間就需要調(diào)整期在延遲隊列中的位置,還需要引入并發(fā)控制。
定時刪除:每個設置了過期時間的 key 都會在設置的時間到達時立即被刪除。這種方法可以確保內(nèi)存中不會有過期的鍵,但是它對 CPU 的壓力最大,因為它需要為每個鍵都設置一個定時器。
Redis 采用的是定期刪除+惰性/懶漢式刪除 結合的策略
定期刪除對內(nèi)存更加友好,惰性刪除對 CPU 更加友好,二者結合起來使用既能兼顧 CPU 友好,又能兼顧內(nèi)存友好。
?Redis 的定期刪除過程
- 隨機的(周期性地隨機從設置了過期時間的 key 中抽查一批),并不能夠保證所有過期鍵都會被立即刪除。這就是為什么有的 key 過期了,并沒有被刪除。
- 而且Redis 底層還會通過限制刪除操作執(zhí)行的時長和頻率來減少刪除操作對 CPU 時間的影響。
因此,定期刪除會受到執(zhí)行時間和過期 key 的比例的影響:
如果刪除操作的執(zhí)行時間已經(jīng)超過了閾值,就會中斷這一次定期刪除循環(huán),以避免使用過多的 CPU 時間。
如果這一批過期的 key 比例超過一個比例,就會重復執(zhí)行此刪除流程,以更積極地清理過期 key。相應地,如果過期的 key 比例低于這個比例,就會中斷這一次定期刪除循環(huán),避免做過多的工作而獲得很少的內(nèi)存回收。
Redis 7.2 版本每次隨機抽查數(shù)量是 20 ,也就是說每次會隨機選擇 20 個設置了過期時間的 key 判斷是否過期。Redis 7.2 版本的執(zhí)行時間閾值是 25ms,過期 key 比例設定值是 **10%**。
4.大量 key 集中過期
如果存在大量 key 集中過期的問題,可能會使 Redis 的請求延遲變高。
盡量避免 key 集中過期,在設置鍵的過期時間時盡量隨機一點。
對過期的 key 開啟 lazyfree 機制(修改
redis.conf
中的lazyfree-lazy-expire
參數(shù)即可),這樣會在后臺異步刪除過期的 key,不會阻塞主線程的運行。