DM 的sync的方式能不能调整

之前用给gravity ,换了dm后,sql执行数增加了。
刚开了下general log,看看dm是怎么sync的,发现是这样做的:

START transaction;
delete from xxx where id=xxx;
replace into xxx (id) values (xxx);
replace into xxx (id) values(xx3232);
delete from xxx where id=xx2;
replace into xxx (id) values (xx2);
replace into xxx (id) values(3333232);
....
commit

就是穿插着delete和replace。然后好几个sql一起再执行一下commit。

gravity的同步基本上就是:
replace into xxx (id) values(1),(2),(3),(4);
并且是auto commit的

主要问题在于:

  1. 为什么已经要replace into 了,还要先执行下 delete?
  2. 为什么不能多个 values 拼一起,用auto commit提交?

怎么配置能实现类似 gravity 的同步方式?那种同步方式感觉性能好一些。

可能需要自定义 DM 的 SQL 模板或者使用 DM 的 route-rules 功能来重写 SQL 语句

写法不同吧,没有什么本质的区别

穿插着delete和replace这个可以提交一个issue;能多个 values 拼一起,这个要看你在源端提交的是什么吧

研究了下,仅供参考!

  1. 为什么已经要replace into 了,还要先执行下 delete?
    → 出于 “幂等性/可冲入行(idempotent/reentrant)” 考虑(but there are no ways to make update idempotent) → DM idempotent, tidb-binlog idempotent
    → 幂等的优势:后续日志完备条件下,可任意时间点重放。
    幂等定义,简而言之,update 不是密等的。

    For a mathematical example, 
        adding 1 changes the results, but multiplying by 1 is idempotent. 
        When you add 1 to a number and then add 1 again, you get different results. 
        If you multiply a number by 1 and multiply by 1 again, you do get the same result.
    
  2. 为什么不能多个 values 拼一起,用auto commit提交?
    → a. 为什么不能多个 values 拼一起?
    related explanation

    syncers:                             # sync 处理单元的运行配置参数
      global: 
      ......
        # 设置为 true,DM 会在不增加延迟的情况下,尽可能地将上游对同一条数据的多次操作压缩成一次操作。
        # 如 INSERT INTO tb(a,b) VALUES(1,1); UPDATE tb SET b=11 WHERE a=1; 会被压缩成 INSERT INTO tb(a,b) VALUES(1,11); 其中 a 为主键
        # 如 UPDATE tb SET b=1 WHERE a=1; UPDATE tb(a,b) SET b=2 WHERE a=1; 会被压缩成 UPDATE tb(a,b) SET b=2 WHERE a=1; 其中 a 为主键
        # 如 DELETE FROM tb WHERE a=1; INSERT INTO tb(a,b) VALUES(1,1); 会被压缩成 REPLACE INTO tb(a,b) VALUES(1,1); 其中 a 为主键
        compact: false
        # 设置为 true,DM 会尽可能地将多条同类型的语句合并到一条语句中,生成一条带多行数据的 SQL 语句。
        # 如 INSERT INTO tb(a,b) VALUES(1,1); INSERT INTO tb(a,b) VALUES(2,2); 会变成 INSERT INTO tb(a,b) VALUES(1,1),(2,2);
        # 如 UPDATE tb SET b=11 WHERE a=1; UPDATE tb(a,b) set b=22 WHERE a=2; 会变成 INSERT INTO tb(a,b) VALUES(1,11),(2,22) ON DUPLICATE KEY UPDATE a=VALUES(a), b=VALUES(b); 其中 a 为主键
        # 如 DELETE FROM tb WHERE a=1; DELETE FROM tb WHERE a=2 会变成 DELETE FROM tb WHERE (a) IN (1),(2);其中 a 为主键
        multiple-rows: false
    

    –>b. 为什么不能用auto commit提交?
    综上,为了把 delete + replace 控制在同一事务内,不能 auto commit。

1 个赞

厉害,学些了饿

// replace and delete are naturally reentrant.
// use delete+replace to represent update can make update reentrant.
// but there are no ways to make update idempotent,
这里面说 delete+replace 是为了让update 幂等,直接把 update 换成 replace into不能做到幂等吗?我这个不太理解。

另外:values 压缩这个事儿,有没有办法优先压缩values,比如说我能容忍1秒钟的延迟,那能不能把这1秒钟的values压缩成一条sql发到下游,而不是为了尽快发送到下游而发送了10条update或者insert。就是在dm中攒一会儿。

1 个赞
  1. 直接把 update 换成 replace into不能做到幂等吗?我这个不太理解。
    → 参考 TiCDC

    ···
    CREATE TABLE t (a INT PRIMARY KEY, b INT);
    INSERT INTO t VALUES (1, 1);
    INSERT INTO t VALUES (2, 2);

    BEGIN;
    UPDATE t SET a = 3 WHERE a = 2;
    UPDATE t SET a = 2 WHERE a = 1;
    COMMIT;

    但 TiCDC 内部收到的 UPDATE 事件顺序可能与上游事务内部实际的执行顺序不同

    UPDATE t SET a = 2 WHERE a = 1;
    UPDATE t SET a = 3 WHERE a = 2;
    ···

  2. 那能不能把这1秒钟的values压缩成一条sql发到下游,而不是为了尽快发送到下游而发送了10条update或者insert。就是在dm中攒一会儿。
    → 其实没太理解这样做的意义,不过感觉你要的是这个 batch

1 个赞

这个顺序如果不对的话,换成delete+replace结果也是错的吧。

这样做的目的是为了降低下游的压力。
batch默认是100.worker count 也改成了64.

其实我是想实现这种效果:
如果压力小,就攒一攒batch,一秒钟给下游执行一次就行。
如果压力大,就在batch满的情况下,多用几个worker发送。

现在的情况好像是 worker有空闲的就不batch了。这个顺序能调整吗?

1 个赞
  1. TiCDC 拆分 UPDATE 事件行为说明 | PingCAP 文档中心

    BEGIN;
    DELETE FROM t WHERE a = 1;
    DELETE FROM t WHERE a = 2;
    REPLACE INTO t VALUES (2, 1);
    REPLACE INTO t VALUES (3, 2);
    COMMIT;
    
  2. 简单翻了下 code,暂时没找到这样的逻辑 → “好像是 worker有空闲的就不batch了”
    也没看到能基于时间 batch 的参数
    compact 是有一些面板看输入输出的,调调吧

2 个赞
CREATE TABLE t (a INT PRIMARY KEY, b INT);
INSERT INTO t VALUES (1, 1);
INSERT INTO t VALUES (2, 2);

BEGIN;
UPDATE t SET a = 3 WHERE a = 1;
UPDATE t SET a = 1 WHERE a = 2;
UPDATE t SET a = 2 WHERE a = 3;
COMMIT;

在上述示例中,通过执行三条 SQL 语句对两行数据的主键进行交换,但 TiCDC 只会接收到两条 UPDATE 变更事件,即将主键 a1 变更为 2,将主键 a2 变更为 1,如果消费者直接将这两条 UPDATE 事件写入下游,会出现主键冲突的问题,导致 changefeed 报错。

看着里面总算理解了UPDATE为什么不能直接换成replace into了。
如果update主键,可能会造成主键冲突而执行失败。

感谢回复,至于下面这个逻辑,我看到的现象是打开下游的general log后,没看到values攒了很多的情况。以前用gravity同步时,每条replace into 的values能一大串,几十条。这样效率就很高。切换dm后,感觉效率不如gravity高。

1 个赞

此话题已在最后回复的 7 天后被自动关闭。不再允许新回复。