在學(xué)習(xí)redis的過程中,過去鍵刪除是其中最重要的知識(shí)點(diǎn)之一,今天和大家分享的就是這部分內(nèi)容,一起來看看吧。
如果一個(gè)鍵過期了,那么它什么時(shí)候會(huì)被刪除呢?
*定時(shí)刪除:在設(shè)置鍵的過期時(shí)間的同時(shí),創(chuàng)建一個(gè)定時(shí)器(timer),讓定時(shí)器在鍵的過期時(shí)間來臨時(shí),立即執(zhí)行對(duì)鍵的刪除操作。
定時(shí)刪除策略是對(duì)內(nèi)存最友好的:通過使用定時(shí)器,定時(shí)刪除策略可以保證過期鍵會(huì)盡可能快地被刪除,并釋放過期鍵所占用的內(nèi)存。另一方面,定時(shí)刪除策略的缺點(diǎn)是,它對(duì)CPU時(shí)間是最不友好的:在過期鍵比較多的情況下,刪除過期鍵這一行為可能會(huì)占用相當(dāng)一部分CPU時(shí)間,在內(nèi)存不緊張但是CPU時(shí)間非常緊張的情況下,將CPU時(shí)間用在刪除和當(dāng)前任務(wù)無關(guān)的過期鍵上,無疑會(huì)對(duì)服務(wù)器的響應(yīng)時(shí)間和吞吐量造成影響。
例如,如果正有大量的命令請(qǐng)求在等待服務(wù)器處理,并且服務(wù)器當(dāng)前不缺少內(nèi)存,那么服務(wù)器應(yīng)該優(yōu)先將CPU時(shí)間用在處理客戶端的命令請(qǐng)求上面,而不是用在刪除過期鍵上面。
除此之外,創(chuàng)建一個(gè)定時(shí)器需要用到Redis服務(wù)器中的時(shí)間事件,而當(dāng)前時(shí)間事件的實(shí)現(xiàn)方式–無序鏈表,查找一個(gè)事件的時(shí)間復(fù)雜度為O(N) —- 并不能高效地處理大量時(shí)間事件。
因此,要讓服務(wù)器創(chuàng)建大量的定時(shí)器,從而實(shí)現(xiàn)定時(shí)刪除策略,在現(xiàn)階段來說并不現(xiàn)實(shí)。
*惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時(shí),都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。
惰性刪除策略對(duì)CPU時(shí)間來說是最友好的:程序只會(huì)在取出鍵時(shí)才對(duì)鍵進(jìn)行過期檢查,這可以保證刪除過期鍵的操作只會(huì)在非做不可的情況下進(jìn)行,并且刪除的目標(biāo)僅限于當(dāng)前處理的鍵,這個(gè)策略不會(huì)在刪除其他無關(guān)的過期鍵上花費(fèi)任何CPU時(shí)間。
惰性刪除策略的缺點(diǎn)是,它對(duì)內(nèi)存是最不友好的:如果一個(gè)鍵已經(jīng)過期,而這個(gè)鍵又仍然保留在數(shù)據(jù)庫中,那么只要這個(gè)過期鍵不被刪除,它所占的內(nèi)存就不會(huì)釋放。
在使用惰性刪除策略時(shí),如果數(shù)據(jù)庫中有非常多的過期鍵,而這些過期鍵又恰好沒有被訪問到的話,那么它們也許永遠(yuǎn)也不會(huì)被刪除(除非用戶手動(dòng)執(zhí)行FLUSHDB),我們甚至可以將這種情況看作是一種內(nèi)存泄露—-無用的垃圾數(shù)據(jù)占用了大量的內(nèi)存,而服務(wù)器卻不會(huì)自己去釋放它們,這對(duì)于運(yùn)行狀態(tài)非常依賴于內(nèi)存的Redis服務(wù)器來說,肯定不是一個(gè)好消息。
舉個(gè)例子,對(duì)于一些和時(shí)間有關(guān)的數(shù)據(jù),比如日志(log),在某個(gè)時(shí)間之后,對(duì)它們的訪問就會(huì)大大減少,甚至不再訪問,如果這類過期數(shù)據(jù)大量地積壓在數(shù)據(jù)庫中,用戶以為服務(wù)器已經(jīng)自動(dòng)將它們刪除了,但實(shí)際上這些鍵仍然存在,而且鍵所占用的內(nèi)存也沒有釋放,那么造成的后果肯定是非常嚴(yán)重的。
*定期刪除:每隔一段時(shí)間,程序就對(duì)數(shù)據(jù)庫進(jìn)行一次檢查,刪除里面的過期鍵。至于要?jiǎng)h除多少過期鍵,以及要檢查多少個(gè)數(shù)據(jù)庫,則由算法決定。
定期刪除策略是前兩種策略的一種整合和折中:
1. 定期刪除策略每隔一段時(shí)間執(zhí)行一次刪除過期鍵操作,并通過限制刪除操作執(zhí)行的時(shí)長和頻率來減少刪除操作對(duì)CPU時(shí)間的影響;
2. 除此之外,通過定期刪除過期鍵,定期刪除策略有效地減少了因?yàn)檫^期鍵而帶來的內(nèi)存浪費(fèi)。
定期刪除策略的難點(diǎn)是確定刪除操作執(zhí)行的時(shí)長和頻率:
1. 如果刪除操作執(zhí)行的太頻繁,或者執(zhí)行的時(shí)間太長,定期刪除策略就會(huì)退化成定時(shí)刪除策略,以至于將CPU時(shí)間過多地消耗在刪除過期鍵上面。
2. 如果刪除操作執(zhí)行得太少,或者執(zhí)行的時(shí)間太短,定期刪除策略又會(huì)和惰性刪除策略一樣,出現(xiàn)浪費(fèi)內(nèi)存的情況。
因此,如果采用定期刪除策略的話,服務(wù)器必須根據(jù)情況,合理地設(shè)置刪除操作的執(zhí)行時(shí)長和執(zhí)行頻率。
Redis服務(wù)器實(shí)際使用的是惰性刪除和定期刪除兩種策略:通過配合使用這兩種刪除策略,服務(wù)器可以很好地在合理使用CPU時(shí)間和避免浪費(fèi)內(nèi)存空間之間取得平衡。簡(jiǎn)單說明下:
過期鍵的惰性刪除策略由db.c/expireIfNeeded函數(shù)實(shí)現(xiàn),所有讀寫數(shù)據(jù)庫的Redis命令在執(zhí)行之前都會(huì)調(diào)用expireIfNeeded函數(shù)對(duì)輸入鍵進(jìn)行檢查。過期鍵的定期刪除策略由redis.c/activeExpireCycle函數(shù)實(shí)現(xiàn),每當(dāng)Redis的服務(wù)器周期性操作redis.c/serverCron函數(shù)執(zhí)行時(shí),activeExpireCycle函數(shù)就會(huì)被調(diào)用,它在規(guī)定的時(shí)間內(nèi),分多次遍歷服務(wù)器中的各個(gè)數(shù)據(jù)庫,從數(shù)據(jù)庫的expires字典中隨機(jī)檢查一部分鍵的過期時(shí)間,并刪除其中的過期鍵。
原文來自:李智的博客
|