面試官:內(nèi)存耗盡后Redis會(huì)發(fā)生什么 ?
往期熱門文章:
1、監(jiān)控告警滿飛天,運(yùn)維在家睡到自然醒...
2、@Bean與@Component 同時(shí)作用同一個(gè)類,會(huì)怎么樣?
expire key ttl:將 key 值的過(guò)期時(shí)間設(shè)置為 ttl 秒。 pexpire key ttl:將 key 值的過(guò)期時(shí)間設(shè)置為 ttl 毫秒。 expireat key timestamp:將 key 值的過(guò)期時(shí)間設(shè)置為指定的 timestamp 秒數(shù)。 pexpireat key timestamp:將 key 值的過(guò)期時(shí)間設(shè)置為指定的 timestamp 毫秒數(shù)。
ttl key 返回 key 剩余過(guò)期秒數(shù)。 pttl key 返回 key 剩余過(guò)期的毫秒數(shù)。
定時(shí)刪除:為每個(gè)鍵設(shè)置一個(gè)定時(shí)器,一旦過(guò)期時(shí)間到了,則將鍵刪除。這種策略對(duì)內(nèi)存很友好,但是對(duì) CPU 不友好,因?yàn)槊總€(gè)定時(shí)器都會(huì)占用一定的 CPU 資源。 惰性刪除:不管鍵有沒(méi)有過(guò)期都不主動(dòng)刪除,等到每次去獲取鍵時(shí)再判斷是否過(guò)期,如果過(guò)期就刪除該鍵,否則返回鍵對(duì)應(yīng)的值。這種策略對(duì)內(nèi)存不夠友好,可能會(huì)浪費(fèi)很多內(nèi)存。 定期掃描:系統(tǒng)每隔一段時(shí)間就定期掃描一次,發(fā)現(xiàn)過(guò)期的鍵就進(jìn)行刪除。這種策略相對(duì)來(lái)說(shuō)是上面兩種策略的折中方案,需要注意的是這個(gè)定期的頻率要結(jié)合實(shí)際情況掌控好,使用這種方案有一個(gè)缺陷就是可能會(huì)出現(xiàn)已經(jīng)過(guò)期的鍵也被返回。
typedef struct redisDb {dict *dict; //所有的鍵值對(duì)dict *expires; //設(shè)置了過(guò)期時(shí)間的鍵值對(duì)dict *blocking_keys; //被阻塞的key,如客戶端執(zhí)行BLPOP等阻塞指令時(shí)dict *watched_keys; //WATCHED keysint id; //Database ID//... 省略了其他屬性} redisDb;
maxmemory
需要額外的空間進(jìn)行存儲(chǔ)。 可能存在某些 key 值使用很頻繁,但是最近沒(méi)被使用,從而被 LRU 算法刪除。
淺灰色帶是被刪除的對(duì)象。 灰色帶是未被刪除的對(duì)象。 綠色是添加的對(duì)象。
typedef struct redisObject {unsigned type:4;//對(duì)象類型(4位=0.5字節(jié))unsigned encoding:4;//編碼(4位=0.5字節(jié))unsigned lru:LRU_BITS;//記錄對(duì)象最后一次被應(yīng)用程序訪問(wèn)的時(shí)間(24位=3字節(jié))int refcount;//引用計(jì)數(shù)。等于0時(shí)表示可以被垃圾回收(32位=4字節(jié))void *ptr;//指向底層實(shí)際的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),如:SDS等(8字節(jié))} robj;
當(dāng)全局 lruclock > lru,則使用 lruclock - lru 得到空閑時(shí)間。 當(dāng)全局 lruclock < lru,則使用 lruclock_max(即 194 天) - lru + lruclock 得到空閑時(shí)間。
提取 0 和 1 之間的隨機(jī)數(shù) R。 counter - 初始值(默認(rèn)為 5),得到一個(gè)基礎(chǔ)差值,如果這個(gè)差值小于 0,則直接取 0,為了方便計(jì)算,把這個(gè)差值記為 baseval。 概率 P 計(jì)算公式為:1/(baseval * lfu_log_factor + 1)。 如果 R < P 時(shí),頻次進(jìn)行遞增(counter++)。
lfu_log_factor 10
lfu-decay-time 1
獲取當(dāng)前時(shí)間戳,轉(zhuǎn)化為分鐘后取低 16 位(為了方便后續(xù)計(jì)算,這個(gè)值記為 now)。 取出對(duì)象內(nèi)的 lru 屬性中的高 16 位(為了方便后續(xù)計(jì)算,這個(gè)值記為 ldt)。 當(dāng) lru > now 時(shí),默認(rèn)為過(guò)了一個(gè)周期(16 位,最大 65535),則取差值 65535-ldt+now:當(dāng) lru <= now 時(shí),取差值 now-ldt(為了方便后續(xù)計(jì)算,這個(gè)差值記為 idle_time)。 取出配置文件中的 lfu_decay_time 值,然后計(jì)算:idle_time / lfu_decay_time(為了方便后續(xù)計(jì)算,這個(gè)值記為num_periods)。 最后將counter減少:counter - num_periods。
最近熱文閱讀:
1、監(jiān)控告警滿飛天,運(yùn)維在家睡到自然醒... 2、@Bean與@Component 同時(shí)作用同一個(gè)類,會(huì)怎么樣? 3、閑魚面試:Thread.sleep(0) 到底有什么用? 4、身為程序員碰到最奇葩的需求是怎樣的? 5、因?yàn)锽itMap,白白搭進(jìn)去8臺(tái)服務(wù)器... 6、面試官:private修飾的方法可以通過(guò)反射訪問(wèn),那么private的意義是什么? 7、如何選擇合適的分布式ID生成方案 8、面試題:為什么數(shù)據(jù)庫(kù)連接池不采用 IO 多路復(fù)用? 9、SpringBoot 配置文件敏感信息如何加密? 10、線上訂單號(hào)重復(fù)了?一招搞定它! 關(guān)注公眾號(hào),你想要的Java都在這里
評(píng)論
圖片
表情
