Redis缓存淘汰

摘要

Redis是一款优秀的、开源的内存数据库,我在阅读Redis源码实现的过程当中,时时刻刻能感觉到Redis做者为更好地使用内存而费尽各类心思,例如最明显的是对于同一种数据结构在不一样应用场景下提供了基于不一样底层编码的实现(如压缩列表、跳跃表等)。今天咱们暂时放下对Redis不一样数据结构的探讨,来一块儿看看Redis提供的另外一种机制——内存淘汰机制。程序员

初衷

Redis内存淘汰指的是用户存储的一些键被能够被Redis主动地从实例中删除,从而产生读miss的状况,那么Redis为何要有这种功能?这就是咱们须要探究的设计初衷。Redis最多见的两种应用场景为缓存和持久存储,首先要明确的一个问题是内存淘汰策略更适合于那种场景?是持久存储仍是缓存?这个问题很显然的我就不回答了。redis

假设咱们有一个Redis服务器,服务器物理内存大小为1G的,咱们须要存在Redis中的数据量很小,这看起来彷佛足够用很长时间了,随着业务量的增加,咱们放在Redis里面的数据愈来愈多了,数据量大小彷佛超过了1G,可是应用还能够正常运行,这是由于操做系统的可见内存并不受物理内存限制,而是虚拟内存,物理内存不够用不要紧,操做系统会从硬盘上划出一片空间用于构建虚拟内存,好比32位的操做系统的可见内存大小为2^32,而用户空间的可见内存要小于2^32不少,大概是3G左右。好了,咱们庆幸操做系统为咱们作了这些,可是咱们须要知道这背后的代价是不菲的,不合理的使用内存有可能发生频繁的swap,频繁swap的代价是惨痛的。因此回过头来看,做为有追求的程序员,咱们仍是要当心翼翼地使用好每块内存,把用户代码能解决的问题尽可能不要抛给操做系统解决。算法

说到这里,对于这个“初衷”咱们彷佛寻到了一个听起来蛮有道理的解释,内存的淘汰机制的初衷是为了更好地使用内存,用必定的缓存miss来换取内存的使用效率。数据库

做为Redis用户,如何使用Redis提供的这个特性呢?看看下面配置缓存

# maxmemory <bytes>
复制代码

咱们能够经过配置redis.conf中的maxmemory这个值来开启内存淘汰功能,至于这个值有什么意义,咱们能够经过了解内存淘汰的过程来理解它的意义:bash

客户端发起了须要申请更多内存的命令(如set)。 Redis检查内存使用状况,若是已使用的内存大于maxmemory则开始根据用户配置的不一样淘汰策略来淘汰内存(key),从而换取必定的内存。 若是上面都没问题,则这个命令执行成功。 maxmemory为0的时候表示咱们对Redis的内存使用没有限制。服务器

内存淘汰策略

内存淘汰只是Redis提供的一个功能,为了更好地实现这个功能,必须为不一样的应用场景提供不一样的策略,内存淘汰策略讲的是为实现内存淘汰咱们具体怎么作,要解决的问题包括淘汰键空间如何选择?在键空间中淘汰键如何选择?数据结构

Redis提供了下面几种淘汰策略供用户选择,其中默认的策略为noeviction策略:dom

  • noeviction:当内存使用达到阈值的时候,全部引发申请内存的命令会报错。
  • allkeys-lru:在主键空间中,优先移除最近未使用的key。
  • volatile-lru:在设置了过时时间的键空间中,优先移除最近未使用的key。
  • allkeys-random:在主键空间中,随机移除某个key。
  • volatile-random:在设置了过时时间的键空间中,随机移除某个key。
  • volatile-ttl:在设置了过时时间的键空间中,具备更早过时时间的key优先移除。 这里补充一下主键空间和设置了过时时间的键空间,举个例子,假设咱们有一批键存储在Redis中,则有那么一个哈希表用于存储这批键及其值,若是这批键中有一部分设置了过时时间,那么这批键还会被存储到另一个哈希表中,这个哈希表中的值对应的是键被设置的过时时间。设置了过时时间的键空间为主键空间的子集。

选择策略

咱们了解了Redis大概提供了这么几种淘汰策略,那么如何选择呢?淘汰策略的选择能够经过下面的配置指定:优化

# maxmemory-policy noeviction
复制代码

可是这个值填什么呢?为解决这个问题,咱们须要了解咱们的应用请求对于Redis中存储的数据集的访问方式以及咱们的诉求是什么。同时Redis也支持Runtime修改淘汰策略,这使得咱们不须要重启Redis实例而实时的调整内存淘汰策略。

下面看看几种策略的适用场景:

  • allkeys-lru:若是咱们的应用对缓存的访问符合幂律分布(也就是存在相对热点数据),或者咱们不太清楚咱们应用的缓存访问分布情况,咱们能够选择allkeys-lru策略。
  • allkeys-random:若是咱们的应用对于缓存key的访问几率相等,则可使用这个策略。
  • volatile-ttl:这种策略使得咱们能够向Redis提示哪些key更适合被eviction。
  • 另外,volatile-lru策略和volatile-random策略适合咱们将一个Redis实例既应用于缓存和又应用于持久化存储的时候,然而咱们也能够经过使用两个Redis实例来达到相同的效果,值得一提的是将key设置过时时间实际上会消耗更多的内存,所以咱们建议使用allkeys-lru策略从而更有效率的使用内存。

非精准的LRU: 上面提到的LRU(Least Recently Used)策略,实际上Redis实现的LRU并非可靠的LRU,也就是名义上咱们使用LRU算法淘汰键,可是实际上被淘汰的键并不必定是真正的最久没用的,这里涉及到一个权衡的问题,若是须要在所有键空间内搜索最优解,则必然会增长系统的开销,Redis是单线程的,也就是同一个实例在每个时刻只能服务于一个客户端,因此耗时的操做必定要谨慎。为了在必定成本内实现相对的LRU,早期的Redis版本是基于采样的LRU,也就是放弃所有键空间内搜索解改成采样空间搜索最优解。自从Redis3.0版本以后,Redis做者对于基于采样的LRU进行了一些优化,目的是在必定的成本内让结果更靠近真实的LRU。

总结

本文的内容主要仍是问题驱动的,为介绍Redis内存淘汰机制,本文从问题出发,经过解决什么是Redis内存淘汰机制?Redis内存淘汰机制应用场景是什么?初衷是什么?咱们怎么开启这个功能?咱们可配哪些淘汰策略?淘汰策略如何选择?等问题来谈Redis内存淘汰机制,但愿本文能给你们带来必定的收获和启发。

相关文章
相关标签/搜索