<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg> <p>我说的是真实情况,有很多候选人都折在这一道看似简单的Redis面试题上。</p>
讯享网
面试官:“我看你简历上写的熟悉Redis是吧,那你说说如果Redis服务器的内存满了,它将会怎么处理?”
候选人略一思考,说:“如果Redis内存满了的话,那肯定是得进行LRU操作了啊。”
面试官:“你确定会进行LRU吗?那你们redis.conf中的maxmemory-policy参数是如何配置的?”
候选人想了想,似乎什么都没想起来,说:“抱歉,这个我确实不太清楚。”
本文我们就来深入聊聊这道面试题,以及与其相关的底层技术实现原理。
Redis还提供了另外一个配置参数 —— maxmemory,该参数是用来配置内存大小的。一旦Redis所使用的内存超过了该参数,就会启动 maxmemory-policy 中所配置的策略。
这里需要说明的是,对于64位的操作系统,maxmemory 参数的默认值为0,表示没有内存大小限制;而对于32位的操作系统,maxmemory 参数的默认值为3GB。
举个例子:
maxmemory 6gb
maxmemory-policy allkeys-lru 或者 volatile-lru
只有这样配置 maxmemory-policy 参数,才如上文中的候选人所说,当Redis的内存满了会进行LRU操作。
其实 maxmemory-policy 参数的配置项有很多,下面且听我一一道来。
noeviction(默认) :当Redis所使用的内存达到了maxmemory的时候,就不再提供除了del、hdel、unlink以外的其他写操作,但读操作可以继续进行。
volatile-lru:通过近似LRU(最近最少使用)算法来淘汰Redis中的key,淘汰范围是Redis中设置过期时间的key。
volatile-lfu:通过LFU(最不常用)算法来淘汰Redis中的key,淘汰范围是Redis中设置过期时间的key。
volatile-ttl: 淘汰Redis中剩余生存时间最短的key,淘汰范围是Redis中设置过期时间的key。
volatile-random:以随机的方式淘汰Redis中的key,淘汰范围是 Redis中设置过期时间的key。
allkeys-lru:通过近似LRU(最近最少使用)算法来淘汰Redis中的key,淘汰范围是Redis中的所有key。
allkeys-lfu:通过LFU(最不常用)算法来淘汰Redis中的key,淘汰范围是Redis中的所有key。
allkeys-random:以随机的方式淘汰Redis中的key,淘汰范围是Redis中的所有key。
上述的八种策略中,除了noeviction策略之外,剩下的7种策略都会涉及到淘汰key的操作。
而对于淘汰key的判断和执行,是通过每次的用户请求来进行触发的,步骤如下图所示:
如果有一条许久不曾被访问的冷数据,偶然间被访问了一次,如果按照LRU算法的规则,这条数据就会被定义为热数据,短期内不会被淘汰。
但按照LFU算法的规则,这条数据可能仍然是最近一段时间内被访问频率最低的,还是会被淘汰掉的。
LRU关注于“最近是否被访问”,LFU关注于“最近的访问频率如何”,相对而言,后者的实现方式更加合理一些。
但根据Redis官方文档所述,Redis并没有按照标准的LRU算法进行实现,而是采取了一种“近似LRU”的实现方式。
其原因在于:
(1)Redis内部只实现了Hash表,而标准的LRU算法则需要双向链表 + Hash表两种数据结构。换言之,需要在Redis内存中再额外增加一个双向链表,这个内存消耗的代价是不可接受的。
(2)每个Redis请求,LRU的双向链表也需要进行同步操作,这种实现方式对性能影响不小。
而Redis本身实现的“近似LRU”算法,则远远不需要付出这么大的内存和性能代价,但也牺牲了一些内存淘汰的准确率。
我们来看一下具体的实现方式:
(1)Redis通过引入LRU时钟值的方式,来记录数据每次被访问的时间。
(2)随机挑选出一批数据,将其一一与“按照空闲时间升序排列的”待淘汰数据池中的数据进行比对。
btw:空闲时间 = 当前时钟值 - LRU时钟值,待淘汰数据池的默认大小为16。
若待淘汰数据池中已满,且该数据的空闲时间最小,则跳过;
若待淘汰数据池中未满,且该数据要写入的位置为空,则执行写入操作;
若待淘汰数据池中未满,且该数据要写入的位置不为空,则将目前处于该位置及后面的元素都后移一个位置,再执行写入操作;
若待淘汰数据池中已满,则将数据要写入位置前面的元素都前移一个位置,再执行写入操作;
批次数据的数量,是由 maxmemory-samples 参数来决定的,默认值为5。该参数值设置越大,就越能提升内存淘汰的准确率,但也会增加服务器的CPU消耗。
(3)从待淘汰数据池中,淘汰掉空闲时间最大的那条数据,同时会根据Redis中的惰性删除配置,来决定在Redis字典中执行同步删除还是异步删除。
(4)此时若释放的内存空间未能小于 maxmemory 参数值,则重复执行上述步骤中的(2)(3),直至达成目标为止。
而换言之,如果候选人能够在技术面试中,有理有据地把这道题所涉及到的技术底层实现原理跟面试官讲清楚,也是一个大大的加分项。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/148590.html