做实时数据同步这几年提到 CDCChange Data Capture变更数据捕获几乎是绕不开的。前段时间在一台 CentOS 7 服务器上给 Oracle 11g 把 CDC 配置整体跑通过程远没有想象中顺滑——从归档模式到补充日志从发布者权限到订阅视图每一步都可能遇到问题。这篇就把整套配置过程、背后原理以及实际踩过的坑完整复盘一遍给正在做数据同步、实时数仓或者被 Oracle CDC 搞到头大的读者一个参照。先说清楚这篇内容能解决什么问题你在 CentOS 7 上装好了 Oracle 11g现在想把某张业务表的 Insert / Update / Delete 变更实时捕获出来同步到下游消息队列、数仓、另一套库都行。我会从 CDC 的两种实现路线讲起然后给出一个可复现的 Oracle 原生同步 CDC 配置全流程再补充归档日志、补充日志、第三方工具衔接这些容易出问题的点最后整理一份问题排查速查表。1. 先搞清楚Oracle 11g 的 CDC 到底有哪几种路线1.1 CDC 的本质与 Oracle 11g 的历史包袱CDC 本质上是把数据库里发生的行级变更插入、更新、删除转化成可消费的数据流。最简单的理解就是给数据库装了一个“录像机”——业务侧每个操作都被记下来下游程序按需回放。问题是 Oracle 11g 这个版本比较特殊。它有两条原生的 CDC 路线很多刚接触的人分不清同步 CDCSynchronous CDC基于发布/订阅机制底层近似于一套内部实现的触发器逻辑。业务在源表上写入后变化会立即被记录到对应的变化表里。异步 CDCAsynchronous CDC基于 Redo Log 日志解析又分成 HotLog 和 AutoLog 两种模式对源库的性能影响更小但延迟会受日志切换和归档节奏影响。除了这两条原生路线生产环境中更常见的做法是直接上 Oracle GoldenGate或者用 Debezium、Flink CDC 这类第三方框架来读取 Oracle 11g 的日志。这也是我觉得标题里“CDC 配置”很容易让人迷茫的原因——你得先明确自己要的是哪种 CDC再去动手配置。1.2 同步 CDC 与异步 CDC 的选择差异我整理了一张对比表方便你对照场景选型对比维度同步 CDC异步 CDC底层技术发布/订阅机制内部实现Redo Log 日志解析依赖 LogMiner实时性事务内即时捕获受日志切换/归档周期影响有延迟对源库影响较大写入路径开销明显较小主要消耗日志解析资源是否必须开启归档模式不强制AutoLog 模式必须是否建议开启补充日志不强制强烈建议最好开主键或全列级适用场景小数据量、学习测试、低并发场景生产环境、大数据量、跨平台同步我自己在项目里的体会是同步 CDC 做概念验证和学习特别直观你插入一条数据马上去变化表查就能看到结果整个链路透明、好排查。但真要上生产除非数据量很小、并发很低否则不建议——它对源库的额外开销并不小而且支持的字段类型有限制细节后面说。1.3 原生 CDC 与第三方工具到底选哪边原生 CDC 的好处是数据库自带不需要额外装组件权限和对象关系都在数据库内部管理适合做“库到库”的小规模同步。缺点也比较明显同步 CDC 对性能影响大异步 CDC 的配置和维护比想象中麻烦Oracle 11g 里相关的文档和资料还相对陈旧。第三方工具路线则是近年的主流。比如用 Flink CDC 或 Debezium 连接 Oracle 11g把日志解析转换成消息流。这条路线的优势是生态成熟、下游对接方便但你得先满足一系列前置条件数据库开归档、开补充日志、创建专用的逻辑挖掘账号而且不同版本的连接器对 Oracle 的支持方式有差异。所以无论走哪条路环境准备工作几乎都是一模一样的。这篇博文会以 Oracle 原生同步 CDC 的完整配置为主线因为它能帮助你理解 CDC 运行的整个机理在这个基础上再去接第三方工具你会清楚知道每一步是为了什么。2. 环境准备CentOS 7 与 Oracle 11g 的基础检查与前置条件2.1 数据库版本和基础环境确认我这次操作的平台是 CentOS 7 的 64 位系统Oracle 数据库版本是 11.2.0.4。建议你在动手前先把环境和版本信息确认清楚尤其是 11.2.0.4 这个版本补丁比较完备很多 CDC 相关的异常在早期小版本上更容易触发。cat /etc/redhat-releaseSELECT * FROM v$version;登录数据库时使用操作系统认证最方便sqlplus / as sysdba如果你刚装完 Oracle 11g还要确认环境变量是否正常。标准的环境变量配置是这样export ORACLE_HOME/u01/app/oracle/product/11.2.0/dbhome_1 export ORACLE_SIDorcl export PATH$ORACLE_HOME/bin:$PATHCentOS 7 上如果用的是 11g 自带的监听建议确认监听状态避免后面 PL/SQL 调用包时报连接相关错误lsnrctl status注意CentOS 7 上安装 Oracle 11g 本身就有一些前置依赖坑比如缺少 libaio、binutils 等系统包64 位系统还需要注意 32 位兼容库。虽然安装过程不是这篇的重点但如果你是在一台干净的系统上从零开始建议先确认这些基础依赖齐全否则后续 CDC 配置中出现的异常可能根本不是 CDC 本身的问题而是安装不完整引起的连锁反应。2.2 开启归档模式最容易被忽略的前置条件异步 CDC 和第三方日志解析工具都有一个硬性前提数据库必须处于归档模式ARCHIVELOG。同步 CDC 虽然不强制但我们做 CDC 配置通常会顺带把这一项准备好因为你很可能后续还是需要异步方式或第三方工具。检查当前模式SELECT log_mode FROM v$database;如果结果是NOARCHIVELOG需要切换到归档模式。这个操作要求数据库先启动到 mount 状态SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN;建议再把归档路径设置一下避免默认路径不可用ALTER SYSTEM SET log_archive_dest_1LOCATION/u01/app/oracle/arch SCOPEBOTH;验证是否成功SELECT log_mode, archiver FROM v$database;看到ARCHIVELOG和STARTED就是正常了。这里分享一个踩过的坑很多人在配 CDC 时先跳过了归档模式直接走到创建发布者、订阅者那一步结果日志解析时永远拿不到数据排查了半天才发现日志模式不对。所以在配置 CDC 之前请务必先把归档和补充日志这两个“地基”打好。2.3 补充日志日志解析是否能拿到完整字段的关键补充日志Supplemental Logging是给日志挖掘用的。Redo Log 里默认不会记录所有字段的旧值尤其是非主键列。如果不开补充日志即使你把日志挖出来了也可能拿不到完整的更新前后字段值这对 CDC 来说是致命的。补充日志有三个级别最小补充日志Minimum只记录必要信息能满足基本挖掘但字段值不完整。主键级补充日志记录主键列信息足够识别变更行。全列级补充日志记录所有列的信息日志量最大但能拿到最完整的变更前后值。我建议在 CDC 场景下至少开到主键级如果下游需要完整旧数据直接开全列级ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS; ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;验证方法SELECT SUPPLEMENTAL_LOG_DATA_MIN, SUPPLEMENTAL_LOG_DATA_PK, SUPPLEMENTAL_LOG_DATA_ALL FROM v$database;三个字段都是YES说明配置生效。经验之谈全列级补充日志的代价是日志量明显增加生产环境日志量可能翻几倍。如果你的同步场景只关注新增数据主键级就够了如果要做完整的更新值比对、数据订正那必须开全列级。这个决策一定要让业务方和 DBA 一起评估不要为了图省事直接全列开满。3. Oracle 原生同步 CDC 配置全流程3.1 核心角色发布者、订阅者、源表、变化表Oracle 原生同步 CDC 的架构里有四个核心概念搞清楚它们之间的关系后面所有配置操作都有章可循源表Source Table你要捕获变更的业务表。发布者Publisher负责构建变化表通常是有源表所在 schema 操作权限的用户。变化表Change Table不算业务数据表而是 CDC 框架自动维护的存储变更记录的地方。订阅者Subscriber订阅变化表并读取数据的人通常对应下游程序。这个模型可以类比成“报纸出版”发布者负责编辑出版把源表的变更写进变化表订阅者负责订报读报从变化表里拉取变更。订报的人不能直接改源表只能看发布者提供的内容。3.2 准备一张带主键的源表Oracle 11g 同步 CDC 对源表有个硬性要求必须有主键。官方文档明确不支持 LOB、LONG、LONG RAW 等大对象类型的列出现在变化表里。所以实操中我会先建一张简单业务表来验证链路CREATE TABLE cdc_pub.orders ( ORDER_ID NUMBER(10) PRIMARY KEY, CUSTOMER_ID NUMBER(10), ORDER_STATUS VARCHAR2(20), ORDER_AMOUNT NUMBER(10,2) );插入几条初始数据备用INSERT INTO cdc_pub.orders VALUES (1001, 501, NEW, 299.00); INSERT INTO cdc_pub.orders VALUES (1002, 502, PAID, 158.50); COMMIT;这里也顺便说一下如果你后续要接第三方 CDC 工具源表同样建议有主键否则很多连接器对无主键表的支持是不稳定甚至不支持的。3.3 创建发布者并授权发布者用户需要一定的权限来构建和操作变化表。从 Oracle 官方文档来看发布者通常需要 CREATE TABLE、CREATE VIEW、CREATE TABLESPACE 以及 DBA 角色等。测试环境我建议直接授予 DBA 简化操作生产环境则按最小权限原则细化。创建发布者用户CREATE USER cdc_pub IDENTIFIED BY Pub123456 DEFAULT TABLESPACE users QUOTA UNLIMITED ON users; GRANT CREATE SESSION TO cdc_pub; GRANT CREATE TABLE TO cdc_pub; GRANT CREATE VIEW TO cdc_pub; GRANT CREATE TABLESPACE TO cdc_pub; GRANT DBA TO cdc_pub;为什么需要 CREATE TABLESPACE这有点反直觉但 Oracle 文档中同步 CDC 的发布者确实有这个要求。我们不用纠结这个设计按文档给权限就行。如果之后构建变化表时报权限不足第一反应就是检查这个用户少了哪些角色。3.4 创建订阅者并授权订阅者只需要读取变化表生成视图权限相对简单CREATE USER cdc_sub IDENTIFIED BY Sub123456 DEFAULT TABLESPACE users QUOTA UNLIMITED ON users; GRANT CREATE SESSION TO cdc_sub; GRANT CREATE TABLE TO cdc_sub; GRANT CREATE VIEW TO cdc_sub;关键一步是授予 CDC 订阅包的执行权限GRANT EXECUTE ON DBMS_CDC_SUBSCRIBE TO cdc_sub;这一步极易漏掉漏掉之后最常见的报错是ORA-00942或ORA-04068这类问题排查起来非常浪费时间。3.5 构建变化表BUILD_CHANGE_TABLE用发布者账号登录或者用 sys 授权后在发布者 schema 下操作执行DBMS_CDC_PUBLISH.BUILD_CHANGE_TABLE建变化表BEGIN DBMS_CDC_PUBLISH.BUILD_CHANGE_TABLE ( source_table cdc_pub.orders, change_table_name cdc_pub.orders_ct, column_type_list ORDER_ID NUMBER(10), CUSTOMER_ID NUMBER(10), ORDER_STATUS VARCHAR2(20), ORDER_AMOUNT NUMBER(10,2) ); END; /这里有几个容易出错的地方change_table_name的命名没有强制规定但建议统一加_CT后缀方便后面用数据字典检索。column_type_list必须和源表字段类型完全匹配写错类型会在后续订阅或查询时报类型转换错误。源表包含大对象字段时column_type_list里不能包含这些字段。我遇到过有同事把 VARCHAR2 写成 VARCHAR构建虽然成功但后面视图查询时行为异常的情况所以类型定义要尽量严谨。验证变化表是否构建成功SELECT CHANGE_TABLE_NAME, SOURCE_TABLE_NAME, STATUS FROM DBA_CHANGE_TABLES WHERE SOURCE_TABLE_NAME ORDERS;正常情况状态是ACTIVE。3.6 订阅变化表并激活接下来用订阅者账号登录执行订阅操作BEGIN DBMS_CDC_SUBSCRIBE.SUBSCRIBE ( change_table_name cdc_pub.orders_ct, subscription_name sub_orders, subscriber cdc_sub ); END; /订阅创建后需要激活才能真正开始捕获数据BEGIN DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION ( subscription_name sub_orders, subscriber cdc_sub ); END; /验证订阅状态SELECT SUBSCRIPTION_NAME, STATUS, CHANGE_TABLE_NAME FROM ALL_SUBSCRIPTIONS WHERE SUBSCRIPTION_NAME SUB_ORDERS;状态应该是ACTIVE。如果还停留在INACTIVE说明激活步骤没有生效可能是权限或包调用顺序问题。3.7 生成变化视图并读取变更数据激活订阅后需要通过DBMS_CDC_SUBSCRIBE.GET_VIEW_COLUMNS在订阅者 schema 下生成一个变化视图。这个视图把变化表里那些结构复杂、列名带特殊前缀的列包装成便于查询的普通视图BEGIN DBMS_CDC_SUBSCRIBE.GET_VIEW_COLUMNS ( subscription_name sub_orders, subscriber cdc_sub, view_name v_orders ); END; /视图生成后直接查询就能看到捕获到的变更记录。Oracle 同步 CDC 的变化视图里有一组以$$$开头的特殊列用来标识变更的元信息。最常用的是$$$OPERATION它记录操作类型I 表示插入U 表示更新D 表示删除。例如SELECT $$$OPERATION, ORDER_ID, CUSTOMER_ID, ORDER_STATUS, ORDER_AMOUNT FROM v_orders;因为列名带特殊字符SQL 里记得用双引号包住。实操中如果你不想每次写带引号的列名可以先SELECT * FROM v_orders看一眼结构再用别名包装一层。我们来演示完整链路在源表里做一次更新然后去变化视图里验证UPDATE cdc_pub.orders SET ORDER_STATUS SHIPPED WHERE ORDER_ID 1001; COMMIT;再查询变化视图SELECT $$$OPERATION, ORDER_ID, CUSTOMER_ID, ORDER_STATUS FROM v_orders;你会看到一条U开头的记录。这证明 CDC 链路已经通起来了。每次读完了可以考虑用DBMS_CDC_SUBSCRIBE.PURGE_WINDOW清理已消费的数据窗口避免变化表无限增长。这个操作和队列消费里的 ack 机制很像如果你不消费数据就会一直累积在窗口里。3.8 同步 CDC 的限制说明同步 CDC 虽然链路直观但限制不少。除了前面说的必须有主键、不支持大对象字段之外它还会增加源库写入路径的开销不适合高并发生产场景。很多团队在生产环境把这个方案跑起来后发现刚开始表小没感觉数据量上来之后源库的写入性能下滑明显才回过头来改用日志解析类的方案。所以我自己的建议是学习理解用同步 CDC生产大规模同步优先评估异步或第三方工具。4. 异步 CDC 与第三方工具衔接的配置要点4.1 理解异步 CDC 的 HotLog 和 AutoLog 模式Oracle 11g 异步 CDC 本质上是基于 LogMiner 技术通过解析 Redo Log 来捕获变更。它有两种模式HotLog 模式在线日志一产生变化就实时解析延迟低但要求日志在内存中或未被覆盖。AutoLog 模式自动扫描归档日志延迟相对高一些但更可靠能应对日志切换。如果要用异步 CDC数据库必须满足的两个条件就是前面反复强调的开启归档模式 开启补充日志。很多生产环境从同步切到异步最开始没数据就是因为归档模式没开。异步 CDC 对参数也有一些要求。建议把 streams_pool_size 设置合理值因为 LogMiner 的解析过程会使用这部分内存。具体大小取决于你的日志量我见过比较常规的设置是 200M 到 500M 之间。Oracle 11g 如果自动管理 SGA你只要确认 shared pool 默认自动调优不用太纠结具体数字但如果你手工管理 SGA这个参数一定要单独预留。异步模式的原生配置过程相对繁琐如果你是第一次接触我的建议是先把同步 CDC 跑通理解变更表和订阅模型之后再切到异步模式排查能力会强很多。4.2 为第三方日志解析工具准备通用环境现在生产上更常见的是用 Flink CDC 或 Debezium 连接 Oracle 11g。这类工具普遍遵循“读日志”的思路所以准备工作和异步 CDC 几乎一致-- 1. 开启归档模式上面已操作 -- 2. 开启补充日志上面已操作然后创建一个专用的日志挖掘账号。Oracle 11g 下做日志挖掘该给什么权限不同工具要求略有差异但最省事也最常见的是组合授权法CREATE USER cdc_lgmr IDENTIFIED BY Lg123456; GRANT CREATE SESSION TO cdc_lgmr; GRANT SELECT ON V_$DATABASE TO cdc_lgmr; GRANT SELECT ON V_$LOGMNR_CONTENTS TO cdc_lgmr; GRANT SELECT ON V_$LOGMNR_LOGS TO cdc_lgmr; GRANT SELECT ON V_$LOGMNR_PARAMETERS TO cdc_lgmr; GRANT SELECT ANY TRANSACTION TO cdc_lgmr; GRANT SELECT_CATALOG_ROLE TO cdc_lgmr;如果你用的工具是基于 XStream 方式不同连接器版本支持情况有差异具体以官方文档为准还需要额外的捕获和应用配置。这里我不展开因为不同版本变化比较大照着博文抄容易误导。有一点必须强调第三方工具读取 Oracle 11g 的官方支持和维护情况并不一致。有些新版连接器可能已经放弃 LogMiner 方式只支持 XStream有些则对 11g 的兼容性依赖具体补丁。选型时一定要先去对应工具官网确认支持矩阵不要听别人说能连就直接上生产。4.3 典型的生产方案选型建议综合我自己接触过的场景给你一个比较务实的建议只是做少量表的实时同步下游也是 Oracle且接受数据里的字段类型限制原生同步 CDC 最直接。数据库量大、表多、下游是 MQ 或者大数据平台优先考虑 GoldenGate 这类专业工具或者 Debezium / Flink CDC 这类常用开源方案。只是想快速验证 CDC 原理原生同步 CDC 是最佳选择因为它能把发布订阅机制完整地暴露给你学习成本最低。5. 常见问题与排查技巧实录5.1 ORA-00942: table or view does not exist这个报错最常见的原因是权限缺失。订阅者账号可能没有访问变化表所在 schema 的权限或者还没生成变化视图。排查顺序SELECT CHANGE_TABLE_NAME, SOURCE_TABLE_NAME FROM ALL_CHANGE_TABLES WHERE SOURCE_TABLE_NAME ORDERS;确认变化表存在后检查订阅者权限GRANT SELECT ON cdc_pub.orders_ct TO cdc_sub;如果是视图没生成重新执行GET_VIEW_COLUMNS并确认调用成功。5.2 ORA-01031: insufficient privileges这个报错也是权限问题但范围更广。发布者缺少 DBA 角色或必要系统权限、订阅者缺少EXECUTE ON DBMS_CDC_SUBSCRIBE都会触发。处理方式简单粗暴但有效测试环境把 DBA 角色授权到位生产环境通过ROLE逐步排查。具体操作GRANT DBA TO cdc_pub; GRANT EXECUTE ON DBMS_CDC_SUBSCRIBE TO cdc_sub;5.3 订阅状态一直是 INACTIVE做了ACTIVATE_SUBSCRIPTION之后状态还是没有变化这种情况通常是因为激活动作没有提交或者在调用前订阅已存在但参数名写错。重新激活之前建议先把旧的订阅删除再重建BEGIN DBMS_CDC_SUBSCRIBE.DROP_SUBSCRIPTION ( subscription_name sub_orders, subscriber cdc_sub ); END; /然后重新走一遍SUBSCRIBE → ACTIVATE_SUBSCRIPTION → GET_VIEW_COLUMNS的流程。5.4 查询变化视图始终没有数据按正常流程查视图没数据先别急着认为 CDC 没生效。有几个常见原因源表在构建变化表之后才有 DML变化表不会回溯过去的数据。订阅没有处于ACTIVE状态。可能你创建变化表后在没有订阅的情况下源表已经产生了一些变更这些变更发生在订阅激活之前不会出现在当前窗口里。查询时筛选条件有误比如把$$$OPERATION字段拼错或没有加双引号。另外同步 CDC 查询窗口有“窗口推进”机制。如果你做了一轮查询后再去看新数据可能需要先扩展窗口BEGIN DBMS_CDC_SUBSCRIBE.EXTEND_WINDOW ( subscription_name sub_orders, subscriber cdc_sub ); END; /这个机制和流式系统的 offset 提交很像不推进窗口新的变更就不会出现在查询结果里。5.5 异步 / 第三方日志解析一直无数据这种情况优先检查三个点按概率从高到低排列数据库是否处于归档模式。补充日志是否已开启特别是主键级和全列级。日志挖掘账号是否具备访问动态性能视图的权限。排查 SQL 一并给你SELECT log_mode FROM v$database; SELECT SUPPLEMENTAL_LOG_DATA_PK, SUPPLEMENTAL_LOG_DATA_ALL FROM v$database;5.6 问题速查表现象可能原因解决方法ORA-00942 表或视图不存在订阅者无权限 / 视图未生成检查 DBA_CHANGE_TABLES补授权重跑 GET_VIEW_COLUMNSORA-01031 权限不足缺 DBA 或 EXECUTE 权限按最小权限补角色测试环境可直接 GRANT DBA订阅状态 INACTIVE未提交激活 / 参数错误DROP 后重建订阅再 ACTIVATE查询无数据窗口未扩展 / 订阅未激活 / 源头时间点不对EXTEND_WINDOW 后重查确认订阅状态日志解析持续无数据归档未开 / 补充日志未开 / 日志账号权限不足检查 v$database补授权LOB 字段参与变化表构建失败同步 CDC 不支持大对象字段从 column_type_list 中剔除相关字段6. 配置之外的几点实操心得配置 Oracle 11g 的 CDC 看起来是一堆命令的组合但真正决定成败的往往是顺序和心态。我在实际操作中踩过几次坑之后总结出三步原则先确认数据库日志模式再确认补充日志最后才碰发布订阅。第一步和第二步其实只花几分钟却能把后面可能出现的 90% 的诡异问题提前消灭。很多人上来就急着建用户、建变化表等查询无数据时才回头补日志配置那个排查过程会痛苦得多。关于第三方工具我也想多说一句如果团队里已经有成熟的数据同步平台直接用平台支持的连接器不要自己在 CentOS 7 上手工维护一套 CDC 脚本。手工方案在数据量小的时候挺灵活但到了几十张表、持续同步的场景监控、断点续传、字段变更这些都会变成很重的工作量。最后分享一个小技巧如果你打算长期跟踪 CDC 相关的对象建议在命名上形成自己的规范。变化表统一用_CT结尾订阅名统一用SUB_开头视图统一用V_开头。这样每次排查时数据字典里查起来一目了然不用反复回忆哪个对象是干什么的。我就因为命名随意吃过亏后来统一规范之后排查效率明显高了不少。