1. Redis 是怎么删除过期 key 的?#
分析
Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略。
常见的三种过期删除策略:定时删除、惰性删除、定期删除。
- 定时删除策略:该策略的作用是给 key 设置过期时间的同时,给 key 创建一个定时器,定时器在 key 的过期时间来临时,对这些 key 进行删除。这样做的好处是保证内存空间得以释放。但是缺点是给 key 创建一个定时器会有一定的性能损失。如果 key 很多,删除这些 key 占用的内存空间也会占用 CPU 很多时间;
- 惰性删除策略:每次从数据库取 key 的时候检查 key 是否过期,如果过期则删除,并返回 null,如果 key 没有过期,则直接返回数据。这样做的好处是占用 CPU 的时间比较少。但是缺点是如果 key 很长时间没有被获取,将不会被删除,容易造成内存泄露;
- 定期删除策略:该策略的作用是每隔一段时间执行一次删除过期 key 的操作,该删除频率可以在 redis.conf 配置文件中设置。这样做的好处是可以避免惰性删除时出现内存泄露的问题,通过设置删除操作的时长频率,可以减少 CPU 时间的占用。但是缺点是相对内存性能友好来说,该策略不如定时删除策略,相对 CPU 性能友好来说,该策略不如惰性删除策略。
三种过期删除策略,每一种都有优缺点,仅使用某一个策略都不能满足实际需求。
所以,Redis 选择「惰性删除+定期删除」这两种策略配合使用,以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。
回答
Redis 采用的删除策略是将惰性删除策略和定期删除策略组合使用。
- 惰性删除策略:每次从数据库取 key 的时候检查 key 是否过期,如果过期则删除,并返回 null,如果 key 没有过期,则直接返回数据。这样做的好处是占用 CPU 的时间比较少。但是缺点是如果 key 很长时间没有被获取,将不会被删除,容易造成内存泄露;
- 定期删除策略:该策略的作用是每隔一段时间执行一次删除过期 key 的操作,这样做的好处是可以避免惰性删除时出现内存泄露的问题,通过设置删除操作的时长频率,可以减少 CPU 时间的占用(从过期字典中随机抽取 20 个 key;检查这 20 个 key 是否过期,并删除已过期的 key;已过期 key 的数量占比随机抽取 key 的数量大于 25%,则继续重复步骤直到比重小于 25%)。
2. Redis 有几种内存回收策略?#
分析
太多了,有 8 种,建议分类阐述:

不进行数据淘汰的策略
- noeviction(Redis 3.0 之后,默认的内存淘汰策略):它表示当运行内存超过最大设置内存时,不淘汰任何数据,这时如果有新的数据写入,会报错通知禁止写入,不淘汰任何数据,但是如果没有数据写入的话,只是单纯的查询或者删除操作的话,还是可以正常工作。
进行数据淘汰的策略
针对「进行数据淘汰」这一类策略,又可以细分为「在设置了过期时间的数据中进行淘汰」和「在所有数据范围内进行淘汰」这两类策略。
在设置了过期时间的数据中进行淘汰:
- volatile-random:随机淘汰设置了过期时间的任意键值;
- volatile-ttl:优先淘汰更早过期的键值;
- volatile-lru(Redis 3.0 之前,默认的内存淘汰策略):淘汰所有设置了过期时间的键值中,最久未使用的键值;
- volatile-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰所有设置了过期时间的键值中,最少使用的键值。
在所有数据范围内进行淘汰:
- allkeys-random:随机淘汰任意键值;
- allkeys-lru:淘汰整个键值中最久未使用的键值;
- allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰整个键值中最少使用的键值。
回答
一种是不开启淘汰策略,此时如果内存满了,写入操作失败,但是不会淘汰已有数据。
另一种是开启淘汰策略,这时候有两个大的分支,一个是基于有过期时间的数据淘汰,一个是基于所有数据,他们都支持 LRU、LFU、RANDOM 算法,过期时间还支持按 ttl 大小淘汰。
3. 内存回收是什么时候发起?#
分析
知道触发时机即可,实际上,每次进行读写的时候,都会调用 processCommand 函数,processCommand 函数又会调用 freeMemoryIfNeeded,这个时候就会尝试去释放一定的内存。函数名不需要去记。
回答
实际上,每次进行读写的时候,都会去检查是否需要释放内存,如果需要则会触发。
4. 介绍下 Redis LRU 回收算法#
分析
谈谈 LRU 概率,这里问题是 Redis 的 LRU 算法,可以提一下是近似的。
回答
LRU,即最近最久未使用,记录每个 key 的最近访问时间,淘汰最久未访问到的数据。但是 Redis 并不是标准的 LRU 算法,而是做了优化,这块我可以展开讲讲吗?
PS:面试官说可以的话,也就是下面这题的回答。
5. Redis LRU 算法是标准的吗?为什么不用标准的#
分析
关键点在近似 LRU,以及内存池优化。
回答
标准 LRU 需要维护双链表,内存成本巨大,所以 Redis 采用近似 LRU 采样来做淘汰,具体步骤是随机采样 n 个 key,这个采样个数默认为 5,然后根据时间戳淘汰掉最旧的那个 key,如果淘汰后内存还是不足,就继续随机采样来淘汰。
在 3.0 之后,Redis 还针对近似 LRU 算法做了淘汰池优化,也就是维护一个候选池,池中的数据根据访问时间进行排序。第一次随机选取的 key 都会放入池中,然后淘汰掉最久未访问的,比如第一次选了 5 个,淘汰了 1 个,剩下 4 个继续留在池子里。
如果池子满了,每次随机选取的 key 只有空闲时间大于当前池子里面最小空闲时间的 key 时才会放入池中,然后将池中空闲时间最大的 key 进行淘汰。
6. 什么是 LFU 算法,为什么 Redis 要引入 LFU 算法?#
分析
LRU 的一个弊端是只看最近访问时间,而忽略了频率,比如下面这个例子:

回答
LFU,即将访问频率也加入到影响因素中,具体而言,LFU 下同时记录了上一次访问时间戳和访问计数,访问计数同时受上一次访问时间和访问频率的影响,因为每次访问都可能会增加计数。