MYSQL--架构--MGR--理论--08--如何执行事务

MYSQL–架构–MGR–理论–08–如何执行事务


1、架构图

在这里插入图片描述

2、如何执行单个事务

2.1、场景

  1. MGR组中有5个节点(s1、s2、s3、s4、s5)了,这些节点目前全都是ONLINE状态,这个状态表示能正确向外提供服务、能正确进行组内通信、能正确投票。

  2. s1是单主模型的主节点。

  3. 当在节点s1上执行了以下事务A1

    # 开启事务
    start transaction;
    # 插入数据
    insert into t values(3);
    # 事务提交
    commit;
    

2.2、说明

  1. s1称为事务的发起节点。
  2. s1首先会执行这个事务到commit,在真正commit之前有一个before_commit的过程

2.3、before_commit过程

  1. s1节点将binlog传播给组内其它节点。
  2. 当组内其它节点的receiver线程(其实就是io_thread)收到binlog后,将对这个A1事务进行决策

2.3.1、组内其它节点对A1事务决策

  1. 如果组内大多数节点(因为组内有5个节点,所以至少3个节点才满足大多数的要求)对这个事务达成一致,则这个事务A1会真正提交
    1. 决定后、提交前会先将buffer binlog写到disk binlog
    2. s2-s5会将收到的binlog也写入到自己的disk binlog中,并通过applier线程(sql_thread)对这个事务进行应用。
  2. 如果大多数节点未达成一致,则这个事务会回滚,日志不会写入到日志中。

2.3.2、注意

决策通过后,事务发起节点的commit操作和其它节点对binlog的应用没有强烈的先后关系,各节点收到"决策通过"的消息后,是独立完成事务的。所以,有些节点可能会有延迟。

当延迟在允许的范围内,不会有什么问题,但如果某个节点严重落后于其他节点(拖后腿),组复制会放慢整个组的处理速度,也可能会做一些限流,关于这个问题的处理,叫做flow control。

2.4、binlog日志内容

以下为binlog中两个事务的对应的日志内容,每个事务的binlog是在成功决定提交之后才写入的:

+------------+------------------------------------------------------------------------+
| Gtid       | SET @@SESSION.GTID_NEXT= 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:4000007'|
| Query      | BEGIN                                                                  |
| Table_map  | table_id: 111 (mut_gr.t1)                                              |
| Write_rows | table_id: 111 flags: STMT_END_F                                        |
| Xid        | COMMIT /* xid=152 */                                                   |
| Gtid       | SET @@SESSION.GTID_NEXT= 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:3000010'|
| Query      | BEGIN                                                                  |
| Table_map  | table_id: 111 (mut_gr.t1)                                              |
| Write_rows | table_id: 111 flags: STMT_END_F                                        |
| Xid        | COMMIT /* xid=153 */                                                   |
+------------+------------------------------------------------------------------------+



2.5、组内所有节点数据和状态都是同步的,为什么还要对事务进行决策?在主节点上判断事务能否执行、能否提交不就可以了吗?

对于单主模型下执行正常的事务来说确实如此。但是多主模型下多个节点可执行并发事务,而且组复制内部也有些特殊的事件(例如成员加组、离组),这些都需要得到大多数节点的同意才能通过,所以必须先进行决策。

3、如何执行并发事务:冲突检测

3.1、场景

  1. MGR组中有5个节点(s1、s2、s3、s4、s5)了,这些节点目前全都是ONLINE状态,这个状态表示能正确向外提供服务、能正确进行组内通信、能正确投票。

  2. s1、s2、s3、s4、s5同时发起了事务t1、t2、t3、t4、t5

  3. 这5个事务会因为GTID特性而具有全局唯一性并有序。例如:

    
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:146'      # 第1个节点的gtid序列
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1000033'  # 第2个节点的gtid序列
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:2000010'  # 第3个节点的gtid序列
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:3000009'  # 第4个节点的gtid序列
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:4000007'  # 第5个节点的gtid序列
    
  4. 只要同一个节点执行的事务,它的前缀是一样的,只是后缀会不断增长。例如

    1. 3个s1节点的事务,它们gtid的后缀可能会是146、147、148
    2. 3个s2节点的事务,它们的gtid后缀可能会是1000033、1000034、1000035。

3.1.1、分布式的xid

  1. 每个事务除了gtid,还有一个分布式的xid。
  2. 这个id也必须全局唯一,但同一个事务A1在不同节点上的体现值不一样。例如
    1. 在s1节点上,A1事务的xid=200
    2. 在s2节点上,A1事务的xid=222
  3. xid并不能保证顺序。举例如下
    1. 操作
      1. 第1步:在s1上执行开启事务t1执行DML,但不提交
      2. 第2步:在s2节点上开启事务t2执行DML,并提交
      3. 第3步:提交s1上的事务
    2. 结果
      1. 在s1上,t1的xid虽然值更小(先执行的事务),但在binlog中却排在t2后面。

3.1.2、冲突检测的3个限制

  1. 必须使用InnoDB引擎
  2. 必须开启gtid模式
  3. 表中必须有主键。

3.1.2.1、必须使用InnoDB引擎

使用InnoDB是为了保证所有数据写入都是事务性的,只有事务型的操作才能回滚,例如并发事务中检测到了冲突时需要回滚。

3.1.2.2、必须开启gtid模式

  1. 必须开启GTID模型是为了保证让事务具有唯一的事务ID,在组内传播出去后不会重复执行。
  2. GTID对组复制的影响是方方面面的,有了GTID,无论新节点还是曾经退出的旧节点,当它们再次加入到组中时都能保证不会与组中现有数据冲突。

3.1.2.3、表中必须有主键

表中必须有主键是为了冲突检测,这个和write-set有关。

3.2、并发事务t1、t2、t3、t4、t5如何执行

  1. 如果是单主模型,那么这5个事务都会路由到主节点上
    1. 如果这5个事务修改的数据互不冲突、互不影响:
      1. 那么它们都会成功应用到所有节点上
    2. 如果这5个事务之间有冲突
      1. 那么先提交的事务将获胜(事实上,这时的冲突事务会被阻塞)。
  2. 如果是多主模型
    1. 如果这5个事务路由到同一个节点上:这和单主模型的情况一样。
    2. 如果这5个事务路由到不同一个节点上
      1. 如果无冲突,则一切都OK
      2. 如果并发事务由冲突,那么先提交的事务获胜。因为此时,后提交的冲突事务,实际上是在修改过期的数据。

3.3、如何进行事务的冲突检测?

3.3.1、不满足冲突检测限制的场景

如果创建了MyISAM表,或者创建没有主键的表,没关系,它会复制走,因为它们是DDL语句,MySQL中没有DDL事务,但是不能再向这样的表中插入数据,这是强制的,如果插入数据将报错。

ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.

3.3.2、如何进行事务的冲突检测?

第1步、收集该事务将要修改行的写集(write-set)
  1. 当s1节点发起事务t1后,s1节点的replication协议模块(架构图)会收集该事务将要修改行的写集(write-set)
  2. 写集是根据每行的主键进行hash计算的,是否记得在组复制的配置文件中有一行:
    # 指定以"XXHASH64"算法将主键hash为写集。
    transaction_write_set_extraction=XXHASH64
    
第2步、s1节点将binlog和写集 发送到s2,s3,s4,s5

s1节点的replication协议模块 将binlog和写集一起传播出去,并被其它节点的replication协议模块收到。

第3步、s2,s3,s4,s5 收到 s1节点的binlog和写集
  1. 当s2,s3,s4,s节点收到后,会对写集进行验证,这个过程称为certify,它由certifier线程完成。
  2. 如果验证通过:
    1. 为此事务投上自己的一票
    2. 多数节点都投票后,交给applier组件写入数据。
  3. 如果验证不通过
    1. 表示有事务冲突,这时将直接通告全组并回滚。

      1. 如果多个节点上出现了并发事务,因为写集是根据表中每行的主键值来计算的,所以不同事务如果修改同一行数据,它的写集会相等,这表示并发事务出现了冲突。
      2. 如果两个事务经常出现冲突,建议将这两个事务路由到同一节点上执行。
    2. 注意:只要检测到了冲突,所有节点都会回滚,组复制不会为冲突事件进行投票决策。这里所投的票是非冲突方面的决策。

3.4、事务冲突问题

  1. 主要是多主模型下的问题,单主模型下只有单个主节点可写,不会出现事务冲突问题。
  2. 单主模型下,如果两个事务修改的是同一行,第二个事务将会因为独占锁冲突而被阻塞。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值