17 mysql XA事务

一、mysql XA事务

XA就是X/Open DTP(分布式事务处理模型)定义的事务管理器TM(交易中间件)与资源管理器RM(数据库)之间的接口规范。XA规范的基础是二阶段提交协议。

注意:对于分布式事务,必须使用SERIALIZABLE隔离级别。

mysql XA事务分为外部XA和内部XA。Mysql外部XA由外部应用程序充当事务管理器,可以用在分布式数据库代理层,如开源工具ameba,网易的DDB,淘宝的TDDL,B2B的cobar等。Mysql内部XA是多个存储引擎之前的,自身即为事务管理器。

为了保证底层引擎commit顺序和Binlog顺序一致(我的推测是,在recover时需要根据binlog判断处于prepare状态的XA事务的处理情况,如果不一致,实际上可能已经完全提交了的事务却没有记录在binlog中;实际上,如果Binlog顺序不一致,那么备库就无法确保和主库有一致的数据。),mysql+InnoDB不支持Group commit(新版的Precona,MariaDB及InnoDB Plugin 1.04支持),同一时间只有一个事务可以提交。

http://hatemysql.com/tag/sync_binlog/ 介绍了innodb_flush_log_at_trx_commit/sync_binlog/ innodb_support_xa这三个参数的作用。

http://hedengcheng.com/?p=136 分析了mysql外部XA的崩溃恢复流程。

http://databaseblog.myname.nl/2012/06/xa-transactions-between-tokudb-and.html 介绍了XA START、 XA END、XA PREPARE、XA COMMIT的使用,在XA PREPARE后使用XA RECOVER可以返回所有处于PREPARE状态的XA事务。

http://www.gpfeng.com/?p=298 详细讲解了mysql 内部XA流程和外部XA中出现的问题(binlog丢失),以及断开连接情况下(非crash)针对xa_prepared事务会发生回滚这一问题的fix。内部XA流程如下图:


对于内部XA,binlog本身也会prepare/commit,但是binlog的prepare阶段不做任何事情(意味着不可能失败),代码中可以看见binlog_prepare函数是空的,写入binlog的过程是在commit阶段做的(在其他事务存储引擎commit之前),binlog具有“原子”性:每个事务产生的binlog是连续、完整的写入到binlog文件中,事务之间不会交叉写(与InnoDB的redo log不同),因此在crash recovery阶段,如果redo log中未提交的事务能够在binlog中发现,说明其已经prepare成功,可以直接提交,而如果redo中未提交事务不在binlog中,直接回滚事务,这样能够保证binlog和存储引擎数据的一致

实际上,内部XA的流程大致是这样的(可以看到有3次fsync()进行持久化):

事务开始---->事务的运行(不断有redo产生)---->事务开始提交(以下函数全部由ha_commit_trans调用)

binlog_prepare(该函数为空);

innobase_xa_prepare(加prepare_commit_mutex锁,同时调用trx_prepare_off_kernel()持久化redo)。

binlog的write(ha_commit_trans()调用tc_log->log_xid()写整个事务的binlog)。

binlog_commit(binlog的持久化);

innobase_commit(释放prepare_commit_mutex锁,将commit标志持久化至redo)。


外部XA:http://dev.mysql.com/doc/refman/5.1/en/xa.html

外部XA缺陷原因摘录如下:

server crash后重启,XA RECOVER可以恢复出未提交的XA PREPARED事务(应该是根据redo log恢复,外部程序可能会决定提交该prepared事务),但是此时提交时无法记录binlog(crash时binlog cache丢失),这就使得binlog和存储引擎数据不一致,会引起复制中断


二、Group Commit

http://www.orczhou.com/index.php/2010/08/time-to-group-commit-1/ 介绍了mysql为何不支持Group commit,并给出了Facebook的解决方案(MariaDB)。

一种思路如下:

前提:不使用prepare_commit_mutex锁;写binlog仍然是原子性的,即同一时刻只有一个事务在写binlog。

操作:一个事务过程中,进行binlog的写入,它之前的redo之后的commit标志仍由事务本身保管,但是需要在写binlog时(写binlog需要获得锁,以达到原子性)给这个事务一个编号(或加入队列)以表示事务写binlog的先后顺序(这也是应当提交的先后顺序)。这样binlog可以group commit。而事务redo本身,只要按照编号先后顺序写入内存(需要保证对应的binlog已经持久化,这也是为了保证不会丢失binlog)并进行持久化即可(可以一次持久化多个事务的redo,这也是group commit)。

优化操作:在所有存储引擎prepare之后(各存储引擎可以进行提交,与之前不同的是,不进行redo的持久化,还没有开始写),进行以下操作。实现两个队列,一个队列中进行持久化/提交操作时;另一个队列在等待,并不断有新的trx链入(prepare_ordered功能)。在获取一个队列后,在(group commit)持久化binlog后,释放对应的LOCK_log锁之前,获得另一个锁LOCK_commit_ordered mutex(保证另一个队列在commit_ordered开始时,该队列已经完成commit_ordered)去依次执行commit_ordered()去写redo log(包括commit标志);redo的持久化交给innobase_commit()(这也是group commit)。

recovery:根据binlog将未持久化的已提交的事务re-play。

http://hedengcheng.com/?p=112给出了Percona的具体实现。

Fixing MySQL group commit (part 3)系列文章给出了实现原理。


三、JDBC

JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

JDBC API 既支持数据库访问的两层模型(C/S),同时也支持三层模型(B/S)。在两层模型中,Java applet或应用程序将直接与数据库进行对话。这将需要一个JDBC驱动程序来与所访问的特定数据库管理系统进行 通讯。用户的SQL语句被送往数据库中,而其结果将被送回给用户。数据库可以位于另一台计算机上,用户通过网络连接到上面。这就叫做客户机/服务器配置,其中用户的计算机为客户机,提供数据库的计算机为服务器。网络可以是 Intranet(它可将公司职员连接起来),也可以是 Internet。

在三层模型中,命令先是被发送到服务的"中间层",然后由它将SQL 语句发送给数据库。数据库对 SQL 语句进行处理并将结果送回到中间层,中间层再将结果送回给用户。MIS 主管们都发现三层模型很吸引人,因为可用中间层来控制对公司数据的访问和可作的的更新的种类。中间层的另一个好处是,用户可以利用易于使用的高级API,而中间层将把它转换为相应的低级调用。最后,许多情况下三层结构可提供一些性能上的好处。

到目前为止,中间层通常都用 C 或 C++ 这类语言来编写,这些语言执行速度较快。然而,随着最优化编译器(它把 Java 字节代码转换为高效的特定于机器的代码)的引入,用 Java 来实现中间层将变得越来越实际。这将是一个很大的进步,它使人们可以充分利用 Java 的诸多优点(如坚固、多线程和安全等特征)。JDBC 对于从Java的中间层来访问数据库非常重要。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值