redis的过期策略以及定时器的实现

 Redis是客户端服务器结构的程序,客户端与服务器通过网络通信,所以对于keys *这种的操作在大型企业中不太建议,生产环境下的key会非常多,Redis是但现成的服务器,执行keys*的时间非常长,就会导致redis服务器阻塞,无法给其他客户端提供服务。如果redis(缓存)被一个key阻塞了,其他的请求会直接到数据库。

expire用途 

expire作用是给指定的 key 设置过期时间,设置的时间单位是秒,key 存活时间超出这个指定的值,就会被自动删除
使用场景:手机验证码~~该验证码,5分钟内有效~~
基于 redis 实现分布式锁为了避免出现不能正确解锁的情况通常都会在加锁的时候设置一下过期时间.(所谓的使用redis 作为分布式锁就是给 redis 里写一个特殊的 key value)

redis的过期策略: 

不能直接整体遍历key,效率非常低,

redis整体策略是:定期删除和惰性删除

  • 定期删除:每次抽取一部分进行验证过期时间。保证抽取检查过程足够快。为了避免一次性删除大量过期键导致服务器阻塞,Redis将每次执行的删除数量限制在一个较小的范围内(否则会导致redis的CPU使用率增加)。
  • 惰性删除:当客户端尝试访问一个键时,Redis会检查该键是否已过期。如果键已过期,则会立即删除该键并返回空结果。

通过惰性过期和定期过期策略的结合,Redis可以高效地管理键的过期,并保持内存的合理使用
 

 为啥不使用定时器进行过期key删除

1.redis 中并没有采取 定时器 的方式来实现过期 key 删除

2.如果有多个 key 过期,也可以通过一个定时器来高效/节省cpu的前提下来处理多个 key ~~
基于 优先级队列 或者 基于 时间轮 都可以实现比较高效的定时器~~
为啥redis没有采取这种定时器的方式呢?
猜测: 基于定时器实现,势必就要引入多线程了.
 

定时器的实现原理:

定时器是在某个时间到达后去执行某个任务;

1. 基于优先级队列/堆

自定义优先级,优先级高的先出。

在Redis的key过期场景中,过期时间越早,优先级越高,此时队首元素就是过期时间最早的,优先级最高的。此时定时器只需要分配一个线程,让这个线程检查队首元素,看是否过期。

但是这个扫描线程不能扫描的太频繁(需要节省cpu开销),可以 根据当前时间和队首过期时间设置一个等待,当时间到了再唤醒这个等待。

如果在队首元素休眠过程中,有了一个新的任务,新任务比队首元素更快过期,可以在新任务添加的过程中,唤醒刚才线程重新检查队首元素,再根据时间差重新调整阻塞时间。

2.基于时间轮实现的定时器

它可以高效地管理大量的定时任务。

时间轮是一个环形的数据结构,分为多个槽(slot)。每个槽代表一个时间间隔,槽中存放着在该时间间隔内要执行的定时任务。时间轮按照固定的时间间隔进行旋转,当时间轮旋转到当前时间所在的槽时,就触发该槽中的定时任务。

时间轮的实现流程如下:
1. 初始化时间轮,确定时间间隔和槽数量。
2. 将定时任务添加到时间轮中,计算任务应该添加到哪个槽。
3. 时间轮按照固定的时间间隔开始旋转。
4. 当时间轮旋转到当前时间所在的槽时,触发该槽中的定时任务。
5. 定时任务执行完毕后,可以选择删除任务或重新添加到时间轮中。

通过使用时间轮,定时器可以高效地管理大量的定时任务,避免了每个任务都需要单独计时的开销。同时,时间轮还可以支持动态添加和删除任务,提供了灵活性。

redis的过期策略以及定时器的实现_第1张图片

几个基本的通用命令具体看redis官方文档

keys: 用来查看配规则的

eyexists: 用来判定指定 key 是否存在

del: 删除指定的 key

expire: 给keg设置过期时间

ttl: 查询 key 的过期时间

type: 查询 key 对应的 value 的类型

你可能感兴趣的:(Java,redis,redis,数据库,缓存)