一篇文章搞懂Redis缓存

目录

  • 一、什么是缓存
    • 缓存的优缺点
      • 缓存的优点
      • 缓存的缺点
  • 二、Redis缓存
  • 三、缓存的更新策略
    • 主动更新策略
  • 四、缓存穿透
    • 解决方案
  • 五、缓存雪崩
    • 解决方案
  • 六、缓存击穿
    • 解决方案

一、什么是缓存

我们都知道在计算机中内存的速度比磁盘要快非常多,如果每次都要去磁盘获取数据,是不是每次的速度都很慢。如果有一个数据是我们要经常使用的,如果每次都从磁盘获取数据,那速度是每次都是那么慢。所以就想到是不是可以把数据放到内存中,这样在第一次获取之后将数据存放在内存中,这样速度就快很多。
一篇文章搞懂Redis缓存_第1张图片
现在的计算机世界中到处都用到了缓存技术。并且缓存也不一定是要放在速度快的介质中才是缓存,应该是只要能提升速度的方法都可以称作缓存,例如一个文件非常大,每次查询一条一条遍历下去很慢,是不是可以把常用的记录单独存放在一个文件中,这样每次先查这个缓存文件就可以大大提高性能。

缓存的优缺点

缓存既然可以大大提升性能,那是不是什么都可以使用缓存?

凡事都是有优缺点的,缓存也不例外,如果他的缺点我们可以接受,那缓存就是适合的技术。

缓存的优点

  1. 降低后端负载
    例如:后端数据库可以可以接受的请求是有一定的瓶颈的,请求太多就会导致服务无法处理后续的请求,如果有些数据可以直接放在客户端,那用户就不需要请求服务器了。
  2. 提高读写效率、降低相应时间
    例如:有些数据是非常常用的数据,如果每次都要去磁盘找这些数据,那速度是一致的,非常慢。但其实可以将这些常用数据放在缓存中,每次先从缓存中找,就可以提升大多数请求的性能。

缓存的缺点

  1. 数据一致性问题
    例如:缓存往往都是将数据复制了一份放在缓存中的,用户看到的都是复制的数据,如果原数据更新了,复制的数据不能及时同步,导致原数据和缓存数据不一致
  2. 代码维护成本变高
    例如:有了缓存就要维护缓存,每次查询都要先查缓存再查磁盘,也要判断要不要维护缓存数据等各种情况
  3. 运维难度变高
    例如:使用Redis缓存,运维就要保证Redis应用不能宕机,否则就要重大事故等

二、Redis缓存

Redis应用是一个基于内存的NoSQL数据库,它具有非常高的读写性能,所以在Web应用开发中非常适合用来做缓存,去承接高并发的用户请求。
一篇文章搞懂Redis缓存_第2张图片
例如上面这样典型的业务场景,客户端的请求先请求Redis,如果查询到数据了则直接返回,如果没有查询到数据,则查询数据,然后将数据放到Redis缓存中并返回给客户端。

三、缓存的更新策略

前面分析到缓存是有数据一致性的问题的,所以使用缓存的数据要是那些更新频率不高的数据,否则维护缓存的成本将会变高,使用缓存也就没什么意义了。

就算是更新频率不高的数据也会发生变更,那应该如何更新缓存的数据呢?有什么策略呢?

内存淘汰 超时剔除 主动更新
说明 利用Redis应用自己的内存淘汰机制,在内存不足时自动淘汰部分数据,下次查询时更新缓存 给数据加过期时间,过期自动删除,下次查询更新缓存 编写业务逻辑,在修改数据的同时也更新缓存
一致性 一般
维护成本

看了这个表格,我们其实发现不同的更新策略各有优略,这就需要根据不同的业务场景来进行选择了。
例如有些业务数据几乎就不会发生改变,就算变化了也不会有什么较大的影响就可以选择内存淘汰策略,好处就是完全不需要维护,但是如果数据要经常发生变化,就需要使用主动更新策略,但是也有有一定难度。

主动更新策略

在实际业务场景中,基本都是在更新数据库的同时更新缓存,再加上超时剔除来作为兜底方案的更新策略。

但是会存在三个问题:

  1. 更新数据库后是删除缓存还是更新缓存?
    一般都是选择删除缓存,然后用户查询时再将数据库的数据保存到缓存中。不选更新缓存是因为每次更新数据库都更新缓存,无效写操作太多。但是也要根据实际业务场景来进行选择。

  2. 如何保证缓存与数据库操作是同时成功或者失败的?
    单体引用就将缓存操作和数据库操作放在一个事务中,这样可以保证从缓存操作失败数据库操作回滚。分布式系统使用分布式事务来解决,但是所有的都无法保证缓存回滚。

  3. 先操作缓存还是先操作数据库?
    一般都是先操作数据再操作缓存,因为缓存操作比较快。基本都是选择先操作数据库再操作缓存,详细看如下两张图。

一篇文章搞懂Redis缓存_第3张图片
一篇文章搞懂Redis缓存_第4张图片
对比这两张图,我们可以发现如果先操作缓存再操作数据库,缓存里的值有可能是过时的数据。先操作数据库再操作缓存,可以保证缓存的值是最新的值。
并且如果先操作数据库,如果执行失败回滚了,对缓存完全无影响,但是如果先操作缓存,则会导致很多缓存失效。

其实缓存更新还有一种策略,就是先操作缓存,然后再开启一个异步线程将缓存的值更新到数据库中

四、缓存穿透

缓存穿透是指客户端请求的数据在缓存和数据库中都不存在(大量请求访问一个不存在的值),这样缓存永远都不会生效,请求全部都会打到数据库。如果请求量过大,很容易造成数据库服务宕机。如下图:
一篇文章搞懂Redis缓存_第5张图片

解决方案

1、缓存空对象
缓存空对象就是将不存在的值保存一个空值在缓存中,这样后续的请求查询缓存就会返回一个空值给客户端。
一篇文章搞懂Redis缓存_第6张图片
但是这样虽然可以防止缓存穿透的问题,但是还会带来其他问题:

  • 额外的内存消耗
  • 可能造成短期的不一致

2、布隆过滤器
将数据库中所有的查询条件,放入布隆过滤器中,当一个查询请求过来时,先经过布隆过滤器进行查,如果判断请求查询值存在,则继续查;如果判断请求查询不存在,直接丢弃。

还有一些主动解决缓存穿透的方案:
1、增强id的复杂度,避免被猜测到id的规律
2、做好数据基础格式的校验
3、加强用户权限管理
4、做好热点数据库限流

五、缓存雪崩

缓存雪崩是指在同一个时间段大量的可缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
一篇文章搞懂Redis缓存_第7张图片

解决方案

如果是因为同一时间段大量缓存key过期导致的

  • 给不同的key设置随机均匀的过期时间

如果是因为Redis宕机

  • 利用Redis集群提高服务可用性
  • 给缓存业务添加降级限流策略
  • 给业务添加多级缓存

六、缓存击穿

缓存击穿问题也叫热点key问题,也就是一个高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会瞬间给数据库带来巨大的冲击。
一篇文章搞懂Redis缓存_第8张图片

解决方案

1、利用互斥锁
就是在缓存重建时只有一个线程去重建,其他线程都阻塞等待。
一篇文章搞懂Redis缓存_第9张图片

2、利用逻辑过期
就是缓存key是永不过期的,key的value值会保存业务数据和一个逻辑过期时间,请求访问数据主动判断数据是否过期,如果过期了则返回过期值并创建一个异步线程来更新缓存。

一篇文章搞懂Redis缓存_第10张图片

你可能感兴趣的:(#,Redis,缓存,redis,spring)