Redis 学习笔记 内存淘汰策略

Posted Johnny*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 学习笔记 内存淘汰策略相关的知识,希望对你有一定的参考价值。

@TOC

Redis中对于过期键并不是马上从内存中删除。它有三种策略: 定时删除、。
定时删除: 定时删除就是为key设置生存时间,它保证过期键值会在过期后立马被删除,其所占用的内存也会随之释放。
缺点:
立即删除对CPU是会造成负担,会抢占CPU的时间。这会产生大量的性能消耗,同时也会影响数据的读取操作。 这是一种拿时间换空间的策略。

惰性删除: 数据到达过期时间,不做处理。等下次访问数据时,如果未过期,返回数据。发现已经过期 了,删除返回不存在。
缺点:
对内存不友好。如果一个键已经过期,而这个键又仍然保存在数据库中,那么这个过期键不被删除,所占用的内存就不会被释放掉。使用惰性删除策略时,如果数据库有非常多的过期键,而这些过期键又没有被访问到,那么它们也许永远都不会被删除(除非用户手动执行FLUSHDB)。这种情况可以看做是一种内存泄漏——即无用的垃圾数据占用着大量内存,而服务器却不会去释放它们。这对服务器来说是一种极大的浪费。
这是一种拿存储 空间换时间的策略。

定期删除

定期删除是定时删除和惰性删除的一个折中。指的是redis服务器设置一个检查时间,每隔一段时间执行一次删除过期键操作。它会周期性地轮询redis库中的设置了时效性的数据,采用随机抽取键的策略,利用过期数据占比的方式来控制删除的频度。
特点是:周期性抽取存储空间(随机抽查、重点抽查)

定期删除策略的难点是确定删除操作执行的时长和频率:如果删除操作太过于频繁或者执行时间过于长,定期删除策略就会退变为定时删除,以至于将CPU时间过多地消耗在删除过期键上。可如果删除操作执行得太少,或执行时间太短,定时删除就会退变惰性删除,出现浪费内存的情况。所以服务器必须合理地设置执行时长和执行频率。

上述三种策略仍然不能保证过期的键会被合时宜的删除:会有key没有被定期删除抽查到也没有被惰性删除使用到。
Redis还提供了最后的屏障。

内存淘汰策略

分为两个维度: 一个是在所有设置了过期时间的key中筛选(也就是volatile),另一个是在所有键中筛选(也就是allkeys)。
删除的算法有: LRU、LFU、ttl和random。

volatile-lru(least recently used): 对所有设置了过期时间的key使用LRU算法进行删除。
allkeys-lru: 对所有key使用LRU算法删除。
volatile-lfu: 对所有设置了过期时间的key使用LFU算法进行删除。
allkeys-lfu:对所有key使用LFU算法进行删除。
volatile-random :对所有设置了过期时间的key随机删除。
allkeys-random:对所有key随机删除。
volatile-ttl: 删除马上要过期的key。
noeviction : 不会淘汰任何key。默认情况下redis是使用的noeviction。

如何配置、修改缓存策略:

一种方式是通过修改redis.conf 文件:设置maxmemory-policy
另一种是通过命令方式设置

config set maxmemory-policy  缓存策略(如lru)

什么是LRU

LRU是一种页面置换算法,会淘汰页面中最近最少使用的页面。对于Redis来说它会淘汰掉最近最少使用的key。

Redis是如何判断 数据是否过期的呢?

Redis有一个过期字典(类似Hash表),过期字典的值指向Redis数据库的某个key,其值是一个longlong类型的整数,保存了这个key所指向的数据库键的过期时间(毫秒 精度的Unix时间戳)。

Redis给数据设置过期时间的作用是什么?

  1. 设置过期时间有助于缓解内存消耗。 因为内存是有限的,因此它就显得十分宝贵。如果缓存中的所有数据都是一直存活的,那么缓存很快就会被填满。
  2. 除此之外,对于某些场景可能需要对数据设置时效,如短信登录验证码。

缓存常见问题

缓存穿透

【概述】

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中的,所以一定会去数据库中查询。
数据库中也查不到数据所以,这将导致这个不存在的数据每次都要到数据库中查询,造成缓存穿透。

【解决方案】

最基本的就是对参数进行合法性校验,一些不合法的数据(查询数据库id小于0、传入的邮箱格式不对等)直接在前端筛掉,避免进入后端,减轻后端压力。

第一种: 单个key穿透

如果是单个key穿透,持久层(数据库)查询不到Redis就会缓存空,就是缓存无效key。 那么下一次在查询这个不存在的key时,就会先判断缓存中是否存在这个key,有则返回空,没有则查询之后缓存,并对这个空值设置一个很小的过期时间。

缺点是:
上述方案可以解决请求的key变化不频繁的情况。如果黑客恶意攻击,每次构建不同请求的key,会导致Redis中缓存大量无效的key。

第二种: 多个key穿透

先判断是否是一个存在的key,如果key合法。那么会查询数据库。如果不是一个合法的key,那么就不在数据中查询。
(1)、 如果数据量不大可以把key放在redis的set集合中。

(2)、如果数据量非常大(上亿级别),可以考虑使用布隆过滤器。

布隆过滤器是一种帮助我们快速判断一给定数据在不在海量数据中的数据结构。具体操作是:
利用布隆过滤器,我们可以预先将海量数据映射到布隆过滤器中,然后判断用户每次发来请求参数是否存在与布隆过滤器中。不存在的话直接返回请求参数 错误信息给客户端。存在的话,才会去查询缓存、数据库。

具体流程:

在这里插入图片描述
Java Guide

缓存击穿

【概述】
缓存击穿是指一个key非常热点,被高并发地进行访问。当这个key在失效的瞬间,持续的大并发就缓存穿透,直接请求数据库。对数据库造成巨大压力。

【解决方案】

  1. 设置热点数据永不过期。
  2. 加互斥锁。使用分布式锁 ,保证对每个key同一时间内只能有一个线程去数据库查询其他线程没有获得分布式锁的权限。因此只需等待即可,这种方式把高并发地压力转移到了分布式锁上。因此对分布式锁的考验很大。
    在这里插入图片描述

缓存雪崩

如果缓存都集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在了数据库上,造成数据库短时间内承受大量 请求,这么多请求会使得数据库服务雪崩。
解决方案:

造成缓存雪崩可能有两个原因:1.缓存宕机。 2. 缓存大面积失效
针对前者:

  1. 采用Redis集群,避免单机故障导致整个缓存系统不可用。
  2. 限流,避免同时处理大量请求。

针对后者:
3. 设置不同的 失效时间,避免集中失效,尽可能地使失效时间均匀分布。
4. 设置缓存永不失效。

热点key

【概述】
某个key的访问频率非常频繁,导致Redis服务器的压力剧增,没法保证Redis可以正常提供服务。

【解决方案】

  1. 扩容。添加集群中的从服务器,提高读数据的能力
  2. 考虑使用本地缓存,把redis中的热点数据直接缓存在本地的服务器中,减少对Redis的访问。

Redis持久化机制

Redis支持吃持久化,而且支持两种不同的持久化操作。一种是快照(snapshotting),另一种是值追加文件(append-only file,AOF)

RDB 操作

Redis 可以通过创建快照来获取存储在内存里的数据在某个时间点上的副本。
RDB是Redis默认采用的持久化方式,在Redis.conf配置文件下有以下配置:

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

RDB 触发条件

  1. 满足上述文件Redis.conf中定义的规则可以触发RDB操作
  2. 在flushall之后会触发
  3. 在关闭客户端连接之后会触发

在这里插入图片描述

【优点】

  1. 适合大规模的数据恢复
  2. 对数据的完整性要求不高

【缺点】
3. fork进程的时候会占用一定的内部空间
4. 需要一定时间间隔进行进程操作。

AOF

AOF就是日志式记录每个写操作,只许追加文件但不可以改写文件。Redis会在启动之初读取该文件重新构建数据,。即在恢复的时候将这个文件全部执行一遍

过程

aof保存的是appendonly.aof 文件,默认是不开启的。需要手动开启配置,在redis.conf文件中:

appendonly yes

如果AOF文件中有错误,这个时候redis是启动不起来的。可以使用redis-check-aof 进行修复:
redis-check-aof --fix appendonly.aof
文件恢复正常之后重启即可直接恢复了

AOF文件默认是无限追加,文件会越来越大,可以通过以下参数进行设置

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

如果aof文件大于64mb了,就会fork一个新进程来重写文件。

在这里插入图片描述

双写不一致

在这里插入图片描述

在这里插入图片描述

以上是关于Redis 学习笔记 内存淘汰策略的主要内容,如果未能解决你的问题,请参考以下文章

Redis内存淘汰策略

Redis个人笔记

Redis过期键删除策略和内存淘汰策略

Redis过期删除策略和内存淘汰策略

聊聊 Redis 内存淘汰策略

缓存三连击——聊聊Redis过期策略?内存淘汰机制?再手写一个LRU 吧!