【redis】redis的过期策略

转载 amberbar 2019/10/31 21:22:40

过期策略在使用做缓存的时候,我们常常会设置过期时间。那么是如何清理这些过期的数据呢答案是定期删除惰性删除定期删除每就会抽查删除过期的数据。但是这种方法有时候会留下大量过期但没有被抽查到的过期数据,白白浪费内存。惰性删除惰

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 extends LinkedHashMap {
    //最大容量
    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 entry) {
        if(size()>maxCapacity)
            return true;
        else
            return false;
    }

    public static void main(String[] args) {
        LRULinkedHashMap 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<>> 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

上一篇:详解 Redis 内存管理机制和实现

下一篇:nsq (三) 消息传输的可靠性和持久化[一]

赞(0)

共有 条评论 网友评论

验证码: 看不清楚?
    IT文章导航
    扫一扫关注最新编程为什么上不了bet356_bet356 下载安装_bet356黑钱