對(duì)于redis服務(wù)器來說,內(nèi)存資源非常寶貴,如果一些過期鍵一直不被刪除,就會(huì)造成資源浪費(fèi),
因此我們需要考慮一個(gè)問題:如果一個(gè)鍵過期了,它什么時(shí)候會(huì)被刪除呢?
1. 常見的刪除策略
常見的刪除策略有以下3種:
- 定時(shí)刪除 在設(shè)置鍵的過期時(shí)間的同時(shí),創(chuàng)建一個(gè)定時(shí)器,讓定時(shí)器在鍵的過期時(shí)間來臨時(shí),立即執(zhí)行對(duì)鍵的刪除操作。
- 惰性刪除 放任過期鍵不管,每次從鍵空間中獲取鍵時(shí),檢查該鍵是否過期,如果過期,就刪除該鍵,如果沒有過期,就返回該鍵。
- 定期刪除 每隔一段時(shí)間,程序?qū)?shù)據(jù)庫(kù)進(jìn)行一次檢查,刪除里面的過期鍵,至于要?jiǎng)h除哪些數(shù)據(jù)庫(kù)的哪些過期鍵,則由算法決定。
其中定時(shí)刪除和定期刪除為主動(dòng)刪除策略,惰性刪除為被動(dòng)刪除策略。
接下來我們一一講解。
1.1 定時(shí)刪除策略
定時(shí)刪除策略通過使用定時(shí)器,定時(shí)刪除策略可以保證過期鍵盡可能快地被刪除,并釋放過期鍵占用的內(nèi)存。
因此,定時(shí)刪除策略的優(yōu)缺點(diǎn)如下所示:
- 優(yōu)點(diǎn):對(duì)內(nèi)存非常友好
- 缺點(diǎn):對(duì)CPU時(shí)間非常不友好
舉個(gè)例子,如果有大量的命令請(qǐng)求等待服務(wù)器處理,并且服務(wù)器當(dāng)前不缺少內(nèi)存,如果服務(wù)器將大量的CPU時(shí)間用來刪除過期鍵,那么服務(wù)器的響應(yīng)時(shí)間和吞吐量就會(huì)受到影響。
也就是說,如果服務(wù)器創(chuàng)建大量的定時(shí)器,服務(wù)器處理命令請(qǐng)求的性能就會(huì)降低,
因此Redis目前并沒有使用定時(shí)刪除策略。
1.2 惰性刪除策略
惰性刪除策略只會(huì)在獲取鍵時(shí)才對(duì)鍵進(jìn)行過期檢查,不會(huì)在刪除其它無關(guān)的過期鍵花費(fèi)過多的CPU時(shí)間。
因此,惰性刪除策略的優(yōu)缺點(diǎn)如下所示:
- 優(yōu)點(diǎn):對(duì)CPU時(shí)間非常友好
- 缺點(diǎn):對(duì)內(nèi)存非常不友好
舉個(gè)例子,如果數(shù)據(jù)庫(kù)有很多的過期鍵,而這些過期鍵又恰好一直沒有被訪問到,那這些過期鍵就會(huì)一直占用著寶貴的內(nèi)存資源,造成資源浪費(fèi)。
1.3 定期刪除策略
定期刪除策略是定時(shí)刪除策略和惰性刪除策略的一種整合折中方案。
定期刪除策略每隔一段時(shí)間執(zhí)行一次刪除過期鍵操作,并通過限制刪除操作執(zhí)行的時(shí)長(zhǎng)和頻率來減少刪除操作對(duì)CPU時(shí)間的影響,同時(shí),通過定期刪除過期鍵,也有效地減少了因?yàn)檫^期鍵而帶來的內(nèi)存浪費(fèi)。
2. Redis使用的過期鍵刪除策略
Redis服務(wù)器使用的是惰性刪除策略和定期刪除策略。
2.1 惰性刪除策略的實(shí)現(xiàn)
過期鍵的惰性刪除策略由expireIfNeeded函數(shù)實(shí)現(xiàn),所有讀寫數(shù)據(jù)庫(kù)的Redis命令在執(zhí)行之前都會(huì)調(diào)用expireIfNeeded函數(shù)對(duì)輸入鍵進(jìn)行檢查:
- 如果輸入鍵已經(jīng)過期,那么將輸入鍵從數(shù)據(jù)庫(kù)中刪除
- 如果輸入鍵未過期,那么不做任何處理
以上描述可以使用如下流程圖表示:
2.2 定期刪除策略的實(shí)現(xiàn)
過期鍵的定期刪除策略由activeExpireCycle函數(shù)實(shí)現(xiàn),每當(dāng)Redis服務(wù)器的周期性操作serverCron函數(shù)執(zhí)行時(shí),activeExpireCycle函數(shù)就會(huì)被調(diào)用,它在規(guī)定的時(shí)間內(nèi),分多次遍歷服務(wù)器中的各個(gè)數(shù)據(jù)庫(kù),從數(shù)據(jù)庫(kù)的expires字典中隨機(jī)檢查一部分鍵的過期時(shí)間,并刪除其中的過期鍵。
activeExpireCycle函數(shù)的大體流程為:
函數(shù)每次運(yùn)行時(shí),都從一定數(shù)量的數(shù)據(jù)庫(kù)中隨機(jī)取出一定數(shù)量的鍵進(jìn)行檢查,并刪除其中的過期鍵,比如先從0號(hào)數(shù)據(jù)庫(kù)開始檢查,下次函數(shù)運(yùn)行時(shí),可能就是從1號(hào)數(shù)據(jù)庫(kù)開始檢查,直到15號(hào)數(shù)據(jù)庫(kù)檢查完畢,又重新從0號(hào)數(shù)據(jù)庫(kù)開始檢查,這樣可以保證每個(gè)數(shù)據(jù)庫(kù)都被檢查到。
劃重點(diǎn):
關(guān)于定期刪除的大體流程,最近面試時(shí)有被問道,我就是按上述描述回答的。 可能有的面試官還會(huì)問,每次隨機(jī)刪除哪些key呢?可以提下LRU算法(Least Recently Used 最近最少使用),一般不會(huì)再細(xì)問,不過有興趣的同學(xué)可以深入研究下。
3. RDB對(duì)過期鍵的處理
3.1 生成RDB文件
在執(zhí)行SAVE命令或者BGSAVE命令創(chuàng)建一個(gè)新的RDB文件時(shí),程序會(huì)對(duì)數(shù)據(jù)庫(kù)中的鍵進(jìn)行檢查,已過期的鍵不會(huì)被保存到新創(chuàng)建的RDB文件中。
舉個(gè)例子,如果數(shù)據(jù)庫(kù)中包含3個(gè)鍵k1、k2、k3,并且k2已經(jīng)過期,那么創(chuàng)建新的RDB文件時(shí),程序只會(huì)將k1和k3保存到RDB文件中,k2則會(huì)被忽略。
3.2 載入RDB文件
在啟動(dòng)Redis服務(wù)器時(shí),如果服務(wù)器只開啟了RDB持久化,那么服務(wù)器將會(huì)載入RDB文件:
- 如果服務(wù)器以主服務(wù)器模式運(yùn)行,在載入RDB文件時(shí),程序會(huì)對(duì)文件中保存的鍵進(jìn)行檢查,未過期的鍵會(huì)被載入到數(shù)據(jù)庫(kù)中,過期鍵會(huì)被忽略。
- 如果服務(wù)器以從服務(wù)器模式運(yùn)行,在載入RDB文件時(shí),文件中保存的所有鍵,不論是否過期,都會(huì)被載入到數(shù)據(jù)庫(kù)中。 因?yàn)橹鲝姆?wù)器在進(jìn)行數(shù)據(jù)同步(完整重同步)的時(shí)候,從服務(wù)器的數(shù)據(jù)庫(kù)會(huì)被清空,所以一般情況下,過期鍵對(duì)載入RDB文件的從服務(wù)器不會(huì)造成影響。
4. AOF對(duì)過期鍵的處理
4.1 AOF文件寫入
如果數(shù)據(jù)庫(kù)中的某個(gè)鍵已經(jīng)過期,并且服務(wù)器開啟了AOF持久化功能,當(dāng)過期鍵被惰性刪除或者定期刪除后,程序會(huì)向AOF文件追加一條DEL命令,顯示記錄該鍵已被刪除。
舉個(gè)例子,如果客戶端執(zhí)行命令GET message訪問已經(jīng)過期的message鍵,那么服務(wù)器將執(zhí)行以下3個(gè)動(dòng)作:
- 從數(shù)據(jù)庫(kù)中刪除message鍵
- 追加一條DEL message命令到AOF文件
- 向執(zhí)行GET message命令的客戶端返回空回復(fù)
4.2 AOF文件重寫
在執(zhí)行AOF文件重寫時(shí),程序會(huì)對(duì)數(shù)據(jù)庫(kù)中的鍵進(jìn)行檢查,已過期的鍵不會(huì)被保存到重寫后的AOF文件中。
5. 復(fù)制功能對(duì)過期鍵的處理
在主從復(fù)制模式下,從服務(wù)器的過期鍵刪除動(dòng)作由主服務(wù)器控制:
- 主服務(wù)器在刪除一個(gè)過期鍵后,會(huì)顯式地向所有從服務(wù)器發(fā)送一個(gè)DEL命令,告知從服務(wù)器刪除這個(gè)過期鍵。
- 從服務(wù)器在執(zhí)行客戶端發(fā)送的讀命令時(shí),即使發(fā)現(xiàn)該鍵已過期也不會(huì)刪除該鍵,照常返回該鍵的值。
- 從服務(wù)器只有接收到主服務(wù)器發(fā)送的DEL命令后,才會(huì)刪除過期鍵。
作者:申城異鄉(xiāng)人
鏈接:https://juejin.im/post/5e93ce3be51d45470d528262
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。