Redis面试题-Redis过期策略及实现原理
Redis面试题
Redis过期策略及实现原理
Redis 过期策略及实现原理#
描述#
我们在使用 Redis 时,一般会设置一个过期时间,当然也有不设置过期时间的,也就是永久不过期。当我们设置了过期时间,Redis 是如何判断是否过期,以及根据什么策略来进行删除的。
redis 过期时间设置#
语法#
以秒为单位设置过期,这是最常用的方式#
EXPIRE KEY time
字符串独有的方式#
SETEX KEY_NAME TIMEOUT VALUE
说明#
除了 字符串 自己独有设置过期时间的方法外,其他方法都需要依靠 EXPIRE 方法来设置时间,如果没有设置时间,那缓存就是永不过期。
如果设置了过期时间,之后又想让缓存永不过期,使用 persist KEY。
三种过期策略#
定时删除#
含义#
在设置 KEY 的过期时间的同时,为该 KEY 创建一个定时器,让定时器在 KEY 的过期时间来临时,对 KEY 进行删除。
优点#
该方法可以保证内存被尽快释放。
缺点#
若过期 KEY 很多,删除这些 KEY 会占用很多的 CPU 时间,在 CPU 时间紧张的情况下,CPU 不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些 KEY。
定时器的创建耗时,若为每一个设置过期时间的 KEY 创建一个定时器(将会有大量的定时器产生),性能影响严重。
懒汉式删除#
含义#
KEY 过期的时候不删除,每次通过 KEY 获取值的时候去检查是否过期,若过期,则删除,返回 null。
优点#
删除操作只发生在通过 KEY 取值的时候,而且只删除当前 KEY,所以对 CPU 时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的 KEY 了)。
缺点#
若大量的 KEY 在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)。
定期删除#
含义#
每隔一段时间执行一次删除过期 KEY 操作。
优点#
通过限制删除操作的时长和频率,来减少删除操作对 CPU 时间的占用。
缺点#
在内存友好方面,不如 ” 定时删除”(会造成一定的内存占用,但是没有懒汉式那么占用内存),在 CPU 时间友好方面,不如 ” 懒汉式删除”(会定期的去进行比较和删除操作,cpu 方面不如懒汉式,但是比定时好)。
难点是合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了),每次执行时间太长,或者执行频率太高对 cpu 都是一种压力。每次进行定期删除操作执行之后,需要记录遍历循环到了哪个标志位,以便下一次定期时间来时,从上次位置开始进行循环遍历。
说明#
memcached 只是用了惰性删除,而 redis 同时使用了惰性删除与定期删除,这也是二者的一个不同点(可以看做是 redis 优于 memcached 的一点)。
对于懒汉式删除而言,并不是只有获取 KEY 的时候才会检查 KEY 是否过期,在某些设置 KEY 的方法上也会检查,比如 SETNEX 命令,因为 SETNX 命令是在 KEY 不存在的情况下才设置,因为,如果不做过期 KEY 检查,那么直接设置,就会与我们原来的意思相违背。
定时任务#
单线程的 redis,如何知道要运行定时任务?
redis 是单线程的,线程不但要处理定时任务,还要处理客户端请求,线程不能阻塞在定时任务或处理客户端请求上,那么,redis 是如何知道何时该运行定时任务的呢?
Redis 的定时任务会记录在一个称为最小堆的数据结构中。这个堆中,最快要执行的任务排在堆的最上方。在每个循环周期,Redis 都会将最小堆里面已经到点的任务立即进行处理。处理完毕后,将最快要执行的任务还需要的时间记录下来,这个时间就是接下来处理客户端请求的最大时长,若达到了该时长,则暂时不处理客户端请求而去运行定时任务。
配置#
Redis 中定期删除使用的是统一的一个定时器,定时器执行的时长默认为 10,具体配置如下:
提高它的值将会占用更多的 cpu,当然相应的 redis 将会更快的处理同时到期的许多 key,以及更精确的去处理超时。 hz 的取值范围是 1~500,通常不建议超过 100,只有在请求延时非常低的情况下可以将值提升到 100。
Redis 采用的过期策略#
说明#
Redis 采用的是懒汉式删除 + 定期删除。
懒汉式删除流程#
在进行 GET 或 SETNX 等操作时,先检查 KEY 是否过期;
若过期,删除 KEY,然后执行相应操作;
若没过期,直接执行相应操作;
定期删除流程#
简单而言,对指定 N 个库的每一个库随机删除小于等于指定 M 个过期 KEY,具体流程如下:
遍历每个数据库(就是 redis.conf 中配置的 ”database” 数量,默认为 16)
检查当前库中的指定个数个 KEY(默认是每个库检查 20 个 KEY,注意相当于该循环执行 20 次,循环体是下边的描述)
如果当前库中没有一个 KEY 设置了过期时间,直接执行下一个库的遍历随机
获取一个设置了过期时间的 KEY,检查该 KEY 是否过期,如果过期,删除 KEY 判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。
对于定期删除,在程序中有一个全局变量 current_db 来记录下一个将要遍历的库,假设有 16 个库,我们这一次定期删除遍历了 10 个,那此时的 current_db 就是 11,下一次定期删除就从第 11 个库开始遍历,假设 current_db 等于 15 了,那么之后遍历就再从 0 号库开始(此时 current_db==0)。
更多#
原文链接:链接
其他:目录
更多文章,可以关注公众号:嗨客网 IT 教程
本作品采用《CC 协议》,转载必须注明作者和本文链接