千家信息网

MySQL数据库分布式事务XA的实现原理分析

发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,1 原理关于MySQL数据库的分布式事务XA,分布式事务实现的原理,可见[3];关于MySQL XA的说明,可见[1][2]。MySQL XA分为两类,内部XA与外部XA;内部XA用于同一实例下跨多个
千家信息网最后更新 2025年02月04日MySQL数据库分布式事务XA的实现原理分析

  1 原理

  关于MySQL数据库的分布式事务XA,分布式事务实现的原理,可见[3];关于MySQL XA的说明,可见[1][2]。

  MySQL XA分为两类,内部XA与外部XA;内部XA用于同一实例下跨多个引擎的事务,由大家熟悉的Binlog作为协调者;外部XA用于跨多MySQL实例的分布式事务,需要应用层介入作为协调者(崩溃时的悬挂事务,全局提交还是回滚,需要由应用层决定,对应用层的实现要求较高);

  本文,假设读者已经知道MySQL数据库外部分布式事务XA的使用,而将重点放在MySQL数据库,如何处理外部分布式事务XA的crash recover,以及面对不同的crash recover的情形,应用程序如何处理,才能够保证分布式事务的一致性。最后,本文简单分析一下目前MySQL数据库外部XA支持存在的问题,以及可选的解决方案。

  源代码分析基于MySQL 5.1.49,MySQL 5.5.16。

  2 MySQL处理流程

  2.1 MySQL 外部XA - 正常处理流程

  MySQL数据库外部XA的正常处理流程,这里不准备介绍,可以参考[1][2][3]。接下来我重点描述一下MySQL数据库外部分布式事务XA的崩溃恢复流程,毕竟此流程跟应用程序如何正确使用外部XA息息相关。

  2.2 MySQL外部XA - 崩溃恢复流程

  若一个运行外部XA分布式事务的MySQL数据库节点发生崩溃,那么其重启之后的崩溃恢复,涉及到外部XA处理的流程如下:

  Crash recover:

// 1. 读取binlog文件,将文件中的xid存入commit_list hash表
  // 顾名思义,所谓的commit_list,就是说此list中对应prepare状态的xid
  // 在崩溃恢复过程中均可以被提交,而不在commit_list中的xid,均须回滚
  // binlog中的xid,都是属于内部xid,由MySQL产生,用于内部XA
  Log.cc::TC_LOG_BINLOG::recover
  // 2. 遍历底层所有的事务引擎,收集处于XA_PREPARED状态的所有xid
  // 这些xid列表,既包括内部xid,也包括外部xid,存储引擎内部不做区分
  Handler.cc::ha_recover(commit_list)
  // 执行各引擎层面提供的recover方法,收集所有的处于prepared状态的xid
  // 根据xid分类:
  // 3. 若xid属于内部xid,那么在commit_list中查找此xid,
  // 若存在,则提交此xid对应的事务;否则,回滚此事务
  // 4. 若xid属于外部xid,那么则将xid插入xid_cache hash表
  // xid_cache中的所有xid,将会通过xa recover命令返回,等待外部程序决策
  Handler.cc::xarecover_handlerton
  // 5. 收集InnoDB存储引擎中,处于prepare状态的所有xid,并返回
  got = hton->recover (innobase_xa_recover)
  my_xid x = info->list[i].get_my_xid();
  if (!x)
  // 若当前为外部xid,那么将xid插入xid_cache hash表
  xid_cache_insert(&xid_cache, x);
  else
  if (x in commit_list)
  // 若当前为内部xid,同时此xid在binlog中存在,则提交
  hton->commit_by_xid();
  else
  // 若当前为内部xid,同时此xid在binlog中不存在,则回滚
  hton->rollback_by_xid();

  通过以上的分析,可以总结出:

  MySQL数据库内部,会对xid做区分。内部xid有MySQL数据库自己产生(MySQL内部xid格式,将在本文下面给出),用于多引擎间事务的一致性;外部xid由应用程序给出,用于跨多MySQL实例的分布式事务。但是存储引擎层不做区分(区分在MySQL上层)。

  crash recover时,存储引擎负责将引擎内部,处于prepare状态的事务收集,并返回MySQL上层。

  Binlog作为内部XA的协调者[5],在binlog中出现的内部xid,在crash recover时,由binlog负责提交;在binlog中未出现的xid,由binlog负责回滚。(这是因为,binlog不进行prepare,只进行commit,因此在binlog中出现的内部xid,一定能够保证其在底层各存储引擎中已经完成prepare)。

  外部XA事务的xid,在crash recover过程中仅仅是插入xid_cache中,而不做其他处理。等到用户发起xa recover命令时,将xid_cache中处于prepare状态的xid返回。

  xa recover命令的流程处理如下。

  xa recover命令处理流程:

sql_parse.cc::mysql_execute_command
  case SQLCOM_XA_RECOVER:
  mysql_xa_recover();
  // 遍历xid_cache,找出其中的状态处于XA_PREPARED的事务,发送客户端
  while (xs = hash_element(&xid_cache,))
  if (xs->xa_state == XA_PREPARED)
  protocol->write();

  根据xa recover命令收集到的各MySQL数据库实例返回的xid列表,然后再对比应用程序端日志,决定这些xid,哪些全局commit,哪些rollback。

  由于测试中只有一个MySQL数据库实例,因此此时可以直接选择commit处于prepare状态的xid。

  注:

  • MySQL内部xid格式: MYSQL_XID_PREFIX + server_id + my_xid
  • MYSQL_XID_PREFIX: MySQLXid (源码写死) 8 bytes
  • server_id: MySQL实例的id,ulong, 4 bytes
  • my_xid: 内部自增序列,ulonglong, 8 bytes
  • 例如:"MySQLXid 0004"
  • server_id = ' ';my_xid = 4

  因此,使用时应该注意,不要在外部构造这种形式的xid,否则MySQL数据库就会将内部xid与外部xid混淆。

  一般情况下,构造一个内部xid比较困难,由于server_id一般小于4 bytes,不足的部分以ASCI NIL(null)补齐,而应用程序一般都不会构造此类的外部xid。

参考资料

[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#132: Transaction coordinator plugin

该文章出自 http://www.searchdatabase.com.cn/showcontent_58646.htm

事务 数据 数据库 引擎 分布式 流程 状态 应用 处理 实例 程序 命令 应用程序 存储 分析 协调者 应用层 原理 一致 一致性 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 游艇数据库 违反网络安全管理制度的处罚 战术小队怎么查找服务器 北京帅泓网络技术发展有限公司 深圳合创软件开发公司 昆明天度网络技术有限公司 本机向服务器发送文件 服务器至强cpu r什么意思 科瑞恩软件开发工程师面试 服务器的可扩展性有哪些 上海一站式软件开发价格 数据库语言的类型转换 软件开发与应用属于什么专业 吴江区正规软件开发品质保障 北京华信恒网络技术 陌陌老是网络安全验证失败 多个主键的表怎么导入数据库 中宁县软件开发技术案例 数据通信与网络技术的ppt 软件开发管理的必要性是什么 北京帅泓网络技术发展有限公司 合肥服务管理软件开发公司 计算机网络技术基础听后感 蚂蚁下载软件开发 网络安全手抄报宣传口号 sql服务器配置 江西九江电信网络安全工程师工资 网络安全售前工程师笔试 有没有支持服务器cpu的主板 网络安全保卫支队 职责
0