IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Redis缓存——穿透、雪崩、击穿、双写一致性 -> 正文阅读

[大数据]Redis缓存——穿透、雪崩、击穿、双写一致性

Redis缓存

什么是缓存

缓存就是数据交换的缓冲区,时临时存储数据的地方,一般读写性能比较高。比如CPU内部就有cache缓存,由于CPU运算的速度非常快,已经远远超过了内存的读写速度,以至于内存的读写速度降低了整体了性能,为了缓解这种速度差异矛盾,就再CPU内部增加了一块存储空间(缓存),用于存储CPU需要经常读写的数据,这样就不必要在内存中读写,使得CPU性能得到更好的发挥。因此才CPU的性能指标上缓存的大小也是很重要的一项。

在Web应用开发中,由于数据库需要从磁盘中加载数据,而磁盘IO的速度是比较慢的,因此数据库也需要缓存。当然在数据库内部也是有缓存的,但这还是不够快,因此就引入了其他的缓存中间件,如Redis、Memcache。在应用服务需要加载数据的时候,先去Redis中查询,如果没有命中再去数据中查询,这样就能使得系统整体的读写性能大大提高。

缓存作用模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JoHH0wwx-1646901981325)(C:\Users\Liuhd\AppData\Roaming\Typora\typora-user-images\image-20220310110531756.png)]

这里的客户端是指数据库的客户端,并不是与用户交互的应用客户端,一般来说就是后端应用服务层。当服务层需要查询数据时,先在Redis中查询,如果能查到就直接返回,如果没有再从数据库中查询,查到之后顺便把数据放入Redis中。

比如现在要根据id查询商铺的信息,大致流程如下:

在这里插入图片描述

这副流程图中还有很多的问题,藏着许多坑,接下来就来聊聊还存在什么问题。

缓存更新策略

缓存更新主要是解决缓存中的数据和数据库中的数据的一致性问题。

内存淘汰

Redis是基于内存的,数据都需要加载在内存中使用,但内存不像磁盘那样空间充足,所以Redis自己有一套内存淘汰机制,当内存不足时会自动淘汰部分数据,等下次查询时如果未命中就可以更新缓存,这样但这种方式存在很大的问题。

这种机制是无法控制的,淘汰的时候淘汰的是哪一部分数据、什么时候淘汰,也有可能内存比较大,很长一段时候都不会触发淘汰机制,这样就很长一段时间缓存和数据库数据不一致,所以一致性是比较差的。除非是静态数据,一般不会采用这种方式。

超时剔除

Redis里面添加数据的时候可以设置TTL过期时间,时间到期后会自动删除,等下次查询时再更新缓存。

这种方式数据一致性的强弱取决于过期时间TTL的长短,TTL长一点,一致性就差一点;TTL短一点,一致性就弱一点,但是如果过期时间过短,而数据的更新频率却比较低,这就会带来很多无效的缓存读写。这种方式数据一致性一般,维护起来也比较简单,适合数据变更不频繁的场景。

主动更新

主动更新,也就是再应用层编写业务逻辑,在修改数据库的同时,更新缓存。这种方式一致性是很高的,但维护成本是比较高的,还是隐藏着一些问题,到底是先更新数据库还是先更新缓存,看似简单顺序问题,却有很深的门道。

一般在高一致性需求场景下,就采用主动更新,并以超时剔除的作为兜底方案。也就是说,在正常情况下,修改数据库的同时更新缓存,但没有人能保证这种同时修改的原子性,如果更新缓存失败了,等过期时间一到,查询时就会从数据库中再写入新数据到缓存中,一段时间的数据不一致,但最终是一致的。

主动更新策略

缓存可以提升性能、缓解数据库压力,但是使用缓存也会导致数据不一致性的问题。有三种经典的缓存模式:

Cache Aside Pattern

旁路缓存模式,它的提出是为了尽可能地解决缓存与数据库的数据不一致问题。

  • 读的时候,先读缓存,缓存命中的话,直接直接返回数据,缓存没有命中的话,就去读数据库,从数据库中取出数据,放入缓存后,同时返回结果。

  • 写的时候,先更新数据库,然后再删除缓存。

    这里又有几个问题需要考虑?

    1. 为什么是删除缓存而不是同时更新缓存呢?

      • 首先多线程环境下可能造成数据不一致的问题、

        ①线程A先发起一个写操作,第一步先更新数据库

        ②线程B再发起一个写操作,第二步更新了数据库

        ③由于网络等原因,线程B先更新了缓存

        ④线程A更新缓存

        这时候缓存保存的是A的数据(老数据),数据库保存的是B的数据(新数据),数据不一致了,而直接删除缓存就不会出现这样的问题。

      • 其次,如果写的场景比较多,每次更更新了数据库都要更新缓存,但写期间数据都不一定被读,这些写的中间过程就是无效的,只有最后一次才是会被读到,如果要缓存的数据需要经过比较复杂的计算才能得到,但那些中间过程又是无效的,这样就造成了很大的性能浪费。

    2. 为什么是先操作数据库,然后再操作缓存呢?

      • 先操作缓存

        排除正确执行的情况,现在又如下执行顺序:

        ①线程1先把要更新的v从缓存中删除,这时候切换到线程2

        ②线程2查询v发现缓存中不存在,然后去查询数据库把v原来的值写入缓存,这时候又切换到线程1

        ③线程1把要更新的v写入数据库

      在这里插入图片描述

      这时候,就出现了数据库和缓存数据不一致的情况。

      • 先操作数据

        同样排除正确执行的情况,先操作数据库也会出现问题:

        ①线程1要查询v发现未命中,然后去查询数据库, 没来及写入缓存,切换到线程2

        ②线程2要更新v直接更新了数据库,然后把缓存删除,这时候又切换回线程1

        ③线程1把刚刚读到的**(线程2更新前的数据)**写入缓存

        在这里插入图片描述

        这时候,又出现了缓存和数据库数据不一致的情况。

      既然两种方式都会出现,拿为啥还是选择了先操作数据库呢?

      先操作数据库再删除缓存,在会出现问题的情况中,要在线程1查询到数据和写入缓存的间隙中线程2完成更新数据库和删除缓存这两件时,要知道更新数据库可比写入缓存慢的多,所以这种情况出现的概率时非常低的,再加上有过期剔除的兜底方案,这样系统的可用性就大大提高了。

    3. 如何保证对数据库和缓存的操作同时失败或者成功呢?也就是如何保证原子性呢?

      • 对于单体系统,将缓存操作和数据库操作放在同一个声明式事务即可利用应用程序来保证。
      • 对于分布式系统,利用TCC 等分布式方案
Read/Write Through Pattern

读写穿透模式,服务端把缓存作为主要数据存储。应用程序跟数据库缓存交互,都是通过抽象缓存层完成的。

  • 读的时候,先从缓存中读取数据,读到就直接返回,没有读到就去数据库中查,然后写入缓存

    这和旁路缓存很像,但它多了一个抽象缓存层

在这里插入图片描述

  • 写的时候,先更新数据库,然后再删除缓存

    在这里插入图片描述

可以理解为,缓存和数据库整合为一个服务,由这个服务来维护一致性。调用者调用服务,无需关心怎么实现的一致性。但现在没有这样直接拿来可以用的组件,只能靠自己去维护开发,成本比较高。

Write Behind Caching Pattern

这种方式也是由一个服务来维护一致性,但却又一个很大的不同Read/Write Through是同步更新缓存和数据的;Write Behind则是只更新缓存,不直接更新数据库,通过批量异步的方式来更新数据库,效率比较高。MySQL的InnoDB Buffer Pool机制就使用到这种模式

1

缓存问题

缓存穿透

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远都不会生效,这些请求会直接到数据库。就是穿过缓存,直接访问数据库。如果这样的请求非常多,就会直接把数据库搞崩。

常见的解决方案有两种:

  • 缓存空对象

    2

    这中方式比较简单粗暴,就是当发现缓存和数据库中都不存在的时候,就在缓存中相对应存一个null,下次这个请求来的时候就会命中缓存。

    但这中方式也有弊端:

    1. 会缓存一些垃圾对象,占用额外的内存空间,一般设置一个短一点的有效期就能缓解。
    2. 可能造成短期的不一致,如果已经缓存了一个null,但这时候真的去数据库中插入了一条数据这时候就会造成不一致,解决的方法是插入和更新一样都去缓存中删一下。
  • 布隆过滤

    在这里插入图片描述

    布隆过滤器就是在缓存前面再加一层保护,每次数据写入都先加入布隆过滤器(类似于白名单),查询的时候先看看能否通过布隆过滤器,如果不能则直接拒绝,如果能在查询缓存。这样就能有效避免查询无效数据了,而导致缓存穿透了。

    同样布隆过滤器也有一些缺点:

    1. 存在误判,可能要查到的元素并没有在容器中,但是hash之后得到的k个位置上值都是1。如果bloom filter中存储的是黑名单,那么可以通过建立一个白名单来存储可能会误判的元素。
    2. 删除困难。一个放入容器的元素映射到bit数组的k个位置上是1,删除的时候不能简单的直接置为0,可能会影响其他元素的判断。
  • 做好数据基础格式的校验

  • 加强用户权限校验

  • 做好热点参数的限流

缓存雪崩

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

解决方案:

  1. 给不同的key设置随机的过期时间,使得这些key的过期时间分布在某个时间段内,而不是同时过期。
  2. 利用Redis集群提高服务的可用性。
  3. 给缓存业务增加降级限流策略
  4. 添加多级缓存

缓存击穿

缓存击穿是指一个被高并发访问且缓存重建业务比较复杂的key突然失效了,这时大量的请求会在瞬间给数据给带来巨大的冲击。

有时候在缓存中存储的不是在数据库中直接存储的数据,而是需要从多个数据库中的表中进行查询, 在这段时间就会有很多请求到达数据库。

3

常见的解决方案有:

  • 互斥锁

    互斥锁使用Redis里的setnx就可以简单的的实现

    setnx lock 1返回1说明上锁成功,返回0说明上锁失败已经被其他线程上锁。

    释放锁时直接del lock即可。还有一个问题就是如果释放锁之前程序出现问题,那么就会出现无法释放锁的情况。所以要在这个锁上加个过期时间,确保这个锁能被释放。

    4

    这种方式可能可能会出现死锁,而且线程需要等待性能受影响比较大。

  • 逻辑过期

    向缓存中添加数据的时候不设置TTL,而是增加一个过期时间的字段。

    这样当过期时间到了的时候,它还是会在缓存中,查询总是会命中,只不过在查询的时候会检查过期时间字段,如果发现过期了,先加锁然后开启一个线程去数据库中查询并写入缓存,然后再释放锁。如果发现已经被上锁了,就先返回已经过期的数据。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZps6sNY-1646901981348)(C:\Users\Liuhd\Desktop\屏幕截图 2022-03-10 161756.png)]这种方式会有一定时间段的不一致性。
    而是增加一个过期时间的字段。

    这样当过期时间到了的时候,它还是会在缓存中,查询总是会命中,只不过在查询的时候会检查过期时间字段,如果发现过期了,先加锁然后开启一个线程去数据库中查询并写入缓存,然后再释放锁。如果发现已经被上锁了,就先返回已经过期的数据。

在这里插入图片描述

这种方式会有一定时间段的不一致性。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 22:17:06  更:2022-03-11 22:17:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:45:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码