Redis 内存淘汰策略 | 您所在的位置:网站首页 › redis的数据淘汰策略有哪些 › Redis 内存淘汰策略 |
实际上redis定义了【八种内存淘汰策略】来处理redis内存满的情况 noeviction:直接返回错误,不淘汰任何已经存在的redis键 allkeys-lru:所有的键使用lru算法进行淘汰 volatile-lru:有过期时间的使用lru算法进行淘汰 allkeys-random:随机删除redis键 volatile-random:随机删除有过期时间的redis键 volatile-ttl:删除快过期的redis键 volatile-lfu:根据lfu算法从有过期时间的键删除 allkeys-lfu:根据lfu算法从所有键删除 设置多大的缓存容量合适?具体结合应用数据实际访问特点和成本开销来综合考虑。一般建议把缓存容量设置为总数据量的 15% 到 30%,兼顾访问性能和内存空间开销。 对于 Redis 来说,一旦确定了缓存最大容量,比如 4GB,就可以执行下面命令: CONFIG SET maxmemory 4gb不过,缓存被写满是不可避免的。 缓存替换需要解决两个问题: 决定淘汰哪些数据 如何处理那些被淘汰的数据 Redis 缓存有哪些淘汰策略?Redis 4.0 之前一共实现了 6 种内存淘汰策略,在 4.0 之后,又增加了 2 种策略。我们可以按照是否会进行数据淘汰把它们分成两类 不进行数据淘汰的策略,只有 noeviction 这一种。 会进行淘汰的 7 种其他策略。会进行淘汰的 7 种策略,我们可以再进一步根据淘汰候选数据集的范围把它们分成两类: 在设置了过期时间的数据中进行淘汰,包括 volatile-random、volatile-ttl、volatilelru、volatile-lfu(Redis 4.0 后新增)四种。 在所有数据范围内进行淘汰,包括 allkeys-lru、allkeys-random、allkeys-lfu(Redis 4.0 后新增)三种。(1)默认情况下,redis在使用的内存空间超过maxmemory值时,并不会淘汰数据,也就是设置的noeviction 策略。对应到redis缓存,也就是值,一旦缓存被写满了,再有写请求到来时,redis不会提供服务,而是直接返回错误。(因此不推荐使用) (2)对于 volatile-random、volatile-ttl、volatile-lru 和 volatile-lfu这四种淘汰策略,它们筛选的候选数据范围,被限制在已经设置了过期时间的键值对上。也正是因为如此,即使缓存没有写满,这些数据如果过期了,也会被删除。 volatile-ttl 在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。 volatile-random 就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。 volatile-lru 会使用 LRU 算法筛选设置了过期时间的键值对。 volatile-lfu 会使用 LFU 算法选择设置了过期时间的键值对。(LFU算法会在LRU算法的基础上,同时考虑数据的访问时效性和数据的访问次数)(3)对于allkeys-lru、allkeys-random、allkeys-lfu这三种淘汰策略的备选淘汰数据范围,扩大到了所有键值对,无论这些键值对是否设置了过期时间。 allkeys-random 策略,从所有键值对中随机选择并删除数据; allkeys-lru 策略,使用 LRU 算法在所有数据中进行筛选。 allkeys-lfu 策略,使用 LFU 算法在所有数据中进行筛选也就是说,如果一个键值对被删除策略选中了,即使它的过期时间还没到,也需要被删除。当然,如果它的过期时间到了但未被策略选中,同样也会被删除。 怎么使用呢? 优先使用allkeys-lru策略。这样,可以充分利用LRU算法的优势,把最近最常访问的数据留在缓存中,提升应用的访问性能。如果你的业务数据中有明显的冷热数据的区分,建议使用allkeys-lru策略 如果业务应用中的数据访问频率不大,没有明显的冷热数据区分,建议使用allkeys-random策略,随机淘汰数据即可 如果业务有置顶的需求,比如置顶新闻、置顶视频,那么,可以使用 volatile-lru策略,同时不给这些置顶数据设置过期时间。这样一来,这些需要置顶的数据一直不会被删除,而其他数据会在过期时根据 LRU 规则进行筛选 LRU算法LRU 算法的全称是 Least Recently Used,从名字上就可以看出,这是按照最近最少使用的原则来筛选数据,最不常用的数据会被筛选出来,而最近频繁使用的数据会留在缓存中。 那具体是怎么筛选的呢? LRU会把所有的数据组织成一个链表,链表的头和尾分别表示MRU端和LRU段,分别代表最近最常使用的数据和最近最不常用的数据。 如下图 其实,LRU 算法背后的想法非常朴素:它认为刚刚被访问的数据,肯定还会被再次访问,所以就把它放在 MRU 端;长久不访问的数据,肯定就不会再被访问了,所以就让它逐渐后移到 LRU 端,在缓存满时,就优先删除它。 不过,LRU算法在实际实现时,需要用链表管理所有的缓存数据,这会带来额外的空间开销。而且,当有数据被访问时,需要在链表上把该数据移动到MRU端,如果有大量数据被访问,就会带来很多链表移动操作,会很耗时,进而降低redis缓存性能。 所以,在redis中,LRU算法被做了简化,以减轻淘汰数据对缓存性能的影响。 具体来说,redis会默认记录每一个数据的最近一次访问的时间戳(由键值对数据结构RedisObject 中的 lru 字段记录)。 然后,redis在决定淘汰的数据时,第一次会随机选出N个数据,把它们作为一个候选集合。 接下来,redis会比较这N个数据的lru字段,把lru字段值最小的数据从缓存中淘汰出去。Redis 提供了一个配置参数 maxmemory-samples,这个参数就是 Redis 选出的数据个数N。 例如,我们执行如下命令,可以让 Redis 选出 100 个数据作为候选数据集: CONFIG SET maxmemory-samples 100 当再次淘汰数据时,redis需要挑选数据进入第一次淘汰时创建的候选集合。这里的挑选标准是:能进入候选集合的数据的lru字段值小于候选集合中最小的 lru 值。 当有新数据进入候选集合后,如果候选数据集合中的数据个数达到了maxmemory-samples,redis就把候选集合集中lru子弹值最下的数据淘汰出去。这样一来,Redis 缓存不用为所有的数据维护一个大链表,也不用在每次数据访问时都移动链表项,提升了缓存的性能。 一旦被淘汰的数据被选定后,Redis 怎么处理这些数据呢? 如何处理被淘汰的数据?一般来说,一旦被淘汰的数据选定后,如果这个数据时干净数据,那我们就直接删除;如果这个数据是脏数据,我们需要把它写回数据库
不过,对于redis来说,它决定了被淘汰的数据后,会把它们删除。即使淘汰的数据时脏数据,redis也不会把它们写回数据库。所以,我们在使用redis缓存时,如果数据被修改了,需要在数据修改时就将它写回数据库。否则,这个脏数据被淘汰时,会被redis删除,而数据库里也没有最新的数据了。 小结 Redis 4.0 版本以后一共提供了 8 种数据淘汰策略,从淘汰数据的候选集范围来看,我们有两种候选范围:一种是所有数据都是候选集,一种是设置了过期时间的数据是候选集。另外,无论是面向哪种候选数据集进行淘汰数据选择,我们都有三种策略,分别是随机选择,根据 LRU 算法选择,以及根据 LFU 算法选择。当然,当面向设置了过期时间的数据集选择淘汰数据时,我们还可以根据数据离过期时间的远近来决定。 一般来说,缓存系统对于选定的被淘汰数据,会根据其是干净数据还是脏数据,选择直接删除还是写回数据库。但是,在 Redis 中,被淘汰数据无论干净与否都会被删除,所以,这是我们在使用 Redis 缓存时要特别注意的:当数据修改成为脏数据时,需要在数据库中也把数据修改过来 选择哪种缓存策略是值得我们多加琢磨的,它在筛选数据方面是否能筛选出可能被再次访问的数据,直接决定了缓存效率的高与低。 很简单的一个对比,如果我们使用随机策略,刚筛选出来的要被删除的数据可能正好又被访问了,此时应用就只能花费几毫秒从数据库中读取数据了。而如果使用 LRU 策略,被筛选出来的数据往往是经过时间验证了,如果在一段时间内一直没有访问,本身被再次访问的概率也很低了。 所以,建议,先根据是否有始终会被频繁访问的数据(例如置顶消息),来选择淘汰数据的候选集,也就是决定是针对所有数据进行淘汰,还是针对设置了过期时间的数据进行淘汰。候选数据集范围选定后,建议优先使用 LRU 算法,也就是,allkeys-lru 或volatile-lru 策略。 当然,设置缓存容量的大小也很重要,我的建议是:结合实际应用的数据总量、热数据的体量,以及成本预算,把缓存空间大小设置在总数据量的 15% 到 30% 这个区间就可以 |
CopyRight 2018-2019 实验室设备网 版权所有 |