【redis问题总结】

redis问题总结

  • 不论是开发中还是面试,redis都是最常见的,因此对redis的深入了解也有助于开发和面试

redis的使用场景

  • 缓存
  • 分布式锁
  • 计数器
  • 保存token
  • 消息队列
  • 延迟队列
缓存的问题
  • 穿透,击穿,雪崩,双写一致性,持久化,数据过期,淘汰策略
分布式锁的问题
  • setnx,redisson
保存token,消息队列,延迟队列的问题
  • 数据类型
其他的问题
  • 集群 (主从,哨兵,集群)
  • 事务
  • redis为什么这么快

缓存穿透

查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库

例:一个GET请求:api/article/getById/-1
缓存穿透请求示例
此时通过url请求id为-1的文章,首先回到redis中请求,如果没有则到数据库中请求,此时数据库中也没有查询到数据,则不写入缓存返回为空,但如果有大量的这样的请求则可能会导致数据库的崩溃,此时就需要采取一些策略防止这样的情况发生。

方案一: 缓存空数据,查询返回的数据为空,扔把这个空结果进行缓存 {key:1,value:null}

  • 优点:简单

  • 缺点:消耗内存,可能发生不一致的问题

    • 加入请求了一个id为99的文章,缓存和数据库都没有这条数据,做缓存空数据之后,数据库中添加了这条id为99的数据,这是如果再去请求id为99的数据因为缓存中设置了空数据,则直接从缓存中返回空数据,造成数据不一致的情况

方案二: 使用布隆过滤器
布隆过滤器

  • 内存占用较少,没有多余的key
  • 实现复杂,存在误判 (这个误判是由于布隆过滤器的机制决定的)
  • 布隆过滤器的原理简单介绍
    • 布隆过滤器实质上就是一个位图
    • bitmap(位图):相当于是一个以(bit)位为单位的数组,数组中每个单元只能存储二进制数0或1
    • 布隆过滤器作用:布隆过滤器可以用于检索一个元素是否存在一个集合中
      假如有一个Id1的数据查看是否存在,只需要三次hash这个id1然后到集合中相应的位置查看该位置是否都为1,如果都为1则表示id1存在,如果有一个不为1则表示不存在
      布隆过滤器判断id1是否存在示意图
      前面说过布隆过滤器存在误判的情况,下图展示了误判的情况
      布隆过滤器误判的情况
      误判率:数组越小误判率就越大,数组越大误判率就越小,但同时带来了更多的内存消耗
      在这里插入图片描述

缓存击穿

给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮
缓存击穿示意图

  • 解决方案
    • 互斥锁
    • 逻辑过期
  • 互斥锁原理

    当有两个线程同时发起请求的时候,假如线程一查询到数据过期然后获取到了互斥锁,那么线程一就去查询数据库并重建缓存数据,然后写数据到缓存,最后释放所,这时候在线程一还没有完成释放锁的过程的时候线程二也请求的缓存,并发现数据过期,这时候线程二尝试获取锁失败,则线程二会休眠一会再次尝试查询缓存,如果不中就继续尝试直到命中缓存返回数据

互斥锁原理解析
互斥锁特点:强一致,性能差

  • 逻辑过期 (不设置过期事件,只是设置一个逻辑过期的值)
    {“id”:“123”,“value”:“逻辑过期”,“expire”:153489345}

    加入有一个线程1去查询缓存,发现缓存逻辑过期,然后尝试获取互斥锁,如果获取锁成功,则开启一个新的线程,查询数据库重建缓存,线程1则返回过期的数据,新建的线程写入缓存成功后释放互斥锁,如果在线程1新开启的线程还未释放所资源时,线程二访问了缓存发现缓存逻辑过期,则线程二会尝试获取互斥锁,如果获取锁失败则返回过期的数据,如果线程三在线程1新开的线程释放了锁资源的情况下访问缓存,则线程三获取的就是最新的为过期的缓存数据。

逻辑过期流程图
逻辑过期的特点:高可用,性能优,数据有延迟不能保证数据绝对一致

缓存雪崩

缓存雪崩是指在同一时段大量的缓存key同时失效或者redis服务宕机,导致大量请求到达数据库,带来巨大压力。

缓雪崩示例图
解决方案:

  • 给不同的key的TTL添加随机值
  • 利用redis集群提高服务的可用性(哨兵模式,集群模式)
  • 给缓存业务添加降级限流策略 (nginx或Spring cloud gateway)
  • 给业务添加多级缓存(Guava或者Caffeine)
    注意:降级限流策略,穿透,击穿,雪崩都适用
    《缓存三兄弟》
    穿透无中生有key,布隆过滤null隔离。
    缓存击穿过期key,锁与非期解难题。
    雪崩大量过期key,过期时间要随机。
    缓存问题三兄弟,降级限流是保底。

数据一致性

  • 场景说明
    • 先删除缓存或者先修改数据库
      数据不一致说明
      从上图可只无论是先删除缓存还是先操作数据库总会出现数据不一致的情况。解决上面的这个问题可以有两种思路:一致性要求高的方案,允许延迟一致但要保证用户体验的方案。
  • 双写一致性解决数据不一致问题

当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致

双写一致性流程示意图

  • 读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设定超时事件
  • 写操作:延迟双删
    延迟双闪流程图
    之所以延迟删除缓存,是为了让数据库集群进行数据同步,删除两次是为了防止脏数据,注意即便这样做之后仍然有脏数据的风险。
  • 分布式锁

    分布式锁通过为错做缓存的线程加锁保障每次操作缓存的时候只有一个线程,这样就避免了脏数据的出现,但又因为锁的限制严重降低了系统的性能,因为每次只能有一个线程去处理缓存的写操作,其他的线程读数据的话只能等待写操作释放锁

分布式锁原理图
分布式锁适用于读多写少,要求强一致性的系统
总结:分布式锁具有强一致,低性能的特征

  • 异步通知保证数据的最终一致性
    • 适用MQ通知
      在这里插入图片描述
    • 基于Canal的异步通知:
      在这里插入图片描述
      二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。

redis持久化

  • RDB - 快照模式
  • AOF
  1. RDB(快照模式)

RDB也被叫做redis数据快照。简单俩说就是把内存中的所有数据都记录到此盘中。当redis实例发生故障重启后,从磁盘读取快照文件,恢复数据

 主动备份
 - 使用save和bgsave这两个命令执行RDB,
 - save 由redis主进程来执行RDB,会阻塞所有命令
 - bgsave 开启子进程执行RDB,避免主进程收到影

redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:
在这里插入图片描述

  • RDB执行原理

bgsave开始时会fork主进程到子进程,子进程共享主进程的数据。完成fork后读取内存数据并写入RDB文件。
在这里插入图片描述

fork采用的是copy-on-write技术:

  • 当主进程执行读操作时,访问共享内存
  • 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
    在这里插入图片描述
  1. AOF

    AOF全称为Append Only File(追加文件)。redis处理的每一个写命令都会记录在AOF文件中,可以看作时命令日志文件

    AOF默认是关闭的需=需要到redis.conf文件中手动开启
    开启AOF配置

    AOF的命令记录频率也可以通过配置文件进行配置
    配置AOF命令记录频率
    AOF配置项说明
    因为是记录命令,AOF文件会比RDB文件大的多。而且会记录对一个key’的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让aof文件执行重写功能,用最少的命令达到相同的效果。
    在这里插入图片描述
    Redis也可以在触发阈值的情况下自动去重写AOF文件,阈值可以在redis.conf文件中配置
    在这里插入图片描述

  2. 总结
    RDB与AOF对比:
    RDB和AOF各有自己的优缺点,如果对数据的安全性要求较高,在开发中往往结合两者同时使用
    RDB和AOF对比

数据过期策略

假如redis的key过期后会立即删除吗?
Redis对数据设置的有效时间,数据过期以后,就需要将数据从内存删除掉。可以按照不同的规则进行删除,这种删除规则就被称为数据的删除策略(数据过期策略)。惰性删除、定期删除

  • 惰性删除策略

    设置key过期时间后,我们不去管它,当需要该key时,我们再检查它是否过期,如果过期我们就删掉它,反之则返回该key
    在这里插入图片描述

    • 优点:对CPU友好,只会在使用该key的时候检查过期,对于很多用不到的key不用浪费时间去检查是否过期
    • 缺点:对内存不友好,如果一个key已经过期,但是一直没有被使用,那么该key就会一直在内存中,内存永远不会被释放
  • 定期删除策略

    每隔一段时间就会对一些key做过期检查,并删除过期的key(从数据库中取出一定数量的随机key进行检查,并删除其中过期的key)

    定期清理有两种模式

    • SLOW模式是定时任务,执行频率默认时10hz,每次不超过25ms,通过修改redis.conf的hz选项来调整这个次数
    • FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms

    总结:

    • **优点:**可以通过限制删除操作执行的时长和频率来减少删除操作对cpu的影响。另外定期删除,也能有效缓解过期key占用的内存
    • **缺点:**难以确定操作执行的时长和频率

    Redis的过期删除策略:惰性删除+定期删除这两种策略进行配合使用

数据淘汰策略

假如缓存过多,内存是有限的,内存被占满了怎么办?

数据淘汰策略:当redis中的内存不够用时,测试在向redis中添加新的key,那么redis会按照某一种规则将内存中的数据删除掉,这种删除数据的规则被称之为redis的数据删除策略

redis支持八种不同的策略来删除key:

  • noeviction:不淘汰任何key,但是内存满时不写入任何数据,默认就是这种策略
  • volatile-ttl: 对设置了ttl的key,比较key的剩余的ttl值,ttl值越小越先被淘汰
  • allKeys-random:对全体key,随机进行淘汰
  • volatile-random:对设置了ttl的key,随机进行套套
  • allKeys-lru:对全体key,基于LRU算法进行淘汰
  • volatile-lru:对设置了ttl的key,基于LRU算法进行淘汰
  • allKeys-lfu:对全体key,基于LFU算法进行淘汰
  • volatile-lfu:对设置了ttl的key,基于LFU算法进行淘汰
    在这里插入图片描述

数据淘汰策略使用建议

  1. 有限使用allKeys-lru策略。充分利用LRU算法的优势,把最近最常访问的数据留在缓存中。如果业务有明显的冷热数据区分建议使用
  2. 如果业务中数据访问频率差别不大,,没有明显的冷热数据区分,建议使用allKeys-random随机淘汰策略
  3. 如果业务中有置顶的需求,可以使用volatile-lru策略,同时置顶数据不设置过期时间,这些数据就一直不被删除,会淘汰其他过期的数据
  4. 如果业务中有短时高频访问的数据,可以使用allKeys-lfu或volatile-lfu策略

最后:redis其他的相关问题,会在下一章中介绍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沂蒙山旁的水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值