DM同步的事务冲突检测与事务执行的顺序性

场景描述:

  事务一(插入表T1,T2):
    开始时间:00:00:00
      insert into t1(id,name) values(1,'a');
      insert into t2(id,name) values(2,'b'); 
    结束时间:00:00:06
  事务二(修改T2):
    开始时间:00:00:07
      update t2 set name = 'a' where id = 2;
    结束时间:00:00:08

问题:
上述场景中,能不能确保事务2中的修改语句一定在插入表T1数据之前运行? 根据官网描述,只能保证事务2中的修改语句一定在插入表T2数据之前运行,并不能保证在插入表T1数据之前运行?我的理解对吗?

另:如果事务2执行的也是insert语句,冲突检测时会认定为冲突吗?能保证事务2中的插入语句一定在插入表T2数据之前运行吗?

引用官网资料:

遇到 DML job,会 先检测并且尝试解决冲突。如果检测到冲突(即存在两个 executor 的 worker 的 jobs 都需要与当前的 job 保持顺序执行),会发送一个 flush job 来等待已经分发的所有 DML jobs 执行完成,然后再将 job 分发到对应的 worker,并且记录该分发信息到内存。在没有冲突的情况下,如果不需要与已经分发出去的 job 保持顺序的话,发送 job 到任意 worker 上;如果需要保持顺序的话,那么根据内存储存的历史分发信息,发送 job 到对应的 worker 上。

按照你上面的描述,事务 1 比事务 2 会提前完成,不存在冲突的情况。

冲突时按事务时间检测吗?
如果事务时间不冲突,一定会按顺序执行吗?

具体的事务冲突还是在 tidb 层去检测,可以详细了解下 tidb 的乐观锁事务。

tidb的乐观锁大概明白。
不过同步时的冲突检测是在tidb上还是dm上?我看官网资料好像是dm上检测完毕,才做任务分发到dm-worker上的吧,dm-worker执行的时候的才会用到tidb的乐观锁吧。dm检测跟tidb一样的吗?

辛苦把链接附上一下,看下我们理解的是否有歧义

不一样。dm 这边 冲突检测实现,根据转换步骤获得每条 statement 对应的 primary/unique key 信息,来进行交集检测,如果存在交集那么认定是需要顺序的执行两条 statement。(上述场景也不会冲突)

tidb 的冲突检测是在提交时,根据 primaryRow 中记录的锁的信息来做冲突检测。

1 个赞

基于dm的检测与tidb的乐观锁,上面的问题中能确保事务2中的修改语句一定在插入表T1数据之前运行吗?

不能。

事务 1 比事务 2 会提前完成,为什么还不能确保事务2中的修改语句一定在插入表T1数据之前运行?如果单线程同步呢?

在不修改主键的前提下,这个可以简单的理解为:同样主键的所有操作,是有序的;不同主键的操作间,无顺序保证;另外纠正一下,上述问题能保证先 INSERT id=2 的记录后再 UDPATE;其他的就没保证了。

DM 根据主键、唯一键算出一个 hash 后分到不同的 worker 线程去执行,相同的主键、唯一键的值,对应的所有操作,自然都分到同一个 worker 线程了,但不的的键值,是分发到不同的 worker 线程的,就并发起来了,顺序无保证。

1 个赞

如果是单worker、单线程情况下呢?能保证吗?

单线程串行执行操作

单线程串行执行操作 能确保UDPATE job再事务1的所有任务之前吗?毕竟UDPATE 事务时序上事务1之后

就上面的 case ,Trx 2 commit 的时间是在 Trx 1 的commit 时间之后。 MySQL 中生成的 Binlog 也是先 Trx 1 再 Trx 2 的顺序,所以 DM 读取的时候也是先 Trx1 然后 Trx2 顺序读取,在拆分的过程 Trx1 的 insert 语句到不同的 worker 线程进行并行执行 。如果 上面的 case ID 为 PK 或者 UK 的话 ID = 2 的 Update 会被分配到与 Insert 的同一个 Job queue 。

1 个赞

在多线程环境下,对相同主键的update操作有序,其他由于并发问题并不能保证顺序。即使是在不同事务,事务没有时序冲突。
在单线程下,job是串行执行操作。但是如果DM 读取的时候是并行的,就上面的case,又有可能出现insert into t2 (id=2)–> update t2 (id=2)–>insert into t1 (id=1)。
所以DM 读取后再拆分任务的时候会导致出现该情况吗?

1个 DM worker 生成 1 个读取的线程,分发到多个 worker 线程并行执行 。所以并不会发生你刚才说的情况。

1 个赞

1个 DM worker 生成 1 个读取的线程
那么单worker、单线程下可以保证有时序的事务的顺序。
如果事务存在时序冲突呢?DM worker读取线程是按照binlog的事务commit时间还是binlog事务开始时间或者binlog文件中的binlog顺序?

根据 binlog 的顺序,一个个 Event 读取。

1 个赞