無錫網絡公司無錫網站制作免費下載百度seo
目錄
- Redis系列-Redis過期策略以及內存淘汰機制【6】
- redis過期策略
- 內存淘汰機制
- 算法
- LRU算法
- LFU
- 其他場景對過期key的處理
- FAQ
- 為什么不用定時刪除策略?
- Ref
個人主頁: 【??個人主頁】
需要您的【💖 點贊+關注】支持 💯
Redis系列-Redis過期策略以及內存淘汰機制【6】
redis主要是基于內存來進行高性能、高并發(fā)的讀寫操作的。但既然內存是有限的,例如redis就只能使用10G,你寫入了20G。這個時候就需要清理掉10G數據,保留10G數據。那應該保留哪些數據,清除哪些數據,為什么有些數據明明過期了,怎么還占用著內存?這都是由redis的過期策略來決定的。
redis過期策略
? redis的過期策略就是:定期刪除
+ 惰性刪除
。
? 定期刪除
,指的是redis默認是每隔100ms就隨機抽取一些設置了過期時間的key,檢查是否過期,如果過期就刪除。
🅰? 100ms怎么來的?
在Redis的配置文件redis.conf
中有一個屬性"hz
",默認為10
表示1s執(zhí)行10次定期刪除,即每隔100ms執(zhí)行一次,可以修改這個配置值。
🅱? 隨機抽取一些檢測,一些是多少?
同樣是由redis.conf
文件中的maxmemory-samples屬性決定的,默認為5。
在Redis的配置文件redis.conf中有一個屬性"hz",默認為10,表示1s執(zhí)行10次定期刪除,即每隔100ms執(zhí)行一次,可以修改這個配置值。
? 假設redis里放了10W個key,都設置了過期時間,你每隔幾百毫秒就檢查全部的key,那redis很有可能就掛了,CPU負載會很高,都消耗在檢查過期的key上。注意,這里不是每隔100ms就遍歷所有設置過期時間的key,那樣就是一場性能災難。實際上redis是每隔100ms就隨機抽取一些key來檢查和刪除的。
? 定期刪除可能會導致很多過期的key到了時間并沒有被刪除掉。這個時候就可以用到惰性刪除了。
惰性刪除
是指在你獲取某個key的時候,redis會檢查一下,這個key如果設置了過期時間并且已經過期了,此時就會刪除,不會給你返回任何東西。
? 但即使是這樣,依舊有問題。如果定期刪除漏掉了很多過期的key,然后你也沒及時去查,也就沒走惰性刪除。此時依舊有可能大量過期的key堆積在內存里,導致內存耗盡。
? 這個時候就需要內存淘汰機制
了。
內存淘汰機制
在redis.conf
中有一行配置 ,該配置就是配內存淘汰策略
的
# maxmemory-policy volatile-lru
redis·內存淘汰機制
有以下幾個:
noeviction
:當內存不足以容納新寫入數據時,新寫入操作會報錯。這個一般很少用。allkeys-lru
:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key,這個是最常用
的。allkeys-random
:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。volatile-lru
:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。volatile-random
:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。volatile-ttl
:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優(yōu)先移除。allkeys-lfu
,淘汰整個鍵值中最少使用的鍵值,這也就是我們常說的LRU算法。 【Redis4.0】volatile-lfu
,淘汰所有設置了過期時間的鍵值中最少使用的鍵值【Redis4.0】
而在Redis4.0版本中又新增了2種淘汰策略:
allkeys-lfu,淘汰整個鍵值中最少使用的鍵值,這也就是我們常說的LRU算法。
volatile-lfu,淘汰所有設置了過期時間的鍵值中最少使用的鍵值
通過上面的內存淘汰策略可以看出,以 allkeys- 開頭的表示從所有key中進行數據淘汰,而以 volatile- 開頭的會從設置了過期時間的key中進行數據淘汰。
算法
LRU
(Least Recently Used,最近最少使用),根據最近被使用的時間,離當前最遠的數據優(yōu)先被淘汰;LFU
(Least Frequently Used,最不經常使用),在一段時間內,緩存數據被使用次數最少的會被淘汰。
LRU算法
? 上面的內存淘汰機制中,用到的是LRU
算法。什么是LRU算法?LRU算法其實就是上面說的最近最少使用
策略。
實現LRU算法,大概的思路如下:
1.? 維護一個有序單鏈表,越靠近鏈表尾部的節(jié)點是越早之前訪問的。當有一個新的數據被訪問時,我們從鏈表頭開始順序遍歷鏈表:
2. 如果此數據之前已經被緩存在鏈表中了,我們遍歷得到這個數據對應的節(jié)點,并將其從原來的位置刪除,然后再插入到鏈表的頭部。
3. 如果此數據沒有在緩存鏈表中,又可以分為兩種情況:
- 如果此時緩存未滿,則將此節(jié)點直接插入到鏈表的頭部;
- 如果此時緩存已滿,則鏈表尾節(jié)點刪除,將新的數據節(jié)點插入鏈表的頭部。
? 這就就實現了LRU算法。
? 當然我們也可以基于Java現有的數據結構LinkedHashMap手擼一個。LinkHashMap本質上是一個Map與雙向鏈表的結合,比起上述的單鏈表,效率更高。代碼如下:
class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int CACHE_SIZE;/*** 傳遞進來最多能緩存多少數據** @param cacheSize 緩存大小*/public LRUCache(int cacheSize) {// true 表示讓 linkedHashMap 按照訪問順序來進行排序,最近訪問的放在頭部,最老訪問的放在尾部。super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);CACHE_SIZE = cacheSize;}@Overrideprotected boolean removeEldestEntry(Map.Entry<K, V> eldest) {// 當 map中的數據量大于指定的緩存?zhèn)€數的時候,就自動刪除最老的數據。return size() > CACHE_SIZE;}
}
LFU
在Redis LFU算法中,為每個key維護了一個計數器,每次key被訪問的時候,計數器增大,計數器越大,則認為訪問越頻繁。但其實這樣會有問題,
1、因為訪問頻率是動態(tài)變化的,前段時間頻繁訪問的key,之后也可能很少再訪問(如微博熱搜)。為了解決這個問題,Redis記錄了每個key最后一次被訪問的時間,隨著時間的推移,如果某個key再沒有被訪問過,計數器的值也會逐漸降低。
2、新生key問題,對于新加入緩存的key,因為還沒有被訪問過,計數器的值如果為0,就算這個key是熱點key,因為計數器值太小,也會被淘汰機制淘汰掉。為了解決這個問題,Redis會為新生key的計數器設置一個初始值。
上面說過在Redis LRU算法中,會給每個key維護一個大小為24bit的屬性字段,代表最后一次被訪問的時間戳。在LFU中也維護了這個24bit的字段,不過被分成了16 bits與8 bits兩部分:
16 bits 8 bits
±-------------------±-----------+
- Last decr time | LOG_C |
±-------------------±----------+
其中高16 bits用來記錄計數器的上次縮減時間,時間戳,單位精確到分鐘。低8 bits用來記錄計數器的當前數值。
在redis.conf配置文件中還有2個屬性可以調整LFU算法的執(zhí)行參數:lfu-log-factor、lfu-decay-time。其中l(wèi)fu-log-factor用來調整計數器counter的增長速度,lfu-log-factor越大,counter增長的越慢。lfu-decay-time是一個以分鐘為單位的數值,用來調整counter的縮減速度。
其他場景對過期key的處理
1、快照生成RDB文件時
過期的key不會被保存在RDB文件中。
2、服務重啟載入RDB文件時
Master載入RDB時,文件中的未過期的鍵會被正常載入,過期鍵則會被忽略。Slave 載入RDB 時,文件中的所有鍵都會被載入,當主從同步時,再和Master保持一致。
3、AOF 文件寫入時
因為AOF保存的是執(zhí)行過的Redis命令,所以如果redis還沒有執(zhí)行del,AOF文件中也不會保存del操作,當過期key被刪除時,DEL 命令也會被同步到 AOF 文件中去。
4、重寫AOF文件時
執(zhí)行 BGREWRITEAOF 時 ,過期的key不會被記錄到 AOF 文件中。
5、主從同步時
Master 刪除 過期 Key 之后,會向所有 Slave 服務器發(fā)送一個 DEL命令,Slave 收到通知之后,會刪除這些 Key。Slave 在讀取過期鍵時,不會做判斷刪除操作,而是繼續(xù)返回該鍵對應的值,只有當Master 發(fā)送 DEL 通知,Slave才會刪除過期鍵,這是統(tǒng)一、中心化的鍵刪除策略,保證主從服務器的數據一致性。
FAQ
為什么不用定時刪除策略?
定時刪除,用一個定時器來負責監(jiān)視key,過期則自動刪除。雖然內存及時釋放,但是十分消耗CPU資源。在大并發(fā)請求下,CPU要將時間應用在處理請求,而不是刪除key,因此沒有采用這一策略.
Ref
https://blog.csdn.net/yuanlong122716/article/details/104420880