过期原理
过期时间会不会被延长?
首先要明确一点,你不给key设置过期时间和有效期,这个key是一直存在的。除非调用del命令删除
- 过期时间是不会被延长的;
- 剔除过期时间的命令:DEL, SET, GETSET 和所有的 *STORE 命令,这样就成永久的了
- 自增 key 中存储的值的 INCR , 向list中新增一个值 LPUSH, 或者修改 hash 域的值 HSET ,这些都不会修改 key 的过期时间。
- 可以通过命令( PERSIST)把过期时间清除,让key变成永久的
- key使用 RENAME 改名后,过期时间被转移到新 key 上。除了过期时间会转移到新key上,其余的属性也会转移到新key上
- expire命令, 返回1表示设置过期时间成功, 0表示key不存在
过期和持久
redis的过期时间是绝对的依赖服务器时间
- key 的过期时间以绝对 Unix 时间戳的方式存储。这意味无论 Redis 是否运行,过期时间都会流逝。
- 服务器的时间必须稳定准确,这样过期时间才能更准确。如果在两个时间相差较多的机器之间移动 RDB 文件,那么可能会出现所有的 key
在加载的时候都过期了。 - 运行的 Redis 也会不停的检查服务器的时间,如果你设置一个带有 1000 秒过期时间的key,然后你把服务器的时间向前调了 2000秒,那么这个 key 会立刻过期,不是等 1000 秒后过期。
Redis 如何淘汰过期 Key
redis中的key过期后,并不是redis立马主动的删除key
被动淘汰(业务控制)
当客户端访问一个已经过期的key的时候,redis这时会发现key已经过期了, 给客户端返回一个nil, 然后删除这个key;这样会导致那些长时间不妨问的key过期以后会一直存在, 浪费内存;
主动淘汰(redis内部轮询)
Redis 周期性主动随机检查一部分被设置生存时间的 key,那些已经过期的 key 会被从 key 空间中删除。
Redis每秒执行10次下面的操作:
- 从带有生存时间的 key 的集合中随机选 20 进行检查。
- 删除所有过期的key。
- 如20里面有超过25%的key过期,立刻继续执行步骤1
这是一个狭义概率算法,我们假设我们选出来的样本 key 代表整个 key 空间,我们继续过期检查直到过期 key 的比例降到 25% 以下。这意味着在任意时刻已经过期但还占用内存的 key 的数量,最多等于每秒最多写操作的四分之一。
复制连接和 AOF 文件是如何处理过期
当一个 key 过期时,DEL 操作会先在主服务器上执行,然后同时在AOF文件和当前配置的所有的从服务器实例上执行;保证数据一致性
内存回收策略
redis的内存是一个固定的大小,并不是没有上限,但是redis内存要是满了, 怎么办? 有没有一些释放内存的方法呢
最大内存配置选项
maxmemory 配置选项使用来配置 Redis 的存储数据所能使用的最大内存限制。可以通过在内置文件redis.conf中配置,也可在Redis运行时通过命令CONFIG SET来配置。例如,我们要配置内存上限是100M的Redis缓存,那么我们可以在 redis.conf 配置如下:
maxmemory 100mb
设置 maxmemory 为 0 表示没有内存限制。在 64-bit 系统中,默认是 0 无限制,但是在 32-bit 系统中默认是 3GB。
当存储数据达到限制时,Redis 会根据情形选择不同策略,或者返回errors(这样会导致浪费更多的内存),或者清除一些旧数据回收内存来添加新数据。
我们打开redis的配置文件会看到关于最大内存和达到最大内存的一些回收和处理策略
vi 6379.conf //配置文件一般放在/etc/redis/6379.conf
回收策略
当内存达到限制时,Redis 具体的回收策略是通过 maxmemory-policy 配置项配置的
以下的策略都是可用的:
- allkeys-lru:从所有的数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
- allkeys-random:从所有数据集(server.db[i].dict)中任意选择数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lfu:从所有的数据集中,优先淘汰使用频率低的数据
- volatile-lfu: 从已设置过期时间的数据集中,优先淘汰使用频率低的数据
- noenviction:不清除数据,只是返回错误,这样会导致浪费掉更多的内存,对大多数写命令(DEL 命令和其他的少数命令例外)
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
回收过程
理解回收过程是运作流程非常的重要,回收过程如下:
- 一个客户端运行一个新命令,添加了新数据。
- Redis检查内存使用情况,如果大于maxmemory限制,根据策略来回收键。
- 一个新的命令被执行,如此等等。
lru和lfu(redis4.0新添加的策略)的区别
lfu :LFU原理使用计数器来对key进行排序,每次key被访问的时候,计数器增大。计数器越大,可以约等于访问越频繁。具有相同引用计数的数据块则按照时间排序。
优点:可以更好的表示热度数据,LFU效率要优于LRU,且能够避免周期性或者偶发性的操作导致缓存命中率下降的问题。
缺点:需要记录所有数据的访问记录,内存消耗较高;需要基于引用计数排序,性能消耗较高。
lru:如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。
Redis3.0对近似LRU算法进行了一些优化。新算法会维护一个候选池(大小为16),池中的数据根据访问时间进行排序,第一次随机选取的key都会放入池中,随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。当放满后,如果有新的key需要放入,需要淘汰的时候,则直接从池中选取最近访问时间最小(最久没被访问)的key淘汰掉就行。
相关的一些命令
设置Redis最大占用内存大小为100M
config set maxmemory 100mb
获取设置的Redis能使用的最大内存大小
config get maxmemory
获取当前内存淘汰策略:
config get maxmemory-policy
通过命令修改淘汰策略:
config set maxmemory-policy allkeys-lru