一种并行加载的方法

1 7th, 2010 | Posted by jacky | Filed under 大话技术

一个数据库的同步系统,可以分为三部分:抓取变化,传输和加载。抓取数据库变化,最通常的做法是用trigger记录到表中,或者通过解析Oracle redo log中的信息来抓取。传输是将数据库变化记录到特定格式的文件中,通过网络推送到目标数据库上。加载则是指在目标数据库上应用这些变化(SQL),这里主要是讨论并行加载的实现思路。

我们通过trigger或者redo log得到了数据库变化的事务流,这个流是按照事务的提交顺序排列的,最简单的方法是在目标端按照这个事务流顺序执行,就是串行执行。这么做的最大优点是可以完全保证事务的一致性,但是缺点是性能很差。如果采用并行加载,就需要考虑事务相关性的问题,所谓事务相关性,是指两个或多个事务更新了同一条或者多条记录,他们之前存在时间上的依赖关系。如果将具有相关性的事务分在不同的并发进程上加载,可能出现后面的事务被前面的事务覆盖掉的情况,最终导致事务混乱。

我们设计一个并行加载的方法,目标是尽可能快的加载数据,保证不会产生数据混乱的情况,但是不能保证事务完全的一致性。这句话如何理解,假设两个事务不相关,A事务只更新A表,B事务只更新B表,如果在源库A事务先于B事务完成,那么在目标库可以让B事务先于A事务执行,或者两个事务并行执行,虽然事务的顺序与主库并不一致,但是数据是正确的,因为两个事务不相关。

我们如果按照事务去分拆并行的话,设计比较困难,因为涉及到事务的相关性分析。换个思路,我们可以按照数据来拆分并行,也就是把同一个事务拆分到不同的并发进程中,保证表的同一行记录的所有更改都由一个并发进程处理。按照这个思路,我们首先把事务流加载到一个队列或者一个内存结构中去,为了理解方便,我们可以认为放在了一张内存表中,这个表有以下几个字段,事务ID,表名,PK,SQL,时间序列号。首先按照不同的表分组,将不同的表的操作分配给不同的进程处理,每个并发进程按照事务提交的时间顺序来执行。比如:A事务更新A,B,C三张表的A1,B1,C1记录,B事务更新A,B,C三张表的A2,B2,C2记录,C事务更新A,B,C三张表的A3,B3,C3记录。三个事务的提交顺序是A,B,C,这时我们可以启动三个并发进程,分别处理A表,B表和C表的操作,顺序是A1,A2,A3……这样就实现了最简单的并行,虽然目标库的事务与主库并不一致,但是数据是完整和正确的。

按照表来做并行可能还不足够,如果某张表的更改量特别大,这时我们还可以进一步分组,针对同一张表中的操作再按照行(PK)分组,保证同一行的不同操作分配到同一个的并发进程处理。这里有一些小的技巧,在很多情况下,我们可以只关注某行的最后一个操作就可以了,比如某行的最后一个操作是delete,那么我们只需要执行delete,之前的操作就可以直接丢弃,如果是insert,那么我们可以在目标库先执行delete,然后再insert,针对我们自己的系统,有些表的update是全部字段更新,所以我们直接采用了merge操作,相当于对同一行的不同操作,我们做了合并处理。因为系统是自己开发的,所以可以针对我们自己的特性定制了功能。

有人说这个思路有些土,Oracle logical standby,Goldengate或者Shareplex这些商业软件是怎么做的?我之前也写过一篇文章探讨这个问题:Oracle Logical Standby SQL Apply Architecture,这些商业软件都声称自己分析了事务的相关性,可以做到并行加载,但是同样也存在事务不一致的问题,但是分析事务的相关性肯定要按照表或者行来分析,所以思路应该不会差太远,无非是他们包装得更好。

PS:这个方法并不是我想出来的,是团队的智慧。现在看起来思路挺简单,但是其实困扰了我们很长的时间。当然如果你有更好的方法,欢迎和我讨论。

–EOF–

标签:
  1. P.Linux
    1 8th, 201015:42

    操作合并这个思路很不错,以前有想过,复制事务操作的时候只复制增量,多个UPDATE归并为一个UPDATE,先INSERT后UPDATE的归并为一个INSERT,先INSERT后又被DELETE或者先DELETE又被INSERT的归并为空(不操作),希望对某行的操作都归并为一次操作或者空操作,然后把同一表中的一些连续性好的UPDATE/INSERT/DELETE语句归并到一个批量操作,就像patch一样传到目标库去当作一个整事务执行,不过并发执行没想到如何处理。

  2. 丁原
    1 8th, 201016:32

    如果一个表的dml需要依赖另一个表的话,数据应该还是会出现不一致的吧。

  3. jacky
    1 9th, 201019:30

    一个不表的DML依赖另一个表的?你是指insert into a select from b这种SQL吗?但是请注意,我们的系统并不是记录原始的SQL,而是记录真实数据的变化,这种语句会被变成很多条insert into value。
    这个有点像MySQL复制中的statement和row模式。

  4. P.Linux
    1 9th, 201020:38

    Jacky这样一说我大概明白了。
    有一句话我不理解,“保证同一行的不同操作分配到不同的并发进程中”,从我的想法中,Merge完全的话,应该一行只会剩下一个最终操作了吧?

  5. jacky
    1 10th, 201022:53

    这句描述有误,应该是:保证同一行的不同操作分配到相同的并发进程中,其实就是对同一行的操作做了合并。

  6. 丁原
    1 11th, 201016:41

    我们的系统并不是记录原始的SQL,而是记录真实数据的变化 –这个是 oracle redo自己的机制吧

    我说的是这种情况,如果拆分成两个不同进程去做,是否会引起数据的不一致呢。
    update a set status=1 where id=2;

    update b set type=3 where id in(select bid from a where id=2 and status=1);

  7. jacky
    1 11th, 201017:07

    哥,说过了我们是row方式,不是statement方式。
    update b set type=3 where id in(select bid from a where id=2 and status=1);

    这个SQL在目标端变成了若干条SQL:
    update b set type=3 where id=1;
    update b set type=3 where id=2;
    ……

  8. 丁原
    1 12th, 201009:42

    我晕了。
    你只是把redo解析出来,然后分进程应用,不涉及到任何statement sql

  9. jacky
    1 12th, 201011:22

    任何逻辑同步系统,都不可能是简单的记录SQL,然后再到目标端应用,而应该是记录数据的变化,然后再将这些变化转成SQL,再应用到目标端。

  10. swallow723
    1 19th, 201013:43

    今天公司来了个Greenplum的介绍交流会,中午正好又拜读了大侠的关于Greenplum的理解,自我感觉你的解析与介绍会的主讲人讲的很一致,而且增加了我对这个新数据库的了解.
    我觉得所有数据仓库关于性能的问题都交给Greenplum这样的数据库系统去处理了,我怀疑关于数据库性能的优化,还需要DBA吗?或者在IT数据仓库部门只需要招一些懂架构与管理,再来些存储管理维护的人就够了,似乎DBA的很多事情就要被那些人取代了,而且那些人不必是资深人士.但毕竟Greenplum只是专长为OLAP设计,而非通用数据库系统.
    当然我也不是那些资深人士或非资深人士,也不是一个DBA,只是一个有时想成为一个DBA,但实际上绝大多数时间都是做着业务开发的普通业务分析处理人员,但我还是认为DBA是一个非常令人尊敬与向往的职业,希望这个职业的人永远都有做不完的事去等待着做,那意味着DBA这职业在国内会越来越发展的好!说不定在哪天我也会放开胆量,拿起勇气,点燃我的DBA之路.
    不知你现在是否还确定在这个领域精耕细作,因为在关于Greenplum的讲述最后,我看到了你关于是否要向新方向发展的考虑,因为那会让我心底埋沉着的DBA意念产生影响,似乎国内关于技术坚持到一定的程度都必须转向其它方向发展.

  11. 业余DBA
    1 23rd, 201022:55

    将数据的操作先按表再按行来弄是个好主意。在某张表更新量大的情况下,对行的更新不可能精确到某一行,因为很多情况下得到的行是动态的,我认为可以用范围来限定,考虑设置一个滑动的窗口来约束一下,以保证串行化。

    探讨而已。

  12. j2wk
    4 14th, 201000:49

    非常类似的思路,我们在07年设计了一个叫数据交换平台的软件,是JAVA+PL/SQL做的,软件不大,但个人认为功能还算比较强,但与你的应用场景稍有差别,我们主要用于企业内、外多系统之间的双向数据共享,但用于数据库同步一样好用,在系统设计之初,你提到的并行加载的问题我也一样遇到了,为了效率做了多个方面的分析和考虑,应该说最后还是较巧妙的解决了这些问题。主要涉及技术:
    TRIGGER、PL/SQL(这里面用了不少ORACLE特性,动态SQL,数组绑定,索引表,临时表,XDK,自定义锁管理。。。)、JAVA 多线程、JMS、XML、JOB 等,配置很简单,目前在行业内全国应用范围越来越多,,有这方面兴趣的话,可交流经验
    msn: wk_sz@hotmail.com

    BTW:个人一直很欣赏TAOBAO DBA TEAM !

  13. jacky
    4 14th, 201009:42

    我也很欣赏taobao dba team,可惜俺不是taobao的:)

  14. j2wk
    4 14th, 201013:04

    呵呵,窘