☰
Oracle GoldenGate Replicat非集成模式切换协同模式实战
2026/10/14 15:53:34 网站建设 项目流程

前阵子处理一套 Oracle GoldenGate(下面统一叫 OGG)数据分发链路时,目标端用的是最传统的非集成模式(nonintegrated)Replicat,也就是经典应用进程。链路跑了一年多一直很稳,但源端上线了几个大事务批处理之后,目标端延迟开始肉眼可见地堆积。把网络、磁盘、日志归档都查过一轮之后,问题最终落在应用进程本身上,把 Replicat 从非集成模式切到协同模式(coordinated)之后,同一条链路的延迟数据明显降了下来。

切换之前我也做了不少功课,发现网上关于这种“非集成模式 → 协同模式”的转换,要么只讲原理不给命令,要么直接丢一个流程让照抄,中间很多关键的前置检查和检查点细节都被一笔带过。这篇文章把这次转换涉及的架构差异、硬性条件、操作全流程、线程调优以及实际踩到的坑完整写出来,给准备做同类切换的同行一个能直接参照的落地方案。

1. 为什么要把 Replicat 从非集成切到协同模式

1.1 两种应用进程模式的本质差别

OGG 目标端的 Replicat,早期默认就是非集成模式,很多文档也叫经典模式。这种模式下,Replicat 是一个单进程,从 trail 文件里按顺序读出事务操作,再通过 OCI 或普通数据库接口一条条写到目标端。好处是结构简单、跨库兼容性好,坏处也直接:一条事务里哪怕有百万行操作,也只能串行执行。

协同模式也就是协调 Replicat,它由两部分组成,一个是协调器进程,另一个是若干 worker 线程。协调器负责读取 trail、分析事务内部的依赖关系,把可以并行处理的不同行子集拆给多个 worker 线程,并行应用到目标端。这个并行处理主要发生在 OGG 进程内部,不依赖目标数据库的并行执行引擎。它跟集成模式(Integrated Replicat)不一样,集成模式是把事务解析和应用分散到目标数据库内部的并行服务里,协同模式则是 OGG 自己的多线程架构。

需要强调的是,协同模式的并行效果,依赖 trail 里是否带有足够的行依赖信息,而这个信息通常来自源端的集成捕获(Integrated Capture)。如果源端到现在还是经典捕获,那就算把目标端换成协同 Replicat,也拿不到依赖关系,很难发挥并行优势,极端情况下甚至跑不起来。后面我会专门讲这个前置条件。

1.2 协同模式解决的核心瓶颈

经典 Replicat 最怕的是两类负载:一类是整体事务量很大,另一类是大事务特别大。举个直观的例子,源端有一条 UPDATE 涉及数百万行,这条事务在 trail 里就是一大串操作记录。经典模式只能刷单线程,一行一行活。就算每行处理只要 0.1 毫秒,几百万行下来也是好几分钟甚至几十分钟。单线程期间,后面所有排队的事务都要等,目标端延迟自然越积越多。

协同模式能把这条大事务根据依赖关系拆开,不同行子集交给不同 worker 并行提交,整体耗时大幅下降。但并不是拆得越碎越好,因为拆分之后,每个 worker 提交完成前,协调器还要负责汇总、保证事务整体顺序,这个环节本身也有开销。如果业务负载本身全是零散小事务,切换协同模式的收益就没那么明显,反而可能因为线程调度增加额外开销。

1.3 我不建议切协同模式的场景

协同模式不是万能药。如果你满足以下情况,建议先评估收益再动手:

  • 目标端不是 Oracle 数据库,而是异构数据库;
  • 源端捕获模式还是经典模式,且短期没有改造计划;
  • 业务事务普遍很短很密集,而且单笔事务数据量不到万行级别;
  • 业务里有大量 DDL 操作,尤其频繁的加列、改表、重建索引。

这些场景里,经典模式或者集成模式往往都更合适。我这次转换之所以有效果,核心原因就是源端有大事务,而且目标端确实是 Oracle,两条缺一不可。

2. 切换之前的硬条件检查清单

2.1 源端必须已经是集成捕获

这是整个切换里最容易忽略、也最容易掉链子的一项。协同 Replicat 想要实现事务内部并行,需要从 trail 里读取一张依赖图,告诉协调器哪些行可以并行、哪些行必须保持先后顺序。这个信息在经典捕获(Classic Capture)生成的 trail 里压根没有,只有源端 Extract 跑在集成捕获模式下,trail 才会带这些元数据。

检查方法很简单,在 GGSCI 里执行:

GGSCI> INFO EXTRACT ext1, DETAIL

如果输出里能看到 Integrated 相关字样,说明源端已经是集成捕获;如果还是 Classic Capture,就要先把 Extract 迁移到集成模式。集成捕获要求源库版本在 11.2.0.4 以上,而且使用 DBLOGIN 连接源库时权限要足够。源端切换集成捕获本身又是一个独立工程,步骤上要停止 Extract、重新注册抽取组、调整参数文件后再启动,这里不展开,但你心里要清楚:目标端切换只是整个改造的后半段。

2.2 版本、数据库与表结构约束

协同 Replicat 在 OGG 11.2.0.4 时代就已经开始有支持,但大量行为在后续版本里才逐步完善。我给的建议是至少使用 OGG 12.1,生产环境最好用 12.3 或更高版本。目标数据库版本同样要 Oracle 11.2.0.4 及以上,目标库版本太低,worker 的会话和并行参数不好配置。

表结构层面的检查也不能省。协同模式需要识别行依赖,所以目标表必须有主键、唯一约束,或者至少在参数文件里显式指定 KEYCOLS。没有主键的堆表如果原来靠 ROWID 做映射,转到协同模式后很容易出问题。另外,LONG、LONG RAW 这类老式字段类型,协同模式的支持非常有限,如果业务表里有这种列,建议先在映射层做转换或者把表结构调整掉再切换。

这里插一个实用检查语句,可以快速找出目标端缺主键或唯一键的同步表:

SELECT table_name FROM user_tables t WHERE NOT EXISTS ( SELECT 1 FROM user_constraints c WHERE c.table_name = t.table_name AND c.constraint_type IN ('P', 'U') );

查出结果之后,要么补主键,要么在 Replicat 参数里给这些表加 KEYCOLS。不要带着一堆无键表直接切,后面启动和验证阶段会非常痛苦。

2.3 Replicat 参数文件里的“违禁”参数

经典 Replicat 参数文件里,有不少参数是协同模式不支持的,最常见的包括 BATCHSQL、GROUPTRANSOPS、MAXTRANSOPS、NUMFILES、DYNSQL 这些。之所以不支持,是因为协同模式要基于依赖图拆分事务,没法像经典模式那样把一批小事务压缩合并后再执行;一旦同时存在,线程拆分逻辑和参数逻辑会起冲突,启动时 GGSCI 会直接报参数解析错误。

转换前最好把参数文件过一遍,把这几类参数删掉或者注释掉。不用太担心删掉之后性能下降,因为协同模式本身已经用多线程把并发做上去了,这些老参数的位置已经由 MAXTHREADS 和依赖图调度代替。

2.4 DDL 复制在协同模式下的边界

经典模式对 DDL 的处理相对成熟,映射关系也灵活。协同模式当然也支持 DDL,但它会有一个比较大的行为差异:DDL 一般由协调器集中处理,在执行 DDL 前后,多个 worker 线程要经历一次同步屏障,保证各线程状态一致。也就是说,DDL 不会因为并行而变快,反而会打断并行。

因此,如果同步链路里包含大量 DDL,切换协同模式之后,你可能会看到延迟在 DDL 执行节点上出现周期性尖峰。建议在切换前把同步对象梳理一遍,确认 DDL 频度可以接受。如果业务就是每天早上改几十张表结构,那协同模式的收益会被明显稀释,要慎重。

3. 转换操作全流程:从记录检查点到重建应用进程

3.1 先备份再动手

切换模式不是改一个参数那么简单,我给出的方案是“停止 → 记录检查点 → 删除旧组 → 以协同模式重建”。在删除 Replicat 组之前,一定要先备份好这些内容:

  • 参数文件,通常位于 OGG 安装目录的 dirprm 下;
  • 检查点文件,通常位于 dirchk 目录;
  • 当前进程的报告文件,位于 dirrpt 目录;
  • GLOBALS 文件。

备份的命令很简单,直接复制目录就可以:

cp -r $OGG_HOME/dirprm $OGG_HOME/dirprm_bak_before_coord cp -r $OGG_HOME/dirchk $OGG_HOME/dirchk_bak_before_coord cp -r $OGG_HOME/dirrpt $OGG_HOME/dirrpt_bak_before_coord cp $OGG_HOME/GLOBALS $OGG_HOME/GLOBALS_bak_before_coord

有人会觉得备份这一步多余,但在生产链路里,万一切换后业务异常需要快速回退,这些备份就是你最后的逃生通道。我后面讲回退踩坑时会再展开。

3.2 停止并记录检查点位置

进入 GGSCI,先登录目标端数据库:

GGSCI> DBLOGIN USERIDALIAS ogg_admin

然后查看 Replicat 的状态和检查点位置:

GGSCI> INFO REPLICAT rep1, DETAIL

输出里会有一个当前检查点(Checkpoint position)信息,通常包含 trail 文件的名称、序号(Seqno)和字节偏移(RBA)。我用这个项目里的模拟进程 rep1 举例,命令长这样:

GGSCI> STOP REPLICAT rep1

停止之后,再执行一次 INFO REPLICAT rep1, DETAIL,确认位置没有变化,然后把这个 Seqno 和 RBA 抄下来。这一步是核心,后面重建进程时会用到。

这里有一个细节必须提醒:如果没有特殊处理,直接删除 Replicat 组再从 trail 头开始跑,那目标端会出现大量重复应用,报主键冲突简直是必然事件。所以要靠 EXSEQNO 和 EXTRBA 把新进程的起点精确指定到旧进程停止的位置,这样除了模式变化之外,复制逻辑基本是连贯的。

3.3 删除旧组并重新添加协同 Replicat

检查点记录好之后,先删除旧 Replicat 组:

GGSCI> DELETE REPLICAT rep1

DELETE REPLICAT 不会删除 trail 文件本身,只是清理掉进程定义和内部检查点。接着用协同模式重新添加:

GGSCI> ADD REPLICAT rep1, EXTTRAIL ./dirdat/aa, COORDINATED, MAXTHREADS 8, EXSEQNO 128, EXTRBA 1024

这里 EXTTRAIL 后面的路径要和你原进程保持一致,COORDINATED 表示使用协同模式,MAXTHREADS 是初始线程数,我建议先设 8,别一上来就拉满。EXSEQNO 和 EXTRBA 就是刚才从旧进程记录下来的 seqno 和 rba。

如果你坚持不指定 EXSEQNO 和 EXTRBA,那么新进程会从对应 trail 文件的开头开始读取并应用,这在目标端数据已经追平的情况下基本等于重新灌一遍,属于典型的自杀式操作。除非链路本身就是要从头同步一张空表,否则千万不要省略这两个参数。

3.4 批量改造 Replicat 参数文件

添加完组之后,编辑参数文件:

GGSCI> EDIT PARAMS rep1

经典模式参数文件一般长这样:

REPLICAT rep1 TARGETDB ORCL, USERIDALIAS ogg_rep SOURCEDEFS ./dirdef/source.defs BATCHSQL GROUPTRANSOPS 200 MAXTRANSOPS 100 MAP USERS.*, TARGET APP_USERS.*; MAP SALES.*, TARGET APP_SALES.*;

切换到协同模式后,我建议改成这个样子:

REPLICAT rep1 TARGETDB ORCL, USERIDALIAS ogg_rep SOURCEDEFS ./dirdef/source.defs COORDINATED MAXTHREADS 8 REPERROR DEFAULT, ABEND DISCARDFILE ./dirrpt/rep1.dsc, APPEND, MEGABYTES 100 MAP USERS.*, TARGET APP_USERS.*; MAP SALES.*, TARGET APP_SALES.*;

改动要点很清晰:删掉 BATCHSQL、GROUPTRANSOPS、MAXTRANSOPS;把 COORDINATED 行放到 REPLICAT 行之后,MAP 之前。MAXTHREADS 可以只出现在 ADD 语句里,但写在参数文件里更直观,而且后续改起来也方便。REPERROR 和 DISCARDFILE 是常规保留项,不影响模式切换。

还要注意,如果你的映射里有 DDL 相关配置,比如 DDLEXCLUDE、DDL INCLUDE 之类的,建议切换后先降低 DDL 映射范围,或者在一张测试表上验证完再放开。前面说过,DDL 在协同模式下要走同步屏障,频繁 DDL 会影响整体并行效率。

3.5 启动新进程

参数文件改完后,直接启动:

GGSCI> START REPLICAT rep1

启动之后不要急着看延迟,先看进程是不是真的起来了:

GGSCI> INFO REPLICAT rep1, DETAIL

如果启动失败,报告文件和告警日志里通常会直接说哪个参数不被协同模式支持,或者哪个位置不合法。按提示调整后再启动。正常启动后,协调器和各个 worker 线程的状态都应该是 Running。

4. 协同模式启动后的线程验证与调优重点

4.1 用 INFO REPLICAT 观察线程状态

协同模式和经典模式最直观的区别,就是 INFO REPLICAT DETAIL 的输出结构不一样。经典模式只有一条进程信息,协同模式下会看到 Coordinator(协调器)和多个 Worker Thread 的独立状态。每个 worker 都有自己的位置,状态都是 Running 时,说明并行应用是正常的。

我在切换后的十分钟内,每两三分钟就看一次:

GGSCI> INFO REPLICAT rep1, DETAIL

重点看各 worker 的 Seqno、RBA 是否都在往前推进。如果发现除了 Coordinator 之外,只有一两个 worker 在动,其他 worker 全部空闲,说明 trail 里的依赖信息没有用上,或者源端的集成捕获还没配置好。

4.2 MAXTHREADS 动态调整与连接数规划

协同模式的线程数不是配好就一劳永逸,它可以在运行中调整。我们项目里一开始设的 8 个线程,业务高峰时发现延迟还是有一点,后来执行:

GGSCI> ALTER REPLICAT rep1, MAXTHREADS 16

线程数调高之后,不需要重启进程,协调器会把新的线程纳入调度。这个动态调整能力很实用,它让你可以先用低线程数跑一段时间,观察监控曲线之后再加。

不过线程数不是越大越好。每个 worker 在目标端都是一个数据库会话,如果 MAXTHREADS 是 16,那至少会有 17 个会话(16 个 worker 加 1 个协调器)同时连到目标库,还不算其他业务会话。调线程前一定要评估目标库的 processes 参数和连接池余量,否则线程一多,数据库先把连接数打满,应用直接罢工。我的经验是初始线程数设为服务器 CPU 核数的 1.5 到 2 倍,等测出瓶颈再加。

4.3 大事务实测中的观察重点

切换后,我特意在源端触发了一条模拟的大事务,大概涉及几百万行更新,用来对比切换前后的差值。切换前经典模式重放这条事务大约要几十分钟,切换后协同模式只用了原来的三分之一左右。这个收益并不仅仅来自多线程,更关键的是这些行本身的更新范围是天然独立的,协调器把不同行范围分给了不同 worker,互不干扰,整个事务的提交时间被大幅压缩。

但有个情况也要有预期:事务拆成多个子段并行后,不同 worker 完成时间不一样,协调器必须等所有子段完成才能提交整个事务。所以实际耗时并等于“总操作数除以线程数”,还要加上汇总等待。观察大事务重放时,的重点是看延迟尖峰是否被削平,而不是看某一个事务是否被拆得飞快。

4.4 报告文件读法

OGG 报告文件在 dirrpt 目录下,文件名一般是进程名加日期序号,比如 rep1.rpt。切换到协同模式后,报告里会单独列出各个 worker 线程的处理统计,包括读取位置、操作数、事务数等。我建议切换后隔一小时看一次,如果发现某个 worker 长期没有操作数变化,大概率是数据倾斜或者依赖图过强,需要调整映射分组或者线程数。

顺便说一句,报告文件默认是追加写的,时间长了会很大。最好在参数文件里用 MAXREPORTROWS、REPORTCOUNT 之类的参数控制输出频率,不然排障时连翻日志都费劲。

5. 转换中后期最容易踩的坑清单

5.1 经典 trail 直接挂协同 Replicat 的后果

这个坑我在测试环境遇到过。当时源端 Extract 还是经典捕获,我直接删掉旧 Replicat,用协同模式重建,进程能启动,但延迟几乎没降。进一步看报告,发现大部分操作都集中在同一个 worker 上,其他 worker 全在空转。

原因就是经典捕获的 trail 里没有集成捕获注入的依赖关系元数据,协调器拿不到可靠的依赖图,只能保守地按多数事务的先后顺序串行应用。最后我是先把源端 Extract 切换成集成捕获,重新生成 trail,再让协同 Replicat 跑,并行效果才真正出来。所以听我一句劝:先源端、后目标端,顺序不要反过来。

5.2 无主键表和字段类型导致的启动失败

另一个测试场景里,我有一张日志表本来就没有主键,经典模式下靠字段组合映射也能跑。切到协同模式后,进程启动直接报错,日志里明确提示需要主键或 KEYCOLS。解决方法是给参数文件里的映射加上 KEYCOLS,比如:

MAP SOURCE.LOG_TAB, TARGET TARGET.LOG_TAB, KEYCOLS (LOG_ID, CREATE_DT);

没有任何唯一性标识的物理表,建议切换前先把表结构补好,否则即使 KEYCOLS 硬写也未必能给出业务级唯一语义,后面数据冲突会很难收拾。类型方面,LONG、LONG RAW 这种老类型建议提前处理,别指望协同模式能帮你想办法。

5.3 检查点无法回退的教训

我最初以为切换就是改改参数,删组之前没有保留检查点文件。后来因为业务方临时要求快速回到经典模式,我试图用旧检查点直接把进程恢复成非集成模式,结果发现进程定义和检查点已经全部被 DELETE REPLICAT 清掉了,只能重新搭建链路。

后来总结出一套保底动作:删除旧组之前,把 dirchk 整个目录复制出来,同时把经典模式下的 ADD REPLICAT 命令记到文档里。真需要回退时,可以恢复目录快照、重建旧进程、从原检查点继续。虽然回退场景最好永远不要发生,但你要保证万一发生时自己还有操作空间。

5.4 瞬间高并发与线程风暴

协同模式把单个大事务拆成多个子段后,目标端会出现短时间内的并发激增。有一回我调完 MAXTHREADS,目标库的日志切换频率直接翻倍,性能监控里能看到明显的瞬时 CPU 峰值。

这不是 bug,而是拆分后的正常现象。只是如果目标端数据库配置比较保守,或者业务高峰期不适合额外负载,这种瞬时并发可能引发连接数打满。建议在切换窗口选择业务低峰期,线程数从 4 或 8 起步,跑完一个大事务样本再逐步往上加。不要一上来就 32 线程,目标库会告诉你什么叫“线程风暴”。

6. 切换到协同模式后的一次复盘经验

把这套链路切完并稳定运行两周之后,我自己复盘了一遍整个过程,最想说的其实就两点。

第一点是切换前一定要把源端集成捕获和目标端协同模式当成一个整体来规划。很多人盯着 Replicat 改来改去,忽略了 trail 里的元数据才是并行调度的“食材”,源端没准备好,目标端再折腾也是白搭。我这次第一阶段就是只切了 Replicat,效果不满意,回头把源端 Extract 切成集成捕获后再看,延迟曲线才真正掉下来。

第二点是切换后的调优要耐心。切完不要急着把线程数拉满,先观察一个大事务的完整重放过程,再结合报告文件判断是数据倾斜问题还是线程不足问题。我当时从 8 个线程加到 16 个线程,就是基于报告里各 worker 的忙碌比例做的判断,而不是凭感觉乱加。加完之后,又特意让业务方在低峰期重跑了几次批处理,确认所有 worker 都能均匀承接,才算彻底收工。

如果你手头也有一个目标端延迟居高不下、大事务又没法从应用侧拆开的 OGG 链路,我建议你把这篇文章里的检查清单先过一遍,再选一个低峰窗口做切换。只要源端集成捕获、目标端版本、主键结构、检查点记录这四件事都准备到位,非集成模式到协同模式的转换是完全可控的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询