redis過期策略
在使用redis做緩存的時候,我們常常會設置過期時間。那么redis是如何清理這些過期的數據呢?
答案是: 定期刪除 + 惰性刪除
- 定期刪除: redis每100ms就會
隨機
抽查刪除過期的數據。但是這種方法有時候會留下大量過期但沒有被抽查到的過期數據,白白浪費內存。 - 惰性刪除: 惰性刪除此時就派上用場了,當用戶獲取數據時,redis會先檢查該數據有沒有過期,如果過期就刪除。
聽上去定期刪除+惰性刪除好像很完美的樣子,but過期的數據用戶又沒有及時訪問,那么內存中還是會存在大量的過期數據。此時應該采用redis內存淘汰機制。
redis內存淘汰機制
- noeviction:內存不足以寫入新數據的時候會直接報錯。
- allKeys-lru:內存不足以寫入新數據時候,移除最近最少使用的key。
- allKeys-random: 內存不足以寫入新數據時,隨機移除key。
- volatile-lru: 內存不足以寫入新數據時,在設置了過期時間的key當中移除最近最少使用的key。
- volatile-random: 內存不足以寫入新數據時,在設置了過期時間的key中,隨即移除key。
- volatile-ttl: 內存不足以寫入新數據時,在設置了過期時間的key當中移除最先過期的key。
上面六種你可以這么記:
- 不移除直接報錯: noeviction。
- 在所有key中移除: 1.allKeys-lru 2. allKeys-random
- 在設置了過期時間的key中移除: 1. volatile-lru 2. volatile-random 3.volatile-ttl
一般常用allKeys-lru
實現一個簡單的lru(最近最少使用算法)
package com.amber;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
//最大容量
private final int maxCapacity ;
// 默認增長因子
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
public LRULinkedHashMap(int maxCapacity) {
super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
this.maxCapacity = maxCapacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
if(size()>maxCapacity)
return true;
else
return false;
}
public static void main(String[] args) {
LRULinkedHashMap<String, String> lruLinkedHashMap = new LRULinkedHashMap(5);
lruLinkedHashMap.put("1", "1");
lruLinkedHashMap.put("2", "2");
lruLinkedHashMap.put("3", "3");
lruLinkedHashMap.put("4", "4");
lruLinkedHashMap.put("5", "5");
Iterator<Map.Entry<String, String>> iterator = lruLinkedHashMap.entrySet().iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
lruLinkedHashMap.get("1");
System.out.println("超出最大容量");
lruLinkedHashMap.put("6", "6");
iterator = lruLinkedHashMap.entrySet().iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
結果
1=1
2=2
3=3
4=4
5=5
超出最大容量
3=3
4=4
5=5
1=1
6=6
Process finished with exit code 0
根據上述結果可以看到,當超出最大容量時移除的是第二個結點,而不是第一個結點,因此一個簡單的lru算法就實現了
super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
調用的是父類的
public LinkedHashMap(int var1, float var2, boolean var3) {
super(var1, var2);
this.accessOrder = var3;
}
accessOrder為true表示會把最新訪問的數據放到最后一個節點,默認false