当前位置: 首页 > news >正文

Redis缓存应用场景【Redis场景上篇】

文章目录

  • 1.缓存基础
  • 2.缓存异步场景
    • 1.缓存穿透
    • 2.缓存击穿
    • 3.缓存雪崩
    • 总结
  • 3.缓存一致性

1.缓存基础

Redis由于性能高效,通常可以做数据库存储的缓存。一般而言,缓存分为服务端缓存和客户端缓存。缓存有以下三种模式:

  • Cache Aside(旁路缓存模式)
  • Read Write Through Cache(读写穿透模式)
  • Write Behind(异步缓存写入模式)

2.缓存异步场景

1.缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。由于缓存时不命中后查询DB时被动写入的,并且在DB查不到数据则不写入缓存,这就会导致这个请求每次都要到存储层查询,缓存毫无意义了。在流量大时,DB也可能会挂掉。

解决方案

  1. 接口增加校验,鉴权ID,直接拦截。
  2. 缓存空值(key-null),给这个key设置一个有效时间,在这个时间内这个key的请求直接拦截。
  3. 布隆过滤器。

2.缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据,由于并发用户过多,同时读缓存又没有读到数据,去到DB读取数据,引起DB压力过大。(一般是缓存时间到期,没来得及重新产生)

解决方案

  1. 热点数据增加过期时间,避免因为过期失效而被穿透。
  2. 重建缓存加互斥锁,线程争抢锁,拿到锁的线程查询数据库,然后重建缓存,争抢失败的,加一个睡眠然后循环重试。(重建的这个缓存,之后的请求就可以直接查询这个缓存)

3.缓存雪崩

缓存雪崩是指大量的应用请求因为异常无法在Redis缓存中进行处理,而是直接打到数据库,引起数据库压力过大甚至宕机。

解决方案

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  2. 重建缓存加互斥锁,线程争抢锁,拿到锁的线程查询数据库,然后重建缓存,争抢失败的,加一个睡眠然后循环重试。

总结

1、缓存击穿和缓存穿透有什么区别?
缓存击穿是指key在数据库中存在而不在缓存中,被一波大流量击垮的场景。
缓存穿透是指key不在缓存和数据库,而被大波流量打击的场景。
主要就是前者是由数据的,只是未来得及加载到缓存,另一个是完全没有。

2、缓存雪崩和缓存击穿有什么区别?
都是由key缓存过期导致的,不同点是缓存击穿是某个热点key过期,就被大波流量访问,雪崩是一群key同时过期,又一起访问并击垮了数据库。

3.缓存一致性

缓存不一致是指在分布式系统中,由于缓存和后端存储的数据之间不同步,导致缓存中的数据和真实数据不一致的问题。主要在缓存的读写过程中,尤其高并发和分布式环境。


要怎么解决缓存不一致呢?以下是大致的方向:


  1. 确认业务对延迟性的要求,如果要求高且数据可能变化,别用缓存,因为用缓存需要接收一定程序的延迟。
  2. 通常,使用过期时间兜底,也是最普遍的方式,如果希望减少缓存不一致的时间,可以增加个删除逻辑,提升一致性。
  3. 订阅binlog来更新,适合场景是不需要过期,直接同步数据。

接下来根据以上的几个方向来谈一谈怎么保存一致性。

方向一

使用Redis的过期时间,MySQL更新时,Redis不做处理,等待缓存过期失效,再从mySQL拉取到缓存。
这种方式的优点就是开发成本低、易于实现、出问题概率小。但是完全依赖于过期时间,如果时间过短,会导致缓存频繁失效,过长,会导致长时间数据不一致。

方向二

不仅仅通过key的过期时间兜底,还在MySQL更新时,同时尝试操作Redis(1.更新Redis,2.删除Redis)。更新Redis容易造成时序性问题,所以更多的是使用删除Redis,等待下次访问再加载回来。
上面所说的删除,也可能会删除失败,那么就忽略它,有过期时间兜底。

方向三

订阅MySQL的binlog日志,解析日志内容,再更新到Redis。(比如阿里巴巴的开源组件canal,https://github.com/alibaba/canal)。也就是说另起一个服务slave,订阅binlog日志,更新任务通过这个服务自动完成。(无时序性问题,和业务完全解耦,但是引入了消息队列这种重量级组件。)

Redis做旁路缓存,mySQL更新了,此时何去何从?

使用过期时间来兜底,并且在更新DB后删除缓存来提升一致性的方式。
(ps:那么什么情况适合使用订阅binlog?)
这种模式更像是同步数据,其实比较适合缓存很长时间过期、或者不过期的场景。

http://www.lryc.cn/news/504150.html

相关文章:

  • 线程与进程基础
  • electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题
  • OpenCV的简单练习
  • JAVA:建造者模式(Builder Pattern)的技术指南
  • 12.11函数 结构体 多文件编译
  • Debezium系列之:使用Debezium采集oceanbase数据库
  • VMware虚拟机 Ubuntu没有共享文件夹的问题
  • spring使用rabbitmq当rabbitmq集群节点挂掉 spring rabbitmq怎么保证高可用
  • 简单vue3前端打包部署到服务器,动态配置http请求头后端ip方法教程
  • C语言关于溢出和不溢出的判断
  • 活动预告 |【Part1】Microsoft Azure 在线技术公开课:使用 Microsoft Fabric 实现数据湖仓
  • Unreal的Audio::IAudioCaptureStream在Android中录制数据异常
  • 6、AI测试辅助-测试报告编写(生成Bug分析柱状图)
  • 【第五节】docker应用系列篇: 使用Docker容器实现ElasticSearch+Kibana部署
  • openwrt 通过DHCP/DNS(Dnsmasq)屏蔽指定域名(hosts)
  • opencv——识别图片颜色并绘制轮廓
  • docker简单私有仓库的创建
  • etcd常见运维事件
  • [代码随想录17]二叉树之最大二叉树、合并二叉树、二搜索树中的搜索、验证二叉搜索树。
  • 前端三大框架 Vue、React 和 Angular 的市场占比分析
  • 12.3【JAVA-EXP4-DEBUGSTUDY】
  • flutter命令行直接指定设备
  • Spring核心--Bean后处理器
  • Windows子系统Ubuntu本地部署xinference以及接入dify详解
  • 如何实现接口继承与实现继承的区别?如何处理多态性与性能的平衡?
  • VR虚拟展厅的实时互动是如何实现的?
  • Java、鸿蒙与嵌入式开发:技术选择与职业发展分析
  • 28. Three.js案例-创建圆角矩形并进行拉伸
  • Shopee算法分析 - x-sap-ri
  • 日志相关的学习记录