分布式系统:数据一致性解决方案

2024-09-06 20:18

本文主要是介绍分布式系统:数据一致性解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

点击上方蓝色字体,选择“设为星标

回复”资源“获取更多资源

大数据技术与架构

点击右侧关注,大数据开发领域最强公众号!

大数据真好玩

点击右侧关注,大数据真好玩!

在分布式系统中,随着系统架构演进,原来的原子性操作会随着系统拆分而无法保障原子性从而产生一致性问题,但业务实际又需要保障一致性,下面我从学习和实战运用总结一下分布式一致性解决方案。

1. CAP & Base理论



CAP定理指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。这三个要素最多只能同时实现两点,不可能三者兼顾:

  • 一致性:在分布式系统中的所有数据备份,在同一时刻是否同样的值。

  • 分区容错性:可靠性,无论应用程序或系统发生错误,还是用户以意外或错误的方式使用,软件系统都能继续运行。

  • 可用性:在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。





CAP理论3选2是伪命题,实际上必须从A和C选择一个和P组合,更进一步基本上都会选择A,相比一致性,系统一旦不可用或不可靠都可能会造成整个站点崩溃,所以一般都会选择AP。但是不一致的问题也不能忽略,使用最终一致是比较好的办法。



BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。接下来看一下BASE中的三要素:

  • 基本可用(Basically Available):基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。注意,这绝不等价于系统不可用。比如:

    • 响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒

    • 系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。

  • 软状态(Soft State):软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

  • 最终一致(Eventually Consistent):最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。



最终一致的核心做法就是通过记录对应操作并在操作失败时不断进行重试直到成功为止。

2. 重试

在出现一致性问题时如果系统的并发或不一致情况较少,可以先使用重试来解决。



在调用Service B超时或失败时进行重试:

  • 同步调用,捕获异常重新调用Service B。

  • 异步消息,捕获异常发送延迟消息重新调用Service B。

  • 异步线程,捕获异常开启异步线程重新调用Service B。



如果重试还是不能解决问题,那么需要使用分布式事务来解决。

3. 分布式事务

对于分布式一致性问题可以采用分布式事务来解决。

3.1 2PC-XA协议

XA事务由一个或多个资源管理器(Resource Managers)、一个事务管理器(Transaction Manager)以及一个应用程序(Application Program)组成。

  • 资源管理器(RM):参与者。提供访问事务资源的方法。通常一个数据库就是一个资源管理器。

  • 事务管理器(TM):协调者。分配标识符,监视事务的进度,并负责事务完成和故障恢复。

  • 应用程序(AP):发起者。定义事务的边界,制定全局事务中的操作。



整个过程分为2个阶段:准备(prepare)和提交(commit),prepare前需要先执行对应的DML操作。





Mysql XA事务语句:

注:执行前需要先生成全局唯一的xidXA {START|BEGIN} xid [JOIN|RESUME]
DML操作
XA END xid [SUSPEND [FOR MIGRATE]]
XA PREPARE xid //1.准备
XA COMMIT xid [ONE PHASE] //2.提交
XA ROLLBACK xid
XA RECOVER

简单的事例:

//准备前阶段
mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)
//准备
mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)
//提交
mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)

XA看起来很美好,但还是存在一些问题:

  • commit丢失/超时导致数据不一致。A commit成功,B commit时网络超时导致数据库未收到commit请求。

  • 性能低。所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态。

  • 主备数据不一致。

  • 协调者单点故障,在任意阶段协调者发生故障都会导致分布式事务无法进行。



3.2 3PC

3PC通过在参与者加入超时机制解决2PC中的协调者单点带来的事务无法进行的问题,但是性能和一致性仍没有解决。



3.3 TCC



这样看下来强一致是很难做了,还是最终一致把。。。



TCC是通过最终一致来达到分布式事务的效果,即:在短时间内无法保证一致性,但最终会一致。核心分为2个阶段:1.Try  2.Confirm or Cancel。先尝试(Try)操作数据,如果都成功则全部确认(Confirm)该修改,如果有任意一个尝试失败,则全部取消(Cancel)。简单点说就是增加了中间态和可回改能力。





通过重试机制保障Confirm和Cancel一定能成功。TCC解决了性能问题,但是业务系统想要实现对业务代码的侵入性很大,可以学习一下阿里GTS是如何做的。



3.4 事务管理器

在实际运用中事务管理器(TM)一般是由应用程序(AP)兼职实现的,这样对业务代码侵入性大,最好是把TM做成中间层。接下来详细看一下TM的职责:协调者。分配标识符,监视事务的进度,并负责事务完成和故障恢复。TM需要具备持久化能力才能完成监控、故障恢复和协调,整个协调过程可以分为3个阶段:

  • 准备阶段:向TM注册全局事务并获取到全局唯一XID,这一步需要定义好事务的范围。

  • 执行阶段:应用程序AP执行业务功能操作自己的RM,全部执行完毕后向TM commit,如果无失败则整个事务成功。

  • 确认/回滚阶段:如果第2步出现异常会触发该阶段,TM咨询各个AP对应操作是否成功,如果成功则commit,如果失败则调用AP进行rollback。



下面简单介绍几种实现方式。

3.4.1 本地事务管理器

对于简单的业务可能只要保障2个数据库之间的一致,这样在本地实现事务管理器比较快成本也不高。





  1. 1. 在做业务逻辑之前把对应事件添加到本地event表中(记录订正时所需要的关键数据)

  2. 2. 执行业务逻辑

  3. 1.本地业务逻辑,操作表数据等等

  4. 2.RPC调用其他服务

  5. 3.修改event状态为确认

  6. 4. 如果第2步不成功,则event状态还是预提交,通过定时任务捞取再执行订正逻辑

  7. 5. 检查业务逻辑中的操作是否完成,如未完成则执行订正逻辑

  8. 1.本地业务逻辑是否执行成功

  9. 2.RPC调用其他服务是否执行成功

  10. 6.返回订正结果

  11. 1.成功则修改event为确认提交

  12. 2.未成功则不操作,等待轮询订正

3.4.2 外部事务管理器

阿里GTS:https://help.aliyun.com/document_detail/157850.html

3.5 DB和MQ之间的一致性



在实际场景中,业务系统对本地DB数据变更后会广播对应的消息,消费者消费消息做自己的业务逻辑,按正常逻辑消息会在数据库变更后发出,如果消息发送超时且失败那么DB和MQ之间就产生了不一致问题,如何解决呢?使用可靠消息来解决,核心逻辑保证消息从投递到消费的过程中不会丢失:生产者confirm、消费者ack和持久化。理论上只要使用生产者确认机制即可,但是不使用消费者ack则没有意义。消费者需要开启手动ack同时做到幂等消费,MQ需要通过将exchange、queue和message进行持久化来保证消息不丢失,生产者则需要通过确认机制保证消息一定投递到MQ种,接下来重点讲解一下生产者确认机制。



confirm机制是在消息投递到所有匹配的queue之后发送确认消息给生产者,这样生产者就知道消息投递成功,但是由于消息是在DB操作之后发出的,生产者必须增加记录表来记录消息投递状态,如果投递成功就在收到确认消息时把记录标记为投递成功,如果长时间未收到确认消息则大概率是消息丢失了,再定时重新投递,这样就可以保证消息最终一定能投递成功。核心逻辑其实就是通过全局事务ID来标识DB操作和MQ消息是在一个分布式事务中的。



疑点:在学习RabbitMQ confirm机制时发现生产者接收到的确认消息只有消息ID,这个消息ID不能作为全局事务ID,所以无法解决DB和MQ之间的一致性问题,后续再看看其它MQ产品是怎么做的。



上面的方式需要业务系统维护消息状态,这部分可以交给中间件来实现,实现逻辑会变得不一样。





预投递的消息不会分发到queue中,只有在接收到确认投递的请求后才会进行投递,如果确认操作因为网络异常失败了,MQ在过一段时间之后主动询问业务系统该消息是否可投递(失败不断重试),这样就能在异常时做到最终一致,不过依赖MQ产品的能力。

3.6 DB和缓存之间的一致性

DB和缓存之间同样也存在不一致问题,先写DB再写缓存如果缓存写失败就不一致了,同样的需要重试更新缓存来做最终一致。方法可以参考“2.重试”部分,如果一定要保证重试不丢失可以用可靠消息或本地task表来记录重试操作,有条件的可以使用DB DRC消息对业务的侵入会小一些。需要注意的是同步更新和异步更新同时使用时可能会产生更新覆盖的问题,加上毫秒级的时间戳或版本号来丢弃旧的更新。

4. 兜底核对

虽然有了分布式事务,但是在实际场景中可能会因为bug导致数据不一致,这时需要兜底来做最后一道防线,通过定时核对数据是否一致,如不一致手动/自动进行订正。

4.1 系统自核对

如果系统数量和数据量不多的情况下可以由业务系统自行核对,通过发送延迟消息自消费或监听其他系统消息做相关数据核对并进行订正。



4.2 搭建核对系统

在核对工作繁多的情况下,由业务系统自己核对会存在很多耦合,这时可以选择搭建独立的核对系统进行核对和订正。



1.监听drc消息





2.监听业务消息



参考:

  • 阿里GTS:https://help.aliyun.com/document_detail/157850.html?spm=a2c4g.11186623.6.554.47ae4df4Zy6hBI

  • 饿了么DRC:https://zhuanlan.zhihu.com/p/34958596

  • Mysql XA:https://dev.mysql.com/doc/refman/8.0/en/xa-statements.html

版权声明:

本文为大数据技术与架构整理,原作者独家授权。未经原作者允许转载追究侵权责任。

编辑|冷眼丶

微信公众号|import_bigdata

欢迎点赞+收藏+转发朋友圈素质三连

文章不错?点个【在看】吧! ????

这篇关于分布式系统:数据一致性解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1143019

相关文章

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S

Python实现将MySQL中所有表的数据都导出为CSV文件并压缩

《Python实现将MySQL中所有表的数据都导出为CSV文件并压缩》这篇文章主要为大家详细介绍了如何使用Python将MySQL数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到... python将mysql数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到另一个