mysql和Redis如何保持数据一致性

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: 文档讨论了在系统重建时如何处理数据库和缓存的一致性问题。关键点包括:数据库(如MySQL)和分布式ID生成器可能不宜轻易替换,而代码可以通过兼容性改造来适应新系统。文中以CPU、Memory和Disk的比喻解释了缓存(如Redis)在性能优化中的作用。为确保MySQL和Redis间的一致性,提到了四种策略:Read/Write Through、Write Behind、Cache Aside(先写数据库后更新缓存或先删除缓存后更新数据库)以及先写缓存后写数据库。考虑到读多写少和低频写操作的业务场景,最终选择了先写数据库后更新缓存的策略,并利用canal保证消息顺序性以实现最终一致性。

1.1 还有哪些问题需要考虑?

每个模块的设计目标并不一样,在做这次重建之前,有一个至关重要的前提是,新建系统要兼容旧系统,那就意味着有些组件不能被替换掉,尤其是数据库部分。

哪些组件不能被替换掉呢?

  1. 数据库,目前用的mysql,如果你说我就要替换掉,那也不是不可能,但就是成本比较高,但又有什么理由去做一个费力不讨好的事儿呢?
  2. 数据库主键生成策略目前采用的是分布式id生成器,系统已经运行了好几年了,但我们目前的数据库表的记录不到100w,我真不知道当时为啥选择分布式id生成器,用主键不香吗?一般用分布式ID主要是分库分表,但我们目前的业务增长量好像近期也不需要分库分表啊。而且分布式id生成器需要进行网络通讯,万一网络抖动了导致无法生成主键id,那岂不是很麻烦?凡是依赖于网络的都存在不可靠的因素。

有哪些可以被替换掉的?

代码,代码还是代码,代码做好兼容性就好了,也许会费点时间,那又何妨,换来一个清爽的,简约的结构不爽吗?

2. 技术方案选型

先讲个故事,我有三个朋友,他们是大C,M,和小D。

大C做事情非常麻利从来不拖泥带水,交给他的事情他都能帮你办的妥妥的。

小D慢性子,社恐,但做事情非常仔细,循规蹈矩,不出格,你交给他的事情除了慢一点,没别的毛病。

M呢,和事佬,经常调节大C和小D之间的矛盾,大C总是嫌小D做事情拖拖拉拉,慢慢腾腾的,他们两个一旦有矛盾,M总会出现。

我这三个朋友他们分别是 CPU,Memory,Disk。

我偷偷的告诉你,后来大C觉得总是麻烦M,很不落忍,于是他经常把自己和小D的矛盾积攒在一起,然后一次性交给M来帮忙解决,积攒在一起的这个地方叫 L Cache。

如果要做到高性能,业内通常的做法是加缓存,在快和慢之间

如果要做到高并发,那肯定不能一个人全把活干了,需要多个像CMD这样的组合,这就是横向扩展。

在上边的故事中,我们捋清楚了他们各自的角色,但有一点需要特别注意,小D的工作任务怎么能有条不紊的交给M呢,他们之间是不是得有条航线啊,这条航线叫操作系统。 万一这条航线断掉怎么办呢?

2.1 mysql和Redis如何保持一致性

说了半天,其实我想跟你探讨如果小D是mysql,M是Redis,怎么保证mysql和Redis的数据一致性呢,我调研了业内的一些做法,别嫌麻烦,看一看也许能让你年薪50w,当然也有可能100w,总之祝福你。

经典的缓存方式有三种:

  1. read/write Through : 读/写直接操作缓存,如果缓存未命中,读/写把数据库数据加载到缓存。整个操作有缓存中间件去完成。
  2. write behind :先写缓存,后写数据库,会带来不一致。
  3. cache aside:
    失效:应用程序从缓存中取,如果未命中,则从数据库中取,然后放到缓存。
    命中: 缓存命中,直接取缓存中数据
    更新:先更新数据库,然后让缓存失效。

根据cache aside的几种情况,详细拆解为以下几种情况。

ini

复制代码

策略1:先写数据库,后更新缓存

case1:数据库成功,缓存失败:
数据库值最新的,缓存值是旧的; 这将导致不一致。
解决方法:重试一直到缓存更新成功,在重试之前会存在短暂的不一致,但会最终一致。

case2:并发场景::
线程A更改数据库FieldA=1,线程B更改数据库FeildA=2, 线程B对缓存的更改晚于线程A,
导致缓存结果是FieldA=1而数据库结果是FieldA=2 --不一致。
解决方法:数据按照更新的顺序同步到缓存,在更新到缓存之前会出现短暂的不一致,但最终会一致。

case3:大量更新操作
如果存在大量的更新操作会影响性能;会出现非热点数据长期在缓存中,浪费内存空间的问题。
解决方法:适用于低频的写操作;同时给缓存数据设置过期时间

css

复制代码

策略2:先写数据库,后删缓存

case1:数据库成功,缓存失败:
数据库值是最新的,缓存是旧值:-不一致。
解决方法:重试机制会最终一致,但在重试成功之前会有短暂的不一致。

case2:并发场景:
线程A更改FieldA=1,线程B更改FeildA=2, 线程B对缓存的更改晚于线程A
不会出现不一致场景,此刻是缓存被删除了,最终数据一致

case3:并发场景:
读取FieldA,这个时候缓存恰好失效,线程A需要从数据库中读取数据,同时有个并发的写操作对FieldA进行更改,
数据库更新完成后,使缓存失效,
恰好这个时候读操作把旧值放到缓存,导致数据不一致。
解决方法:这种场景发生需要具备 读的速度要慢于写的速度并且有并发写操作下,
一般这种数据库读速度是远大于写的速度,这种事情发生的概率很小

case4:网络抖动
线程A更改FieldA=1,线程B更改FeildA=2;数据库目前最新值是FeildA=2
由于网络抖动导致缓存未同步,读操作取的还是缓存旧值,等待网络恢复,缓存被删除。- 最终一致

复制代码

策略3:先写缓存,后写数据库	

case1: 缓存成功,数据库失败:此时缓存的数据是脏数据

复制代码

策略4: 先删除缓存,后更新数据库
case1: 缓存成功,数据库失败:丢失新的请求

猜猜按照我们的业务场景,最终选择了哪一种呢?

奖券的修改属于读多写少的场景,同时写操作属于低频操作,并不会存在因大量更新导致的性能低下。

如果采用策略2,如果有大量缓存失效,那将会有大量请求分发到数据库中,导致数据库压力上升,目前在读多写少的场景中,希望更多的命中缓存的方式。

如果采用策略1需要解决的问题是:消息的顺序性;容忍短暂的不一致

通过调研canal在同步binlog的机制中可以按照顺序进行同步 在高并发场景中不会出现错误,所以在业务场景中,我们选择了策略1。


转载来源:https://juejin.cn/post/7360498535076347944

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1天前
|
存储 SQL 关系型数据库
MySQL事务处理:如何确保数据一致性与可靠性
事务(Transaction)是数据库管理系统(DBMS)中的一个核心概念。MySQL 事务是指**一组数据库操作**,作为一个整体进行处理,确保要么全部成功,要么全部失败。
29 15
MySQL事务处理:如何确保数据一致性与可靠性
|
12天前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
73 26
|
1月前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
64 14
|
29天前
|
存储 NoSQL 关系型数据库
MySQL和Redis的区别
**MySQL和Redis的区别** MySQL和Redis都是流行的数据存储解决方案,但它们在设计、用途和特性上有显著区别。理解这些区别有助于选择合适的数据库来满足不同的应用需求。本文将详细介绍MySQL和Redis的区别,包括它们的架构、使用场景、性能和其他关键特性。 ### 一、基本概述 **MySQL**: MySQL是一个关系型数据库管理系统(RDBMS),使用结构化查询语言(SQL)进行数据管理。它支持事务、复杂查询和多种存储引擎,广泛应用于各种Web应用、企业系统和数据分析项目。 **Redis**: Redis是一个基于内存的键值数据库,通常被称为NoSQL数
71 4
|
1月前
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(13)作者——LJS[你个小黑子这都还学不会嘛?你是真爱粉嘛?真是的 ~;以后请别侮辱我家鸽鸽]
MYSQL日志之详解如何配置查看二进制、查询及慢查询日志;备份与恢复等具体详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
2024Mysql And Redis基础与进阶操作系列(13)作者——LJS[你个小黑子这都还学不会嘛?你是真爱粉嘛?真是的 ~;以后请别侮辱我家鸽鸽]
|
1月前
|
存储 SQL NoSQL
2024Mysql And Redis基础与进阶操作系列(10)作者——LJS[你个IKUN还学不会嘛?你是真爱粉嘛?真是的 ~;以后别侮辱我家鸽鸽]
Mysql And Redis基础与进阶操作系列之存储函数和MySQL 触发器等具体举例以及详解步骤;注意点及常见报错问题所对应的解决方法]
|
存储 NoSQL 关系型数据库
MySQL学习笔记04(redis)
MySQL学习笔记04(redis) 一:存储过程 存储过程比普通SQL语句功能更强大,而且能够实现功能性编程,它是SQL语句集,当执行成功后会被存储在数据库服务器中,并允许客户端直接调用,而且存储过程可以提高SQL语句的执行效率,还能保证安全性。
1331 0
|
2天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
111 85
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
78 6
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题

相关产品

  • 云数据库 Tair(兼容 Redis)
  • 云数据库 RDS MySQL 版
  • 推荐镜像

    更多
    下一篇
    DataWorks