PS:本文已收录到1.1K Star数开源学习指南——《大厂面试指北》,如果想要了解更多大厂面试相关的内容,了解更多可以看

http://notfound9.github.io/interviewGuide/#/docs/BATInterview

【大厂面试02期】Redis过期key是怎么样清理的?

在Redis中,对于过期key的清理主要有惰性清除,定时清理,内存不够时清理三种方法,下面我们就来具体看看这三种清理方法。

(1)惰性清除

在访问key时,如果发现key已经过期,那么会将key删除。

(2)定时清理

Redis配置项hz定义了serverCron任务的执行周期,默认每次清理时间为25ms,每次清理会依次遍历所有DB,从db随机取出20个key,如果过期就删除,如果其中有5个key过期,那么就继续对这个db进行清理,否则开始清理下一个db。

(3)内存不够时清理

当执行写入命令时,如果发现内存不够,那么就会按照配置的淘汰策略清理内存,淘汰策略一般有6种,Redis4.0版本后又增加了2种,主要由分为三类

  • 第一类 不处理,等报错(默认的配置)

    • noeviction,发现内存不够时,不删除key,执行写入命令时直接返回错误信息。(Redis默认的配置就是noeviction)
  • 第二类 从所有结果集中的key中挑选,进行淘汰

    • allkeys-random 就是从所有的key中随机挑选key,进行淘汰
    • allkeys-lru 就是从所有的key中挑选最近使用时间距离现在最远的key,进行淘汰
    • allkeys-lfu 就是从所有的key中挑选使用频率最低的key,进行淘汰。(这是Redis 4.0版本后新增的策略)
  • 第三类 从设置了过期时间的key中挑选,进行淘汰

    这种就是从设置了expires过期时间的结果集中选出一部分key淘汰,挑选的算法有:

    • volatile-random 从设置了过期时间的结果集中随机挑选key删除。

    • volatile-lru 从设置了过期时间的结果集中挑选上次使用时间距离现在最久的key开始删除

    • volatile-ttl 从设置了过期时间的结果集中挑选可存活时间最短的key开始删除(也就是从哪些快要过期的key中先删除)

    • volatile-lfu 从过期时间的结果集中选择使用频率最低的key开始删除(这是Redis 4.0版本后新增的策略)

LRU算法

LRU算法的设计原则是如果一个数据近期没有被访问到,那么之后一段时间都不会被访问到。所以当元素个数达到限制的值时,优先移除距离上次使用时间最久的元素。

可以使用双向链表Node+HashMap<String, Node>来实现,每次访问元素后,将元素移动到链表头部,当元素满了时,将链表尾部的元素移除,HashMap主要用于根据key获得Node以及添加时判断节点是否已存在和删除时快速找到节点。

PS:使用单向链表能不能实现呢,也可以,单向链表的节点虽然获取不到pre节点的信息,但是可以将下一个节点的key和value设置在当前节点上,然后把当前节点的next指针指向下下个节点,这样相当于把下一个节点删除了

//双向链表
public static class ListNode {
String key;//这里存储key便于元素满时,删除尾节点时可以快速从HashMap删除键值对
Integer value;
ListNode pre = null;
ListNode next = null;
ListNode(String key, Integer value) {
this.key = key;
this.value = value;
}
} ListNode head;
ListNode last;
int limit=4; HashMap<String, ListNode> hashMap = new HashMap<String, ListNode>(); public void add(String key, Integer val) {
ListNode existNode = hashMap.get(key);
if (existNode!=null) {
//从链表中删除这个元素
ListNode pre = existNode.pre;
ListNode next = existNode.next;
if (pre!=null) {
pre.next = next;
}
if (next!=null) {
next.pre = pre;
}
//更新尾节点
if (last==existNode) {
last = existNode.pre;
}
//移动到最前面
head.pre = existNode;
existNode.next = head;
head = existNode;
//更新值
existNode.value = val;
} else {
//达到限制,先删除尾节点
if (hashMap.size() == limit) {
ListNode deleteNode = last;
hashMap.remove(deleteNode.key);
//正是因为需要删除,所以才需要每个ListNode保存key
last = deleteNode.pre;
deleteNode.pre = null;
last.next = null;
}
ListNode node = new ListNode(key,val);
hashMap.put(key,node);
if (head==null) {
head = node;
last = node;
} else {
//插入头结点
node.next = head;
head.pre = node;
head = node;
}
} } public ListNode get(String key) {
return hashMap.get(key);
} public void remove(String key) {
ListNode deleteNode = hashMap.get(key);
ListNode preNode = deleteNode.pre;
ListNode nextNode = deleteNode.next;
if (preNode!=null) {
preNode.next = nextNode;
}
if (nextNode!=null) {
nextNode.pre = preNode;
}
if (head==deleteNode) {
head = nextNode;
}
if (last == deleteNode) {
last = preNode;
}
hashMap.remove(key);
}

LFU算法

LFU算法的设计原则时,如果一个数据在最近一段时间被访问的时次数越多,那么之后被访问的概率会越大,基本实现是每个数据都有一个引用计数,每次数据被访问后,引用计数加1,需要淘汰数据时,淘汰引用计数最小的数据。在Redis的实现中,每次key被访问后,引用计数是加一个介于0到1之间的数p,并且访问越频繁p值越大,而且在一定的时间间隔内,

如果key没有被访问,引用计数会减少。

最后

大家有什么想法,可以一起讨论!

【大厂面试02期】Redis过期key是怎么样清理的?的更多相关文章

  1. redis过期key的清理策略

    一,有三种不同的删除策略(1),立即清理.在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作. (2),惰性清理.键过期了就过期了,不管.当读/写一个已经过期的 ...

  2. Redis过期key淘汰策略

    Redis采用惰性+定期的key淘汰策略 1. Redis配置项hz定义了serverCron任务的执行周期,默认为10,即CPU空闲时每秒执行10次; 2. 每次过期key清理的时间不超过CPU时间 ...

  3. 【大厂面试07期】说一说你对synchronized锁的理解?

    synchronized锁的原理也是大厂面试中经常会涉及的问题,本文主要通过对以下问题进行分析讲解,来帮助大家理解synchronized锁的原理. 1.synchronized锁是什么?锁的对象是什 ...

  4. 【大厂面试08期】谈一谈你对HashMap的理解?

    摘要 HashMap的原理也是大厂面试中经常会涉及的问题,同时也是工作中常用到的Java容器,本文主要通过对以下问题进行分析讲解,来帮助大家理解HashMap的原理. 1.HashMap添加一个键值对 ...

  5. redis过期key监听事件

    目录 redis安装 docker拉取 启动 redis 配置 命令监听 问题 程序监听 具体监听类 效果 总结 redis常用语缓存操作,但是redis功能不仅仅于此.今天我们来看看redis的ke ...

  6. 面试官:Redis 过期删除策略和内存淘汰策略有什么区别?

    作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林. Redis 的「内存淘汰策略」和「过期删除策略」,很多小伙伴容易混淆,这两个机制虽然都 ...

  7. 【大厂面试03期】MySQL是怎么解决幻读问题的?

    问题分析 首先幻读是什么? 根据MySQL文档上面的定义 The so-called phantom problem occurs within a transaction when the same ...

  8. 【大厂面试06期】谈一谈你对Redis持久化的理解?

    Redis持久化是面试中经常会问到的问题,这里主要通过对以下几个问题进行分析,帮助大家了解Redis持久化的实现原理. 1.Redis持久化是什么? 2.Redis持久化有哪些策略?各自的实现原理是怎 ...

  9. SpringBoot监听redis过期key

    开启过期监听 vim /etc/redis.conf 取消notify-keyspace-events Elg的注释 pom.xml 添加: <dependency> <groupI ...

随机推荐

  1. Qt线程池

    说明 Qt中可以有多种使用线程的方式: 继承 QThread,重写 run() 接口: 使用 moveToThread() 方法将 QObject 子类移至线程中,内部的所有使用信号槽的槽函数均在线程 ...

  2. Java三大特征:封装 继承 多态

    内部类:成员内部类.静态内部类.方法内部类.匿名内部类. 内部类:定义在另外一个类里面的类,与之对应,包含内部类的外部类被称为外部类. 内部类的作用:(1)内部类提供了更好的封装,可以把内部类隐藏在外 ...

  3. 【Linux系列汇总】小白博主的嵌入式Linux实战快速进阶之路(持续更新)

    我把之前在学习嵌入式Linux和工作中遇到问题和相关经验等,一起整理到这里,方便自己查阅和学习,温故而知新,如果能帮助到您,请帮忙点个赞: 本文的宗旨 嵌入式Linux 的项目通常需要一个团队来开发, ...

  4. Mybatis 分页:Pagehelper + 拦截器实现

    一.分页插件 Pagehelper PageHelper是Mybatis的一个分页插件,非常好用! 1.1 Spring Boot 依赖 <!-- pagehelper 分页插件--> & ...

  5. CF#637 D. Nastya and Scoreboard DP

    D. Nastya and Scoreboard 题意 一块电子屏幕上有n个数字. 每个数字是通过这样7个线段显示的,现在你不小心打坏了k个线段,给出打坏之后的n个数字的显示方式,问之前的屏幕表示的最 ...

  6. FPGA的“可编程”使你迷惑吗?

    http://www.alteraforum.com.cn/showtopic-7791.aspx FPGA的“可编程”使你迷惑吗?   任何一个硬件工程师对FPGA都不会陌生,就好比C语言对于软件工 ...

  7. .NETcore中使用jwt来对api进行身份验证

    对于 登陆,身份,授权这之类的操作,我们最常用的几种方法无非就是 cookie session token 这三者的差别 https://www.cnblogs.com/moyand/p/904797 ...

  8. 下载Android代码

    1.由于墙,无法下载android源码,但是又不想利用清华源repo下载整个工程,只下载个别仓库 解决办法: 2.下载frameworks/base: git clone https://androi ...

  9. Android 开发技术周报 Issue#280

    新闻 6分钟完整视频提前看光谷歌新机Pixel 4a 统一推送官方解读:消灭Android毒瘤.待机续航猛增43% Google Play细化搜索结果:可按评分.编辑推荐.最新上线过滤 教程 了解一下 ...

  10. AVPlayer的使用+简单的播放器Demo

    学习内容 AVPlayer学习 几个播放器相关的类 AVPlayer.AVURLAsset.AVPlayerItem.AVPlayerLayer //控制播放器的播放.暂停.播放速度 @propert ...