MySQL数据库分布式事务XA优缺点与改进方案

2024-01-12 12:48

本文主要是介绍MySQL数据库分布式事务XA优缺点与改进方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 MySQL 外部XA分析

1.1 作用分析

  MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:ameoba[4],网易的DDB,淘宝的TDDL,B2B的Cobar等等。

  通过MySQL数据库外部XA,这些工具可以提供跨库的分布式事务。当然,这些工具也就成了外部XA事务的协调者角色。在crash recover时控制悬挂事务是全局commit,或者rollback。

  在crash recover之后,外部应用程序可能会遇到以下几种情况:

  • 情况一:分布式事务对应的MySQL数据库实例,部分完成prepare,部分未完成prepare。此时直接回滚完成prepare的实例即可。n_prepared < Total Nodes (处于prepare状态的节点数量要小于参与分布式事务的所有节点总数)。
  • 情况二:分布式事务对应的MySQL实例,全部完成prepare,未开始进行commit。此时即可提交此事务,也可回滚此事务(根据分布式事务原理,所有节点都完成prepare,应该提交)。n_prepared = Total Nodes。
  • 情况三:分布式事务对应的MySQL实例,全部完成prepare,并且部分节点已经完成commit。此时应该提交该事务处于prepare状态的节点。n_prepared < Total Nodes。对比情况三与情况一,仅仅通过prepare节点的数量无法区分,因此应用程序需要在prepare完成之后记录日志(此时,应用程序起着事务协调者(Transcaction Coordinator)的角色,而根据MariaDB WorkLog#132[5]的说法,TC角色是可以进行”middle engine”优化的,不需要prepare过程,所有MySQL节点xa prepare返回之后,应用程序直接写commit标识即可,然后再对每个MySQL节点进行xa commit操作。),从而用于区分情况一与情况三。
  • 情况四:分布式事务对应的MySQL实例,全部完成commit。此时事务已经提交成功,xid不会出现在执行xa recover的任一个节点。不需要特殊处理。
  • 情况五:未记录任何prepare日志。那么所有的事务,在各个存储引擎的crash recover时,都会被回滚,不需要外部特殊处理。

1.2 MySQL外部XA不足

  通过前面的分析,可知应用程序配合MySQL的XA事务功能,能够较好的支持分布式环境下的事务。但是,这个支持并不完美,根据我的分析,有可能会出现以下几个问题:

  l 问题一:主备数据库的数据不一致。

  MySQL数据库的主备数据库的同步,通过Binlog的复制完成。而Binlog是MySQL数据库内部XA事务的协调者,并且MySQL数据库为binlog做了优化——binlog不写prepare日志,只写commit日志。

  考虑前面提到的情况二,所有的参与节点prepare完成,在进行xa commit前crash。crash recover如果选择commit此事务。由于binlog在prepare阶段未写,因此主库中看来,此分布式事务最终提交了,但是此事务的操作并未写到binlog中,因此也就未能成功复制到备库,从而导致主备库数据不一致的情况出现。

  在MySQL 5.5.16版本中做过测试,这个问题实际存在。crash recover之后,对xa recover返回的事务运行xa commit,对应事务提交,但是操作并未写入binlog,因此无法复制到备库。

  那么是否回滚所有prepare的事务,就可以避免此问题呢?结论是仍旧不行,不仅不能解决问题一,甚至可能引起问题二。

  l 问题二:同一事务,在各参与节点,最终状态不一致(部分提交,部分回滚)。

  若回滚所有prepare状态的分布式事务,会产生问题二。考虑情况三(所有节点完成prepare,部分节点完成commit),该分布式事务对应的节点,部分已经提交,无法回滚,而部分节点回滚。最终导致同一分布式事务,在各参与节点,最终状态不一致。

  l 问题三:源码级别问题。MySQL 5.1.49源码对于外部XA事务处理存在bug,在MySQL 5.5.16版本中,此bug已经被fix。经过验证发现,在我已下载的MySQL 5.1.61与之后的所有版本,此bug均已经被fix。

  在MySQL 5.1.49中,所有xa recover返回的外部xid,都不能被提交。原因如下:

  当运行xa commit ‘xid_name’命令时,MySQL会判断当前xid_name的错误信息,若存在错误信息,那么就在内部将xa commit命令强制转换为xa rollback。xid_name的状态存于xid_cache中,在crash recover阶段,由函数Handler.cc::xarecover_handlerton调用xid_cache_insert(&xid_cache, x)函数完成插入。MySQL 5.1.49在实现xid_cache_insert函数有bug。

  …

  xs->xa_state=xa_state;

  xs->xid.set(xid);

  xs->in_thd=0;

  xs->rm_error=0;

  res=my_hash_insert(&xid_cache, (uchar*)xs);

  …

  MySQL 5.1.49中,缺少了xs->rm_error =0这一行,未初始化rm_error,导致xa commit时判断出错,无法commit。MySQL 5.5.16已经fix此bug,加上了黑色这一行的初始化,应用程序可以xa commit。

1.3 不足的解决方案

  从MySQL数据库外部分布式事务XA不足的分析可以看出,除了实现bug之外,产生其余两个问题的最大原因,还是在于MySQL针对binlog做的 ”middle engine” 优化,binlog的prepare不写日志。在MySQL内部XA事务中,这个优化是可行的,因为Binlog本身的角色就是事务协调者(Transaction Coordinator),事务协调者可以不进行prepare [5]。

  但是对于MySQL外部XA事务,Binlog已经不是事务协调者的角色,其也是一个参与者,或者说是Resource Manager。因此Binlog的prepare日志是不可省略的。

  为了解决MySQL数据库外部XA分布式事务crash recover过程中出现的问题,我觉得只能修改binlog模块。使binlog模块在正常运行过程中也区分内部XA事务与外部XA事务。内部XA事务可以仍旧沿用现在的方案;而外部XA分布式事务,需要增加写prepare日志的功能,已经crash recover时处理prepare日志的功能。

2 参考资料

  [1] Sergei Golubchik. Distributed Transaction Processing with MySQL XA

  [2] http://dev.mysql.com/doc/refman/5.1/en/xa.html

  [3] X/Open. Distributed TP: The XA Specification

  [4] 陈思儒. Amoeba

  [5] MariaDB WorkLog: Transaction coordinator plugin

该文章出自http://jishu.zol.com.cn/4306.html

这篇关于MySQL数据库分布式事务XA优缺点与改进方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

MySQL中删除重复数据SQL的三种写法

《MySQL中删除重复数据SQL的三种写法》:本文主要介绍MySQL中删除重复数据SQL的三种写法,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下... 目录方法一:使用 left join + 子查询删除重复数据(推荐)方法二:创建临时表(需分多步执行,逻辑清晰,但会

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

oracle数据库索引失效的问题及解决

《oracle数据库索引失效的问题及解决》本文总结了在Oracle数据库中索引失效的一些常见场景,包括使用isnull、isnotnull、!=、、、函数处理、like前置%查询以及范围索引和等值索引... 目录oracle数据库索引失效问题场景环境索引失效情况及验证结论一结论二结论三结论四结论五总结ora

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Redis分布式锁使用及说明

《Redis分布式锁使用及说明》本文总结了Redis和Zookeeper在高可用性和高一致性场景下的应用,并详细介绍了Redis的分布式锁实现方式,包括使用Lua脚本和续期机制,最后,提到了RedLo... 目录Redis分布式锁加锁方式怎么会解错锁?举个小案例吧解锁方式续期总结Redis分布式锁如果追求

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO