redis内存淘汰
Redis是基于内存存储,常用于数据的缓存,所以Redis提供了对键的过期时间的设置,实现了几种淘汰机制便于适应各种场景。
- 设置过期时间:我们可以在设置键时设置expire time,也可以在运行时给存在的键设置剩余的生存时间,不设置则默认为-1,设置为-1时表示永久存储。
清除过期key 的方式
定时删除
设置键的过期时间时,创建一个 Timer ,当过期时间到临时,立刻删除键。
内存友好型策略,一旦键过期,就会被删除,并释放所占用的内存,Cpu 不友好,当一批数量比较多的键过期时,正好遇上Cpu 紧张的时段,这时候需要的是Cpu处理能力,而不是内存,显然 Cpu 时间用在删除过期键上,会对服务器的响应时间和吞吐量造成影响。另外当前 Redis 时间事件(无序链表O(N))无法高效处理大量时间事件,所以定时删除并不是一种好的定时删除策略。
惰性删除
不管过期的键,在这种策略下,当键在键空间中被取出时,首先检查取出的键是否过期,若过期删除该键,否则,返回该键。
很明显,惰性删除依赖过期键的被动访问,对于内存不友好,如果一些键长期没有被访问,会造成内存泄露(垃圾数据占用内存)。我们知道,Redis是依赖内存的,所以惰性删除也不是一个好的策略。
定期删除
由定时删除算法,定期的去检查一定的数据库,删除一定的过期键。通过合理的删除操作执行的时长和频率,达到合理的删除过期键。
生成RDB文件时
执行 SAVE
或 BGSAVE
时 ,数据库键空间中的过期键不会被保存在RDB文件中
载入RDB文件时
-
Master
载入RDB时,文件中的未过期的键会被正常载入,过期键则会被忽略。 -
Slave
载入 RDB 时,文件中的所有键都会被载入,当同步进行时,会和Master 保持一致。
AOF 文件写入时
数据库键空间的过期键的过期但并未被删除释放的状态会被正常记录到 AOF
文件中,当过期键发生释放删除时,DEL
也会被同步到 AOF
文件中去。
重新生成 AOF文件时
执行 BGREWRITEAOF
时 ,数据库键中过期的键不会被记录到 AOF
文件中
主从复制
-
Master
删除 过期Key
之后,会向所有Slave
服务器发送一个DEL
命令,从服务器收到之后,会删除这些Key
。 -
Slave
在被动的读取过期键时,不会做出操作,而是继续返回该键,只有当Master
发送DEL
通知来,才会删除过期键,这是统一、中心化的键删除策略,保证主从服务器的数据一致性。
配置阈值
redis.conf 配置文件中配置最大可用内存
// 设置Redis 最大可用内存为 1024mb
maxmemory 1024mb
命令操作
//获取设置的Redis能使用的最大内存大小
127.0.0.1:6379> config get maxmemory
//设置Redis最大占用内存大小为1024M
127.0.0.1:6379> config set maxmemory 1024mb
配置内存淘汰机制选项
redis.conf 配置文件中配置最大可用内存
// 设置Redis 淘汰机制为 volatile-lfu
maxmemory-policy volatile-lfu
命令操作
//获取设置的Redis内存淘汰机制
127.0.0.1:6379> config get maxmemory-policy
//设置Redis内存淘汰机制
127.0.0.1:6379> config set maxmemory-policy volatile-lfu
- 没有配置时,
默认为noeviction
不驱逐(删除)数据
名称 | 描述 |
noeviction | 当内存不足写入新数据时,写入操作会报错,同时不删除数据 |
volatile-lru | 从 已设置过期时间 的数据集中挑选 最近最少使用 的 Key 淘汰 |
volatile-ttl | 从 已设置过期时间 的数据集中挑选 将要过期 的 Key 淘汰 |
volatile-random | 从 已设置过期时间 的数据集中挑选 任意 Key 淘汰 |
volatile-lfu | 从 已设置过期时间 的数据集中挑选 最不经常 使用的 Key 淘汰 |
allkeys-lru | 当内存不足写入新数据时淘汰 最近最少使用 的 Key |
allkeys-random | 当内存不足写入新数据时随机选择 任意 Key 淘汰 |
allkeys-lfu | 当内存不足写入新数据时移除 最不经常使用 的 Key |
常见的缓存算法
- LRU (Least recently used) 最近最少使用,如果数据最近被访问过,那么将来被访问的几率也更高。
- LFU (Least frequently used) 最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。
- FIFO (Fist in first out) 先进先出, 如果一个数据最先进入缓存中,则应该最早淘汰掉。
LRU
- 实现 LRU 算法需要附加一个链表,刚被访问的数据放在链表头。当空间满的时候,会踢掉链表尾部的元素。所以链表的元素排列顺序就是元素最近被访问的时间顺序。
- 在redis中通过存储键值使用时间的方式,然后通过维护一个16大小的池子的方式去实现的。
LFU
- 根据 key 的最近访问频率进行淘汰,很少被访问的优先被淘汰,被访问多的则留下来。
- 在redis中通过存储键值使用时间和使用次数的方式实现。