redis过期和内存淘汰策略
关于redis的过期和内存淘汰策略的笔记。集合了官方文档,网络资源和实体书里的内容
内存淘汰策略
内存淘汰是用于内存不足时淘汰数据使用
可以使用多大内存
redis通过以下配置决定内存使用量
1 | |
可以在配置文件中注明,也可以在运行时通过config命令指定
如果设置为0,在64位系统上是无限制,就是可以使用所有的物理内存,在32位系统上最多使用3GB
什么时候淘汰内存
redis遵循以下逻辑
- 客户端发送一个命令,该命令会导致内存占用增加
- redis检查当前剩余内存是否够执行该命令,如果不够,则执行淘汰策略
- redis执行命令,返回结果
有哪些淘汰策略
在4.0以后的版本中,有以下策略
- noeviction: 可能导致内存增加的命令直接返回错误,所以不包括del和一些其他命令
- allkeys-lru: 按照最近最少使用算法淘汰,淘汰范围为所有的key
- volatile-lru: 按照最近最少使用算法淘汰,淘汰范围为设置了过期时间的key
- allkeys-random: 随机淘汰,淘汰范围为所有的key
- volatile-random: 随机淘汰,淘汰范围为设置了过期时间的key
- volatile-ttl: 淘汰ttl最短的key
- volatile-lfu: 按照最少访问频率淘汰,淘汰范围为设置了过期时间的key
- allkeys-lfu: 按照最少访问频率淘汰,淘汰范围为所有的key
可以按照以下方式记忆:
redis淘汰策略有:不淘汰、最近最少使用(lru)、随机淘汰、最短过期时间(ttl)、最少访问频率(lfu)。
除了不淘汰和ttl,剩下的又有两种分类,所有的key(allkeys)、有过期时间的key(volatile)
其中noeviction是默认的淘汰策略,同时如果其他淘汰策略无法淘汰合适的内存大小,也会进入该模式
如何选择淘汰策略
如果你不知道怎么选,直接使用allkeys-lru。这是官方推荐的策略(This is a good pick if you are unsure)。
如果所有的key都会被持续地、周期性地被访问,或者你希望分布是均匀的(所有的节点都有相同的访问概率)。这里应该是想说数据没有热点,那就使用allkeys-random
当你创建缓存对象的时候,你可以通过不同的ttl告诉redis哪些数据更应该被淘汰,这时使用volatile-ttl
LRU如何工作
redis的LRU不是标准的lru,而是一种近似算法。
基本原理是,在每个key中记录最后一次访问时间,然后每次随机选出N个key,把N个key中访问时间最小的淘汰。
其中取样个数N可通过CONFIG SET maxmemory-samples <count>或者配置文件中配置。
官网的例子是如果取样是10,那么就非常接近标准LRU算法了
LFU如何工作
LRU仅按照最后一次访问时间作为判断标准,对于部分情况是不够准确的。
假设有个key实际上很少使用,但就在淘汰开始前突然被访问了一次,那么LRU不会淘汰这个key。这里潜藏的风险就是很可能删除了一个当时暂时未被访问,但是以后可能会被高频访问的数据。
以上是对官方文档的不标准翻译
LFU使用8位来记录访问频率。为了实现如此少的位保存足够高的频率,redis使用了一种叫做Morris counter的算法,具体原理暂时不去深究。
redis提供了两个配置项来调整LFU算法
1 | |
decay-time 意为衰退时间,如果不做衰退处理,频率记录只会越来越高,直到上限。文档特别指出不要把这个值设置为0
log-factor 这个值用来限定能够记录的最高频率。redis只用了8位记录频率,那么最高就是255,当访问频率高到一定程度后,频率记录就始终是255,分辨不出高低了。这个值越高,一定程度就会越高。官方给了一个表
| factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits |
|---|---|---|---|---|---|
| 0 | 104 | 255 | 255 | 255 | 255 |
| 1 | 18 | 49 | 255 | 255 | 255 |
| 10 | 10 | 18 | 142 | 255 | 255 |
| 100 | 8 | 11 | 49 | 143 | 255 |
过期策略
redis过期策略有两种:懒删除和定时扫描。官方称其为passive way、active way
懒删除
每次访问key时,判断key是否已经过期,过期了就删除
定时扫描
redis将会每秒进行10次扫描,每次扫描按照以下流程
- 从过期字典(记录了所有设置了过期时间的key)中随机挑选20个key
- 删除其中过期的key
- 如果过期的数据占据了25%,那么重复步骤1
除了官网内容外,书中还提及redis为了防止过度扫描,规定了一次扫描不能超过25毫秒,这25毫秒内是停止服务的。此外扫描还可能由于内存回收导致卡死。
因此如果发生了缓存雪崩,除了请求击穿到数据库外,redis本身也可能出现一定程度的卡顿
从节点和AOF
当有key过期时,redis会写入一条DEL命令,这个命令会被写入AOF文件以及发送给从节点。所以从节点不会主动进行过期处理,全部依赖主节点的同步