数据库在设计之出,除了满足数据规范管理,查询统计方便,数据结构设计方便之外,最大的功能就是保证事务完整性了;当事务提交(commit)时,要保证内部所有交易成功才返回成功,否则要回滚(rollback),保证所有数据回退到提交之前的状态。

      无论在证券系统、银行系统、税务系统、电信计费系统、电力系统,只要涉及到一个交易多表或者多记录同时操作,为了让多条记录能够保持多条联动,都必须用到事务提交,所以事务是数据库为满足交易数据多条SQL语句执行完全成功或完全失败而设计的保证交易一致性的SQL语句组合。

      在数据库同步过程中如何保持事务的完整性呢?如果不考虑执行效率,我们可以很简单的设计为,抽取到日志后,记录事务流水,转换流水,装载事务,修改流水状态,这样一个事务的同步就完成了;即使最后一步失败,我们也可以根据最后事务中不同的DDL和DML语句来分析该语句在备库的执行状态,之后再决定继续执行还是执行下一个事务,这就是断点

      但是我们在进行数据库同步项目实施的过程中,不断出现一个问题:如果事务串行加载,那对于银行、证券等行业晚上的批处理交易而言,就出现很大效率问题,因为对于抽取进程,我们一定要把日志中成功提交的日志进行同步,对于失败的交易我们不应该再去进行抽取和分析,但是如果大交易(100万SQL语句/笔),提交后,会产生大量日志,我们分析日志的时候会记录事务日志流水,这样磁盘I/O就产生很大的瓶颈,假设该事物产生的事务日志为100W*1024Bytes=1G,如果每秒磁盘IO速度是40M,那么需要25秒,这就说明当主库日志产生后,我们抽取进程通过网络(假如网络100M独享)获得日志需要10秒),那么从日志抽取到写入到流水文件至少要35秒时间才把一个大事务写完成,如果我们再考虑装载速度,一个事务装载效率是远程SQL执行时间+回写完成状态时间,如果我们把这个过程最小化:数据库连接使用长连接,装载用OCI批量装载,则装载SQL执行时间大约为1000秒,回写时间25秒,则装载总用时约为1025秒,加上抽取的35秒,接近18分钟,所以对于同步效率要求比较高的金融行业来说,同步灾备系统18分钟就有些慢了,但是这种方式对于事务完整性来说确实很简单的方法,每次执行都会写入事务断点,所以串行效率低但依然很有效,那么如何合理提高装载效率呢?

      目前基于交易日志方式同步的技术在装载上考虑最多的是并行装载,其实很简单,就是把事务按照表来分解为表级别串行数据,不同的进程来完成不同表的装载,这样装载时间按照就是1000/N,表越多,数据库装载效率越高,当然,数据库连接也越多,占用备库资源也越多,但是对于备库只作为查询服务器来说,占用资源并不会对系统用什么影响,又何况是晚上的数据库呢?

      但是虽然这样提高了装载效率,事务却被我们分解成了很多的小交易,都是基于不同表的,那当中间执行出错情况下,如何保证事务完整性呢?这就要用到从前我们提到的网格断点来实现(参见《如何保证数据库同步中目的端交易提交的原子性》),当每个进程执行成功后就会修改自己对应的断点文件,所以当系统出现异常的时候我们就会检查所有的断点文件,这样数据库就可以根据断点情况继续同步对于不同的DDL和DML语句进行相应的错误处理,无断点的进程会将同步执行完毕,有断点的会停留在断点处,等带人工判断。