Redis-缓存过期淘汰策略

缓存淘汰策略

生产上redis内存设置为多少

设置为最大内存的 3/4

redis 会占用物理机多少内存

默认大小是 0,64 位系统下表示不限制内存大小,32位系统表示 3G

如何设置修改redis内存大小

  1. config get maxmemory 查看
  2. 修改方式
    1. 配置文件 单位是字节
2. <font style="color:#000000;">临时修改,重启后失效 config set maxmemory 104857600</font>

如果redis内存满了会怎么样

redis 将会报错:(error) OOM command not allowed when used memory > 'maxmemory'

通过命令查看 redis 内存使用情况?

info memory

redis 对于过期 key 的三种不同删除策略

定时删除:创建kv的同时cpu会创建定时器,内存友好,cpu占用高

惰性删除:再次访问这个 key 的时候才会去检查过期时间,内存不友好

定时删除:每隔一段时间去抽样扫描一定(注意不是所有)数量的key是否过期,并可通过限制执行的频率和时长来控制对 cpu 的影响,折中,但可能存留较多过期key,并且需要根据具体情况合适的设置频率和时长

如果执行时间太长,退化成定时。太短则又会出现过期key太多

引出兜底方案,缓存淘汰策略

redis 缓存淘汰策略

8种内存淘汰策略

  • noevition: 不操作 默认,看上面oom案例
  • allkeys-lru: 对所有 key 使用 lru
  • volatile-lru: 对所有设置了过期时间的key lru
  • allkeys-random
  • volatile-random
  • volatile-ttl: 删除快要过期
  • allkeys-lfu lfu
  • volatile-lfu

修改 -> maxmemory-policy

总结记忆

  1. 2个维度
    1. 过期键中筛选 allkeys
    2. 所有键中筛选 volatile
  2. 4个方面
    1. lru 最少使用,最长时间未被使用
    2. lfu 最不常用,一段时间内使用次数最少
    3. random 随机
    4. ttl

用哪种

后两种都对业务有精确的要求,推荐 allkeys-lru

lru算法手写,最近最少使用算法

leetcode 146

哈希链表

基于 LinkedHashMap 的写法

java 复制代码
public class LruCacheDemo<K,V> extends LinkedHashMap<K,V> {
    private int capacity;

    public LruCacheDemo(int capacity) {
        super(capacity, 0.75f, false); // true = accessOrder false insertionOrder
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return super.size() > capacity;
    }

    public static void main(String[] args) {
        LruCacheDemo lruCacheDemo = new LruCacheDemo(3);
        lruCacheDemo.put(1, 1);
        lruCacheDemo.put(2, 2);
        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.keySet());

        lruCacheDemo.put(4, 4);
        System.out.println(lruCacheDemo.keySet());

        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.keySet());
        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.keySet());
        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.keySet());

        lruCacheDemo.put(5, 5);
        System.out.println(lruCacheDemo.keySet());
    }
}
/**
 * true
 * [1, 2, 3]
 * [2, 3, 4]
 * [2, 4, 3]
 * [2, 4, 3]
 * [2, 4, 3]
 * [4, 3, 5]
 */
// false,只看插入顺序,不看访问顺序,多次插入3,3的位置不变
/**
 * false
 *[1, 2, 3]
 * [2, 3, 4]
 * [2, 3, 4]
 * [2, 3, 4]
 * [2, 3, 4]
 * [3, 4, 5]
 */

手写的案例

java 复制代码
// 手写 LruCache
public class MyLruCacheDemo {

    // map 负责查找,构建一个虚拟的双向链表,它里面安装的就是一个个Node节点,作为数据载体

    // 1 构造一个 Node 作为数据载体
    class Node<K, V> {
        K key;
        V value;
        Node<K, V> prev;
        Node<K, V> next;

        public Node() {
            this.prev = this.next = null;
        }
    }

    //2 构建一个虚拟的双向链表,里面安放的就是我们的Node
    class DoubleLinkedList<K, V> {
        Node<K, V> head;
        Node<K, V> tail;

        // 2.1 构造方法
        public DoubleLinkedList() {
            head = new Node<K, V>();
            tail = new Node<K, V>();
            head.next = tail;
            tail.prev = head;
        }

        //2.2 添加到头
        public void addFirst(Node<K, V> node) {
            node.next = head.next;
            node.prev = head;
            head.next.prev = node;
            head.next = node;
        }

        //2.3 删除节点
        public void remove(Node<K, V> node) {
            node.prev.next = node.next;
            node.next.prev = node.prev;
            node.prev = null;
            node.next = null;
        }

        //2.4 获得最后一个节点
        public Node<K, V> getLast() {
            return tail.prev;
        }
    }

    private int cacheSize;
    Map<Integer, Node<Integer, Integer>> map;
    DoubleLinkedList<Integer, Integer> doubleLinkedList;

    public MyLruCacheDemo(int cacheSize) {
        this.cacheSize = cacheSize; // 坑位
        map = new HashMap<>(); // 查找
        doubleLinkedList = new DoubleLinkedList<>();
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        Node<Integer, Integer> node = map.get(key);
        doubleLinkedList.remove(node);
        doubleLinkedList.addFirst(node);
        return node.value;
    }

    // saveOrUpdate
    public void put(int key, int value) {
        if (map.containsKey(key)) { // update
            Node<Integer, Integer> node = map.get(key);
            node.value = value;
            doubleLinkedList.remove(node);
            doubleLinkedList.addFirst(node);
        } else {
            if (map.size() == cacheSize) { // 坑位满了
                Node<Integer, Integer> last = doubleLinkedList.getLast();
                map.remove(last.key);
                doubleLinkedList.remove(last);
            }
            // 才是新增
            Node<Integer, Integer> node = new Node<>();
            node.key = key;
            node.value = value;
            map.put(key, node);
            doubleLinkedList.addFirst(node);
        }
    }

    public static void main(String[] args) {
        MyLruCacheDemo lruCacheDemo = new MyLruCacheDemo(3);
        lruCacheDemo.put(1, 1);
        lruCacheDemo.put(2, 2);
        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.map.keySet());
        lruCacheDemo.put(4, 4);
        System.out.println(lruCacheDemo.map.keySet());

        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.map.keySet());

        lruCacheDemo.put(3, 3);
        System.out.println(lruCacheDemo.map.keySet());

        lruCacheDemo.put(5, 5);
        System.out.println(lruCacheDemo.map.keySet());

    }
}
相关推荐
亽仒凣凣几秒前
Windows安装Redis图文教程
数据库·windows·redis
亦世凡华、9 分钟前
MySQL--》如何在MySQL中打造高效优化索引
数据库·经验分享·mysql·索引·性能分析
YashanDB12 分钟前
【YashanDB知识库】Mybatis-Plus调用YashanDB怎么设置分页
数据库·yashandb·崖山数据库
ProtonBase22 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
希忘auto1 小时前
详解Redis的常用命令
redis·1024程序员节
云和数据.ChenGuang6 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
woshilys6 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi6 小时前
SQL注入的那些面试题总结
数据库·sql
建投数据7 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi8 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql