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

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

相关文章

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动

Oracle数据库使用 listagg去重删除重复数据的方法汇总

《Oracle数据库使用listagg去重删除重复数据的方法汇总》文章介绍了在Oracle数据库中使用LISTAGG和XMLAGG函数进行字符串聚合并去重的方法,包括去重聚合、使用XML解析和CLO... 目录案例表第一种:使用wm_concat() + distinct去重聚合第二种:使用listagg,

Python实现将实体类列表数据导出到Excel文件

《Python实现将实体类列表数据导出到Excel文件》在数据处理和报告生成中,将实体类的列表数据导出到Excel文件是一项常见任务,Python提供了多种库来实现这一目标,下面就来跟随小编一起学习一... 目录一、环境准备二、定义实体类三、创建实体类列表四、将实体类列表转换为DataFrame五、导出Da

深入理解Redis大key的危害及解决方案

《深入理解Redis大key的危害及解决方案》本文主要介绍了深入理解Redis大key的危害及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、背景二、什么是大key三、大key评价标准四、大key 产生的原因与场景五、大key影响与危

Python实现数据清洗的18种方法

《Python实现数据清洗的18种方法》本文主要介绍了Python实现数据清洗的18种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录1. 去除字符串两边空格2. 转换数据类型3. 大小写转换4. 移除列表中的重复元素5. 快速统

Python数据处理之导入导出Excel数据方式

《Python数据处理之导入导出Excel数据方式》Python是Excel数据处理的绝佳工具,通过Pandas和Openpyxl等库可以实现数据的导入、导出和自动化处理,从基础的数据读取和清洗到复杂... 目录python导入导出Excel数据开启数据之旅:为什么Python是Excel数据处理的最佳拍档

在Pandas中进行数据重命名的方法示例

《在Pandas中进行数据重命名的方法示例》Pandas作为Python中最流行的数据处理库,提供了强大的数据操作功能,其中数据重命名是常见且基础的操作之一,本文将通过简洁明了的讲解和丰富的代码示例,... 目录一、引言二、Pandas rename方法简介三、列名重命名3.1 使用字典进行列名重命名3.编

Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南

《Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南》在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步... 目录一、准备工作二、读取Excel文件三、数据叠加四、处理重复数据(可选)五、保存新DataFram

Xshell远程连接失败以及解决方案

《Xshell远程连接失败以及解决方案》本文介绍了在Windows11家庭版和CentOS系统中解决Xshell无法连接远程服务器问题的步骤,在Windows11家庭版中,需要通过设置添加SSH功能并... 目录一.问题描述二.原因分析及解决办法2.1添加ssh功能2.2 在Windows中开启ssh服务2