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