【问题】分布式事务的场景下如何保证读写分离的数据一致性

我的理解这个题目可以获得以下关键字:分布式处理、读写分离、数据一致性

那么就从”读写分离“做切入口吧,按我的理解其实就是在保证数据一致性的前提下两个(或以上)的数据库分别肩负不同的数据处理任务。太过久远的就不说了,最近几年其实都用的 MySQL 比较多。那么就基于 MySQL 我用到过的读写分离技术主要有:

  1. MySQL 主从热备机制
  2. Alibaba Canal 组件
  3. Apache Shardingsphere 中间件

总体来说应该可以归纳为一下这些优缺点(纯粹个人感受):

技术 机制 总结
MySQL 利用MySQL自身的日志复制机制,通过Binlog日志将主库的写操作同步到从库,实现数据备份和读写分离 优点:
1. 简单易用,不需要额外的中间件和组件;
2. 原生技术成熟;
3. 与业务代码解耦;
缺点:
1. 数据同步是异步的,只能保证最终一致性不能达到强一致性,这将导致高并发下数据不能保证读写一致;
2. 数据同步依赖网络和磁盘稳定性,会有数据不完整或丢失的风险(大大的教训有机会给各位分享);
3. 跨平台会存在兼容性问题;
Alibaba Canal 基于MySQL Binlog的增量订阅和消费组件,可以实时捕获MySQL的增量日志并消费。 优点:
1. 可实现数据库对应多产品的数据同步(如 kafka、redis、elasticsearch 等等);
缺点:
1. 额外的 Canal 服务同时需要增加维护和监控功能;
2. 高并发下存在性能问题;
3. 采用与 MySQL 相同的 binlog 复制机制只能保证最终一致性;
Apache Shardingsphere 开源的分布式数据库中间件解决方案,支持读写分离、分库分表等功能 优点:
1. 可直接在应用中通过配置路由实现
2. 多种协议数据同步模式,适合复杂的分布式场景,如:
- XA 协议:基于两阶段提交和三阶段提交协议实现分布式事务管理。
- BASE 协议:基于最终一致性理念实现分布式事务管理。
- TCC 协议:基于补偿型事务理念实现分布式事务管理。
- Saga 协议:基于长事务理念实现分布式事务管理。
缺点:
1. 配置较为复杂会增加学习成本;

其实之前还有用过 MyCAT 并且也有调研过 Google 的 Vitess。

MyCAT不是说它不好,只能说谁用谁知道。虽然接入成本低且性能上还可以,但功能相对单一且对分布式事务的支持也不是太好。

而 Vitess 又太过于庞大,若你有超大型的 MySQL 集群 Vitess 是一个不错的选择,但对于中小型企业来说选择较为灵活且通用的 Shardingsphere 无疑是更好的选择。

回到问题中,经上表比较,如果不需要强一致性且项目较小的情况下使用 MySQL 的主从热备保证最终一致性就可以了。但也有例外的情况,譬如我曾经有遇到过一个项目它的部分业务场景需要用到 Federated 引擎做跨服务数据映射,这种情况下就会影响到原来的主从热备,具体表现为从库同步会时不时停掉(这个说起来可以另起一篇文章有机会再给各位分享吧)。这种方式看情况使用吧,一般来说没用到哪些”古灵精怪“的数据库引擎的情况下是个不错的低成本解决方案。

至于 Alibaba Canal 已经是业界比较成熟的数据同步解决方案了,用它来将 MySQL 数据同步到 Redis 或者 MQ 就用过,但从 MySQL 同步到另一个 MySQL 就没有尝试过。众所周知 Alibaba Canal 也是通过 binlog 进行数据复写从而实现数据同步,那么如果要 MySQL 同步 MySQL,那么直接原生主从热备就可以了,还有你 Alibaba Canal 什么事儿吗?所以跨产品吧 Alibaba Canal是个不错的选择,但数据同步嘛,不至于,不至于…

所以,到目前为止我这边最终是选择使用 Apache Shardingsphere (以下简称”A-SS“)做分布式事务读写分离的这个事儿。

A-SS 已经被我加入到公司开发框架里面,考虑到公司项目一般都是”读多写少“的情况,A-SS 主要用在读写分离里的”写“操作,而”读“操作将直接使用 HikariCP 数据库连接池进行读取。

因为 A-SS 本来就支持多种分布式事务场景,所以只要你读懂了 A-SS 的配置文档,基本上就能够解决大部分的分布式事务事情了,剩下的可以完全托管给 A-SS 就可以了… 但话虽如此一些基本的概念还是要搞清楚的,由于我用的就是 XA 协议的二阶段提交,这里就以 XA 协议作为例子进行解释吧。

扫描二维码关注公众号,回复: 16375013 查看本文章

首先,A-SS 的 XA 协议二阶段提交是一种基于 X/Open 分布式事务处理(DTP)模型实现的数据同步技术,它可以保证跨多个数据库实例或服务的事务的强一致性。原理简单点理解就是:

  1. 当一个分布式事务需要提交时,A-SS 的事务管理器会先向所有参与该事务的数据库实例发送准备提交的命令;
  2. 每个数据库实例如果成功执行了事务中的SQL,则会响应准备提交成功的消息,表示该实例可以执行提交操作。如果任一实例失败,则响应 abort 消息;
  3. A-SS 收到所有数据库实例的准备提交成功响应后,会向所有实例发送正式提交事务的命令;
  4. 每个实例收到提交命令后,会正式提交事务,并响应提交成功至此事务完成;
  5. 如果在准备提交阶段任意一个实例失败,事务管理器会向所有实例发送回滚事务的命令然后整个事务回滚;

通过这样的两阶段提交过程,可以保证分布式事务要么全部分库都成功提交,要么全部分库都失败回滚。这样就能保证跨多个数据库实例的分布式事务的强一致性。

当然了,A-SS 也不是万能的它会存在很多使用限制(具体可以查看官方文档),在使用的时候也要多加小心。但就目前来看除了压测时的写入性能有点低之外(也有可能是压测的脚本有问题),暂时还没有发现什么太大的问题。

猜你喜欢

转载自blog.csdn.net/kida_yuan/article/details/132351858