redis内存淘汰

Redis是基于内存存储,常用于数据的缓存,所以Redis提供了对键的过期时间的设置,实现了几种淘汰机制便于适应各种场景。

  • 设置过期时间:我们可以在设置键时设置expire time,也可以在运行时给存在的键设置剩余的生存时间,不设置则默认为-1,设置为-1时表示永久存储。

清除过期key 的方式

定时删除

设置键的过期时间时,创建一个 Timer ,当过期时间到临时,立刻删除键。
内存友好型策略,一旦键过期,就会被删除,并释放所占用的内存,Cpu 不友好,当一批数量比较多的键过期时,正好遇上Cpu 紧张的时段,这时候需要的是Cpu处理能力,而不是内存,显然 Cpu 时间用在删除过期键上,会对服务器的响应时间和吞吐量造成影响。另外当前 Redis 时间事件(无序链表O(N))无法高效处理大量时间事件,所以定时删除并不是一种好的定时删除策略。

惰性删除

不管过期的键,在这种策略下,当键在键空间中被取出时,首先检查取出的键是否过期,若过期删除该键,否则,返回该键。
很明显,惰性删除依赖过期键的被动访问,对于内存不友好,如果一些键长期没有被访问,会造成内存泄露(垃圾数据占用内存)。我们知道,Redis是依赖内存的,所以惰性删除也不是一个好的策略。

定期删除

由定时删除算法,定期的去检查一定的数据库,删除一定的过期键。通过合理的删除操作执行的时长和频率,达到合理的删除过期键。

生成RDB文件时

执行 SAVEBGSAVE 时 ,数据库键空间中的过期键不会被保存在RDB文件中

载入RDB文件时

  1. Master 载入RDB时,文件中的未过期的键会被正常载入,过期键则会被忽略。
  2. Slave 载入 RDB 时,文件中的所有键都会被载入,当同步进行时,会和Master 保持一致。

AOF 文件写入时

数据库键空间的过期键的过期但并未被删除释放的状态会被正常记录到 AOF 文件中,当过期键发生释放删除时,DEL 也会被同步到 AOF 文件中去。

重新生成 AOF文件时

执行 BGREWRITEAOF 时 ,数据库键中过期的键不会被记录到 AOF 文件中

主从复制

  1. Master 删除 过期 Key 之后,会向所有 Slave 服务器发送一个 DEL命令,从服务器收到之后,会删除这些 Key
  2. 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中通过存储键值使用时间和使用次数的方式实现。