轉載自:https://blog.csdn.net/tr1912/article/details/81267910
在redis4.0的配置文件中有這麼一段被註釋了的解釋:
這個裏面講的是redis的內存回收配置,其中有這麼幾種:
volatile-lru -> 根據LRU算法刪除設置了超時屬性(expire)的鍵,直到騰出足夠空間爲止。如果沒有可刪除的鍵對象,回退到noeviction策略。
allkeys-lru -> 根據LRU算法刪除鍵,不管數據有沒有設置超時屬性,直到騰出足夠空間爲止。
volatile-lfu -> 根據LFU算法刪除設置了超時屬性(expire)的鍵,直到騰出足夠空間爲止。如果沒有可刪除的鍵對象,回退到noeviction策略。
allkeys-lfu -> 根據LFU算法刪除鍵,不管數據有沒有設置超時屬性,直到騰出足夠空間爲止。
volatile-random -> 隨機刪除過期鍵,直到騰出足夠空間爲止。
allkeys-random -> 隨機刪除所有鍵,直到騰出足夠空間爲止。
volatile-ttl -> 根據鍵值對象的ttl屬性,刪除最近將要過期數據。如果沒有,回退到noeviction策略。
noeviction -> 不會刪除任何數據,拒絕所有寫入操作並返 回客戶端錯誤信息,此 時Redis只響應讀操作。
redis默認的策略就是noeviction策略,如果想要配置的話,需要在配置文件中寫這個配置:
maxmemory-policy volatile-lru
一、什麼是LRU
LRU是Least Recently Used 近期最少使用算法,很多緩存策略都使用了這種策略進行空間的釋放,在學習操作系統的內存回收的時候也用到了這種機制進行內存的回收,類似的還有LFU(Least Frequently Used)最不經常使用算法,這種算法。
我們在上面的描述中也可以瞭解到,redis使用的是一種類似LRU的算法進行內存溢出回收的,其算法的代碼:
/* volatile-lru and allkeys-lru policy */
else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||
server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
{
struct evictionPoolEntry *pool = db->eviction_pool;
while(bestkey == NULL) {
evictionPoolPopulate(dict, db->dict, db->eviction_pool);
/* Go backward from best to worst element to evict. */
for (k = REDIS_EVICTION_POOL_SIZE-1; k >= 0; k--) {
if (pool[k].key == NULL) continue;
de = dictFind(dict,pool[k].key);
/* Remove the entry from the pool. */
sdsfree(pool[k].key);
/* Shift all elements on its right to left. */
memmove(pool+k,pool+k+1,
sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1));
/* Clear the element on the right which is empty
* since we shifted one position to the left. */
pool[REDIS_EVICTION_POOL_SIZE-1].key = NULL;
pool[REDIS_EVICTION_POOL_SIZE-1].idle = 0;
/* If the key exists, is our pick. Otherwise it is
* a ghost and we need to try the next element. */
if (de) {
bestkey = dictGetKey(de);
break;
} else {
/* Ghost... */
continue;
}
}
}
}
Redis會基於server.maxmemory_samples配置選取固定數目的key,然後比較它們的lru訪問時間,然後淘汰最近最久沒有訪問的key,maxmemory_samples的值越大,Redis的近似LRU算法就越接近於嚴格LRU算法,但是相應消耗也變高。所以,頻繁的進行這種內存回收是會降低redis性能的,主要是查找回收節點和刪除需要回收節點的開銷。
所以一般我們在配置redis的時候,儘量不要讓它進行這種內存溢出的回收操作,redis是可以配置maxmemory,used_memory指的是redis真實佔用的內存,但是由於操作系統還有其他軟件以及內存碎片還有swap區的存在,所以我們實際的內存應該比redis裏面設置的maxmemory要大,具體大多少視系統環境和軟件環境來定。maxmemory也要比used_memory大,一般由於碎片的存在需要做1~2個G的富裕。
————————————————
二、內存回收策略
內存回收觸發有兩種情況,上面說的是一種,也就是內存使用達到maxmemory上限時候觸發的溢出回收,還有一種是我們設置了過期的對象到期的時候觸發的到期釋放的內存回收。
刪除過期對象
Redis所有的鍵都可以設置過期屬性,內部保存在過期字典中。由於進程內保存大量的鍵,維護每個鍵精準的過期刪除機制會導致消耗大量的 CPU,對於單線程的Redis來說成本過高,因此Redis採用惰性刪除和定時任務刪除機制實現過期鍵的內存回收。
1、惰性刪除:顧名思義,指的是不主動刪除,當用戶訪問已經過期的對象的時候才刪除,最大的優點是節省cpu的開銷,不用另外的內存和TTL鏈表來維護刪除信息,缺點就是如果數據到期了但是一直沒有被訪問的話就不會被刪除,會佔用內存空間。
2、定時任務刪除:爲了彌補第一種方式的缺點,redis內部還維護了一個定時任務,默認每秒運行10次。定時任務中刪除過期邏輯採用了自適應算法,使用快、慢兩種速率模式回收鍵。
————————————————
流程說明:
- 定時任務在每個數據庫空間隨機檢查20個鍵,當發現過期時刪除對應的鍵。
- 如果超過檢查數25%的鍵過期,循環執行回收邏輯直到不足25%或 運行超時爲止,慢模式下超時時間爲25毫秒。
- 如果之前回收鍵邏輯超時,則在Redis觸發內部事件之前再次以快模 式運行回收過期鍵任務,快模式下超時時間爲1毫秒且2秒內只能運行1次。
- 快慢兩種模式內部刪除邏輯相同,只是執行的超時時間不同。
————————————————