Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案

简介: 根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案

导航:

【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析

目录

一、四种基础同步策略

1.1 同步策略

1.2 更新缓存还是删除缓存?

1.2.1 更新缓存的优缺点

1.2.2 删除缓存的优缺点(推荐)

1.3 先操作数据库还是先删除缓存?

1.3.1 先删除缓存再操作数据库的优缺点

1.3.2 先操作数据库再删除缓存的优缺点(推荐)

1.4 最优同步策略:先更新数据库、再删除缓存

二、同步删除+可靠消息方案

三、延时双删:更高一致性方案

四、异步监听+可靠消息删除方案

五、多重保障:最终强一致方案


一、四种基础同步策略

1.1 同步策略

保证缓存和数据库的双写一致性,共有四种同步策略,即先更新缓存再更新数据库、先更新数据库再更新缓存、先删除缓存再更新数据库、先更新数据库再删除缓存。

  • 先更新缓存再更新数据库:第二步失败缓存库是脏数据
  • 先更新数据库再更新缓存:第二步失败缓存库是旧数据
  • 先删除缓存再更新数据库:第二步失败缓存库是空数据
  • 先更新数据库、再删除缓存(推荐):第二步失败缓存库是旧数据

1.2 更新缓存还是删除缓存?

1.2.1 更新缓存的优缺点

更新缓存的优点是每次数据变化时都能及时地更新缓存,这样不容易出现查询未命中的情况,但这种操作的消耗很大,如果数据需要经过复杂的计算再写入缓存的话,频繁的更新缓存会影响到服务器的性能。如果是写入数据比较频繁的场景,可能会导致频繁的更新缓存却没有业务来读取该数据。

1.2.2 删除缓存的优缺点(推荐)

删除缓存的优点是操作简单,无论更新的操作复杂与否,都是直接删除缓存中的数据。这种做法的缺点则是,当删除了缓存之后,下一次容易出现未命中的情况,那么这时就需要再次读取数据库。

那么对比而言,删除缓存无疑是更好的选择

1.3 先操作数据库还是先删除缓存?

1.3.1 先删除缓存再操作数据库的优缺点

情况1:数据库和缓存内容不一致

线程1删除缓存后还没有来得及更新数据库时,线程2读缓存,由于缓存中的数据已经被线程1清空了所以线程2需要去数据库读数据,然后把读到的结果保存到缓存中。此时线程1更新更新数据库成功。就会出现数据库和缓存内容不一致。

情况2:缓存击穿,数据库卡死

线程1删除缓存后还没有来得及更新数据库时,来了大量的读请求,由于缓存中没有数据,导致缓存击穿直接将大量请求访问到数据库,导致数据库崩溃。

1.3.2 先操作数据库再删除缓存的优缺点(推荐)

脏数据问题:先操作数据库但删除缓存失败的话,导致缓存库里一直存留着旧数据,而我们数据库里存的是新数据。

解决办法:异步重试机制

出现上述问题的时候,我们一般采用重试机制解决,而为了避免重试机制影响主要业务的执行,一般建议重试机制采用异步的方式执行。当我们采用重试机制之后由于存在并发,先删除缓存依然可能存在缓存中存储了旧的数据,而数据库中存储了新的数据,二者数据不一致的情况。

1.4 最优同步策略:先更新数据库、再删除缓存

所以我们得到结论:先更新数据库、再删除缓存是影响更小的方案。如果第二步出现失败的情况,则可以采用重试机制解决问题。

同步删除方案: 先更新数据库、再删除缓存。适用于不强制要求数据一致性的情景

流程:先更新数据库、再删除缓存。

问题:

  • 并发时脏数据:在查询数据库到写缓存期间其他线程执行了一次更新删除,导致缓存的数据是旧数据
  • 缓存删除失败:删除失败导致缓存库还是旧数据

二、同步删除+可靠消息方案

同步删除+可靠消息删除: 适用于不强制要求数据一致性的情景

流程:先更新数据库、再删除缓存,如果删除失败就发可靠MQ不断重试删除缓存,直到删除成功或重试5次。

问题:MQ多次重试失败,导致长期脏数据。

三、延时双删:更高一致性方案

延时双删方案:比同步删除策略一致性更高的方案。

流程:先删除缓存再更新数据库,大约在数据库从库更新后再删一次。

问题:时间无法控制,不能保证在数据库从库更新后删除缓存。如果在从库更新前删除,用户再在更新前查从库又把脏数据写在缓存里了。

四、异步监听+可靠消息删除方案

异步监听+可靠消息删除:很多大厂正在使用的方案。

流程:

  1. 更新数据库后不做操作;
  2. Canal等组件监听binlog发现有更新时就发可靠MQ删除缓存;
  3. 如果删除缓存失败,就基于手动ack、retry等机制,让消息在有限次数之内不断重试。

image.gif

优点:

  • 异步删除,性能更高;
  • 可靠消息重试机制,多次删除保证删除成功。

问题:要求canal等binlog抓取组件高可用,如果canal故障,会导致长期脏数据。

五、多重保障:最终强一致方案

多重保障方案:同步删除+ 异步监听+可靠消息删除,缓存时设置过期时间,查询时强制主库查;适合于强制要求数据一致性的情况

  1. 同步删除:先更新数据库、再删除缓存;之后本链路禁止再查该数据,防止没来得及删缓存就又查到旧缓存数据。
  2. Canal监听:Canal等组件监听binlog发现有更新时就发可靠MQ删除缓存;第二重保证删缓存成功;
  3. 延迟消息校验一致性:Canal等组件监听binlog,发延迟MQ,N秒后校验缓存一致性;
  4. 缓存过期时间:每次缓存时设置过期时间;第三重保证删缓存成功;
  5. 强制Redis主库查:以后查缓存时强制从缓存主库查;因为主从同步有延迟,同时不用担心主库压力大,因为分片集群机制。
相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
20天前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
42 0
|
4天前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
5天前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
15天前
|
缓存 NoSQL 关系型数据库
MySQL与Redis缓存一致性的实现与挑战
在现代软件开发中,MySQL作为关系型数据库管理系统,广泛应用于数据存储;而Redis则以其高性能的内存数据结构存储特性,常被用作缓存层来提升数据访问速度。然而,当MySQL与Redis结合使用时,确保两者之间的数据一致性成为了一个重要且复杂的挑战。本文将从技术角度分享MySQL与Redis缓存一致性的实现方法及其面临的挑战。
38 2
|
17天前
|
Java UED Maven
紧跟技术潮流:手把手教你构建响应式Vaadin应用,让用户体验无缝接轨!
【8月更文挑战第31天】本文从零开始,详细介绍如何使用强大的Java框架Vaadin构建流畅且响应式的Web应用程序。首先,确保安装JDK 1.8+、Maven 3.3.9+及IDE。接着,创建Maven项目并添加Vaadin依赖。然后,通过继承`UI`类创建主界面,并定义自定义主题与样式。利用Vaadin的响应式布局组件,如`HorizontalLayout`和`VerticalLayout`,实现多设备兼容性。
26 0
|
17天前
|
缓存 NoSQL Redis
Entity Framework Core 与 Redis 强强联手!实现高速缓存,提升应用性能超厉害
【8月更文挑战第31天】在现代应用开发中,结合 Entity Framework Core 与 Redis 可显著提升数据访问速度。Entity Framework Core 是一个强大的 ORM 框架,但处理频繁访问的数据时可能遇到性能瓶颈。Redis 作为高性能内存数据库,具备快速读写能力。两者结合利用 Redis 高速缓存,减少直接数据库访问,提高应用响应速度及性能。
25 0
|
18天前
|
SQL 存储 NoSQL
从SQL到NoSQL:理解不同数据库类型的选择与应用——深入比较数据模型、扩展性、查询语言、一致性和适用场景,为数据存储提供全面决策指南
【8月更文挑战第31天】在信息技术飞速发展的今天,数据库的选择至关重要。传统的SQL数据库因其稳定的事务性和强大的查询能力被广泛应用,而NoSQL数据库则凭借其灵活性和水平扩展性受到关注。本文对比了两种数据库类型的特点,帮助开发者根据应用场景做出合理选择。SQL数据库遵循关系模型,适合处理结构化数据和复杂查询;NoSQL数据库支持多种数据模型,适用于非结构化或半结构化数据。SQL数据库在一致性方面表现优异,但扩展性较差;NoSQL数据库则设计之初便考虑了水平扩展性。SQL使用成熟的SQL语言,NoSQL的查询语言更为灵活。
27 0
|
20天前
|
缓存 NoSQL Java
惊!Spring Boot遇上Redis,竟开启了一场缓存实战的革命!
【8月更文挑战第29天】在互联网时代,数据的高速读写至关重要。Spring Boot凭借简洁高效的特点广受开发者喜爱,而Redis作为高性能内存数据库,在缓存和消息队列领域表现出色。本文通过电商平台商品推荐系统的实战案例,详细介绍如何在Spring Boot项目中整合Redis,提升系统响应速度和用户体验。
43 0
|
24天前
|
缓存 NoSQL 网络安全
【Azure Redis 缓存】Azure Redis服务开启了SSL(6380端口), PHP如何访问缓存呢?
【Azure Redis 缓存】Azure Redis服务开启了SSL(6380端口), PHP如何访问缓存呢?
|
24天前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Redission客户端连接Azure:客户端出现 Unable to send PING command over channel
【Azure Redis 缓存】Redission客户端连接Azure:客户端出现 Unable to send PING command over channel