Redis中的LRU是真的LRU吗?
结论
redis的lru不是严格的lru,而是近似的lru
区别
- 传统精度lru:需要维护有序链表,淘汰时找到全局最久未访问的key
- redis lru:不会遍历所有key,采用随机采样策略,只在采样集合内删除闲置最久的key
为什么不实现真正的LRU
每次读写key,都需要把节点移动到链表头部
大量链表修改操作,单线程高并发场景绘产生性能损耗,内存上还需要额外存储链表指针
参考——LRU的java实现
package org.example;
import java.util.HashMap;
public class LRUCache {
static class Node {
String key;
String val;
Node prev, next;
Node(String k, String v) {
key = k;
val = v;
}
}
private final int capacity;
private final HashMap<String, Node> map;
private final Node head, tail;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
head = new Node(null, null);
tail = new Node(null, null);
head.next = tail;
tail.prev = head;
}
public String find(String key) {
if (!map.containsKey(key)) return "";
Node node = map.get(key);
moveToTail(node);
return node.val;
}
public boolean set(String key, String value) {
if (map.containsKey(key)) {
Node node = map.get(key);
node.val = value;
moveToTail(node);
return true;
}
Node newNode = new Node(key, value);
map.put(key, newNode);
addTail(newNode);
if (map.size() > capacity) {
Node del = removeHead();
map.remove(del.key);
}
return false;
}
private void removeNode(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void addTail(Node node) {
node.prev = tail.prev;
node.next = tail;
tail.prev.next = node;
tail.prev = node;
}
private void moveToTail(Node node) {
removeNode(node);
addTail(node);
}
private Node removeHead() {
Node first = head.next;
removeNode(first);
return first;
}
public static void main(String[] args) {
LRUCache cache = new LRUCache(3);
cache.set("1", "A");
cache.set("2", "B");
cache.set("3", "C");
cache.find("1");
cache.set("4", "D");
System.out.println(cache.find("2")); // ""
System.out.println(cache.find("1")); // A
}
}
原创
redis的lru是真的lru吗
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法