OGG Extract 异常停止排查:最后根因落在 RAC 私网分片重组失败
Oracle GoldenGate 故障处理案例
大家好,我是睿。
今天处理了一个比较有意思的 Oracle GoldenGate 问题:某生产库的 OGG Extract 进程突然异常停止。
刚开始看现象,很容易把方向放在 OGG 自身,比如参数、trail 文件、归档日志、抽取表 DDL、Redo 读取等。但这次一路排下来,最后发现真正的问题并不在 GoldenGate 本身,而是在 RAC 私网通信链路上。
更具体一点:
OGG 元数据线程查询 GV$INSTANCE
=> RAC 节点间发生跨实例 IPC 通信
=> Oracle IPC 包大于当前私网 MTU ,需要 IP 分片和重组
=> 接收端出现大量 IP 分片重组失败
=> 发送端持续重传,接收端持续 Deferred NAK
=> OGG 内部线程长时间无响应
=> Extract 进程 ABEND
这类问题的迷惑性在于:最终挂掉的是 OGG,但根因不一定在 OGG。DBA 排查时如果只盯着 GoldenGate 日志,很容易停在“重启后恢复”这一层,后面真正的风险点就漏掉了。
某客户业务系统反馈:Oracle GoldenGate 抽取进程 EXT02 异常停止。
故障发生时,GoldenGate 错误日志中先出现内部线程状态切换超时,随后 Redo 线程对 Stop 命令无响应,最后进程 ABEND。
脱敏后的关键日志如下:
ERROR OGG-01028 Oracle GoldenGate Capture for Oracle, ext02.prm:
Thread: +++consumer_1 has timed out after waiting for: 600000 seconds,
for other threads to respond to message: SUSPEND,
while changing state from: RUNNING to: SUSPENDED.
WARNING OGG-15429 Oracle GoldenGate Capture for Oracle, ext02.prm:
Thread Redo_Thread_2 not responding to command Stop in timely manner.
ERROR OGG-01668 Oracle GoldenGate Capture for Oracle, ext02.prm:
PROCESS ABENDING.
看到这几条日志,基本可以确认一件事:
这个 Extract 不是正常停止,而是内部线程长时间没有响应,最终异常终止。
先看参数文件,确认这个 Extract 到底怎么抽取、抽哪些对象。
参数大概如下:
extract ext02
setenv (ORACLE_SID=<INSTANCE_NAME>)
USERID <OGG_USER>, PASSWORD ****
checkpointsecs 1
tranlogoptions dblogreader
EXTTRAIL ./dirdat/02
ddl include mapped
ddloptions report
table APP_OWNER.BIZ_SYNC_TABLE;
这里有几个信息比较重要:
1. 这是经典抽取模式。
2. 参数中使用了 TRANLOGOPTIONS DBLOGREADER ,也就是通过数据库接口读取 redo。
3. 本进程只同步一张脱敏后的业务表 APP_OWNER.BIZ_SYNC_TABLE 。
4. 开启了 mapped 范围内的 DDL 捕获。
为什么要先看参数?
因为后面排查日志时,需要知道哪些 DDL、哪些对象、哪些数据库会话可能和这个 Extract 相关。否则看到一点异常就往上套,很容易误判。
故障时间段里,GoldenGate 日志中确实出现过一些 DDL。
比如类似下面的统计信息收集语句:
DDL found, operation [ANALYZE TABLE APP_OWNER.LOG_TABLE_1 COMPUTE STATISTICS]
DDL operation excluded [not included by any filter]
DDL found, operation [ANALYZE TABLE APP_OWNER.LOG_TABLE_2 COMPUTE STATISTICS]
DDL operation excluded [not included by any filter]
这里要看后半句:
DDL operation excluded [not included by any filter]
意思是这些 DDL 不在当前 Extract 的同步过滤范围内,GoldenGate 已经排除了。
所以这一步先排除一个方向:
故障时间段出现过同步清单外 DDL ,但这些 DDL 不是本次 Extract 异常停止的直接原因。
这一点很关键。生产故障分析里,不是同一时间出现的东西都叫根因。要看它有没有进入当前链路。
GoldenGate 日志只能告诉我们 Extract 内部线程卡住了,但卡在数据库哪里,还要回到数据库侧看。
我先查故障时间段内的 ASH,重点看非 Idle 等待:
select inst_id,
qc_instance_id,
qc_session_id,
module,
program,
sql_id,
event,
count(*) cnt
from gv$active_session_history
where sample_time between timestamp '2026-08-17 11:20:00'
and timestamp '2026-08-17 12:40:00'
and inst_id = 2
and wait_class <> 'Idle'
group by inst_id,
qc_instance_id,
qc_session_id,
module,
program,
sql_id,
event
order by cnt desc;
结果里有一类等待非常突出:
INST_ID : 2
QC_INSTANCE_ID : 1
QC_SESSION_ID : 3996
MODULE : OGG-OCI_META_THREAD
PROGRAM : oracle@dbnode2 (PPA7)
EVENT : IPC send completion sync
CNT : 3664
这里有几个关键点:
5. MODULE 是 OGG-OCI_META_THREAD ,说明它和 GoldenGate 元数据线程有关。
6. PROGRAM 是 oracle@dbnode2 (PPA7),说明节点二上出现了并行从进程。
7. 等待事件是 IPC send completion sync ,这是 RAC 节点间 IPC 通信相关等待。
8. QC_INSTANCE_ID = 1,QC_SESSION_ID = 3996,说明这个节点二的 PPA7 进程,是节点一会话 3996 拉起来的。
这里不要只凭 PPA 进程名去猜它属于谁。真正把它和 OGG 关联起来的,是 ASH 里的 MODULE=OGG-OCI_META_THREAD 以及 QC_SESSION_ID 。
继续看这个等待持续了多久:
select min(sample_time) first_time,
max(sample_time) last_time,
count(*) cnt
from gv$active_session_history
where inst_id = 2
and sample_time between timestamp '2026-08-17 11:20:00'
and timestamp '2026-08-17 12:40:00'
and module = 'OGG-OCI_META_THREAD'
and program like '%PPA7%'
and event = 'IPC send completion sync';
结果:
FIRST_TIME : 2026-08-17 11:38:49.271
LAST_TIME : 2026-08-17 12:39:59.420
CNT : 3664
也就是说,Extract 真正异常停止之前,数据库侧已经有一段时间在持续等待 RAC IPC 发送完成。
上一步看到节点二有 PPA 进程等待,接下来要确认节点一的 QC 会话。
根据 ASH 里的 QC_INSTANCE_ID=1、QC_SESSION_ID=3996,查节点一对应会话:
select sample_time,
inst_id,
session_id,
session_serial#,
module,
program,
sql_id,
top_level_sql_id,
event,
wait_class
from gv$active_session_history
where inst_id = 1
and session_id = 3996
and sample_time between timestamp '2026-08-17 11:20:00'
and timestamp '2026-08-17 12:40:00'
order by sample_time;
关键结果如下:
INST_ID : 1
SESSION_ID : 3996
SESSION_SERIAL# : 58011
MODULE : OGG-OCI_META_THREAD
PROGRAM : extract@dbnode1 (TNS V1-V3)
EVENT : PX Deq: Slave Session Stats
这一步把链路串起来了:
节点一 Extract 会话
=> 发起 OGG 元数据查询
=> 节点二 PPA 并行从进程参与查询
=> 节点二向节点一发送 IPC 数据
=> 节点一等待节点二返回状态
所以,此时问题已经不只是 GoldenGate 进程日志里的一个 ABEND,而是 RAC 跨实例通信链路上的等待。
继续看 ASH 里的上层 SQL_ID,现场值是 50h8yp28ravcx。
查询 SQL 文本:
select sql_text
from v$sql
where sql_id = '50h8yp28ravcx';
得到的 SQL 很简单:
SELECT TO_CHAR(startup_time, 'YYYY-MM-DD HH24:MI:SS')
FROM gv$instance
WHERE inst_id = :1;
再看绑定变量:
select inst_id,
sql_id,
name,
value_string,
last_captured
from gv$sql_bind_capture
where sql_id = '50h8yp28ravcx';
绑定变量大概是:
NAME : :1
VALUE : 1
这个 SQL 本身没有复杂业务逻辑,也不是一条大 SQL。
但是它查的是 GV$INSTANCE 。
在 RAC 环境里, GV$ 视图有可能触发跨实例通信。平时这个动作很快,基本没存在感;但如果节点间私网通信异常,一个很简单的元数据查询也可能被卡住。
这就是这次问题里比较容易被忽略的地方:
不是 SQL 复杂导致 OGG 卡住,而是这个简单的 GV$ 查询触发了 RAC 跨实例通信,而通信链路本身出现异常。
节点二 alert 日志里,在故障前出现了 ORA-10388 ,并指向 PPA 进程 trace 文件。
脱敏后的日志如下:
Errors in file /path/to/diag/rdbms/<db>/<inst2>/trace/<inst2>_ppa7_2319774.trc:
ORA-10388: parallel query server interrupt (failure)
这里的 PPA7 进程和 ASH 中看到的 oracle@dbnode2 (PPA7) 能对上。
继续看这个 PPA trace,里面有几类信息很关键:
Local Address : <node2_private_ip>:10645
Remote Address : <node1_private_ip>:38735
Peer : FG: 2949857.KSX.2949857
Pending Sends : Yes
Unacked Sends : Yes
Pldsz : 16376
RETRANS DMP request sent to peer: <node1_private_ip>:38735
同时,同一消息的重传次数在不断增加:
# XMits: 127360
# XMits: 131008
这里可以得到一个很明确的判断:
节点二 PPA7 进程向节点一发送 IPC 数据包后,长时间收不到正常确认。
Oracle IPCLW 层持续进行重传。
Pending Sends 、 Unacked Sends 、 RETRANS 这几个词放在一起看,方向已经很清楚了:发送端不是没有发,而是发出去后一直没有等到对端正常确认。
只看发送端还不够,最好能在接收端找到对应证据。
节点二 PPA trace 里显示对端进程是:
Peer : FG: 2949857.KSX.2949857
Remote Address : <node1_private_ip>:38735
其中 2949857 是节点一侧对端 Oracle 进程号。
在节点一查这个进程:
select inst_id,
addr,
pid,
spid,
program,
tracefile
from gv$process
where spid = '2949857';
结果可以定位到节点一对端 trace:
INST_ID : 1
SPID : 2949857
PROGRAM : oracle@dbnode1 (TNS V1-V3)
TRACEFILE : /path/to/diag/rdbms/<db>/<inst1>/trace/<inst1>_ora_2949857.trc
检查节点一对端 trace,能看到同一类 IPC 消息的异常确认:
ERRCH K PKT(17262591.1433052174)
peer=PPA7.KSXP_ksipc
ospid=2319774
msn=17262591
seq=1433052173
Deferred NAK
UDP://<node2_private_ip>:10645 -> UDP://<node1_private_ip>:38735
Total errch k 138048
Total errch k 140000
PT DMP_REQ at seq 1433052173 from peer <node2_private_ip>:10645
这里发送端和接收端可以互相印证:
节点二 PPA7 端显示 Unacked Sends / RETRANS 。
节点一对端显示 ERRCH K / Deferred NAK 。
问题发生在节点二到节点一的 RAC 私网 IPC 通信确认环节。
这一步很重要。它让问题从 “OGG 好像卡住了”,进一步收敛成了“RAC 私网 IPC 通信确认异常”。
继续看 RAC 私网配置。
检查集群 interconnect:
select inst_id,
name,
ip_address,
is_public,
source
from gv$cluster_interconnects
order by inst_id, name;
脱敏后的结果:
INST_ID NAME IP_ADDRESS IS_PUBLIC
------- ----- ------------------- ---------
1 bond1 <node1_private_ip> NO
2 bond1 <node2_private_ip> NO
两边 RAC 私网都走 bond1 ,当前 MTU 为 1500:
bond1 mtu 1500
slave_nic_1 mtu 1500
slave_nic_2 mtu 1500
而前面 PPA trace 里看到:
Pldsz 16376
这里就有一个关键点:
Oracle IPC 报文载荷约 16KB ,大于当前私网 MTU 1500 。
因此这类通信需要依赖 IP 分片和接收端重组。
正常情况下,分片和重组对上层来说是透明的。但如果网络链路、交换机、驱动、内核参数或瞬时拥塞等因素导致分片丢失、乱序、重组超时,上层看到的就可能是 IPC 包迟迟无法确认。
这也解释了为什么 OGG 日志里看起来是线程不响应,但底层 trace 却是 Unacked Sends 、 RETRANS 、 Deferred NAK 。
接下来检查节点一 OSWatcher 的 netstat 历史数据。
脱敏后的检查思路如下:
for f in dbnode1_netstat_26.08.17.{0900,1000,1100,1200,1300,1400}.dat.gz; do
zcat "$f" | awk '
/^IpReasmFails/ {
if (n==0) first=$2;
last=$2;
n++;
}
END {
printf "%s first=%s last=%s delta=%s samples=%s\n",
FILENAME, first, last, last-first, n;
}'
done
关键结果如下:
09:00 IpReasmFails delta≈0
10:00 IpReasmFails delta≈0
11:00 IpReasmFails delta=15662
12:00 IpReasmFails delta=35664
13:00 IpReasmFails delta=36831
14:00 IpReasmFails delta=36688
故障前 09:00、10:00 基本没有明显分片重组失败;11:00 开始明显增长,和 ASH 中 OGG 元数据线程开始出现 IPC send completion sync 等待的时间窗口基本吻合。
再看更细的指标:
IpReasmReqds delta=1129228
IpReasmOKs delta=134758
IpReasmFails delta=15662
IpFragOKs delta=129171
IpFragFails delta=0
UdpInErrors delta=0
UdpRcvbufErrors delta=0
UdpSndbufErrors delta=0
IpInHdrErrors delta=0
IpInDiscards delta=0
下一小时仍然类似:
IpReasmReqds delta=1296230
IpReasmOKs delta=126839
IpReasmFails delta=35664
IpFragOKs delta=142023
IpFragFails delta=0
UdpInErrors delta=0
UdpRcvbufErrors delta=0
UdpSndbufErrors delta=0
IpInHdrErrors delta=0
IpInDiscards delta=0
这里有个判断点:
不是 UDP 缓冲区错误。
不是 IP 头错误。
不是普通 IP 丢弃。
不是本机发送分片失败。
问题集中体现在接收端 IP 分片重组失败。
也就是说,节点一私网接收方向在故障时间段确实存在大量 IP 分片重组失败。这和前面看到的 RAC IPC 发送端重传、接收端 Deferred NAK 是能对上的。
为了避免结论过早,还同步排查了几个常见方向。
检查故障时间段 Thread 2 的归档日志:
select thread#,
sequence#,
first_time,
next_time,
name,
archived,
status,
deleted
from v$archived_log
where thread# = 2
and sequence# between 11208 and 11214
order by sequence#;
结果显示:
Thread 2 sequence 11208 - 11213 均存在
ARCHIVED = YES
STATUS = A
DELETED = NO
alert 日志中 Thread 2 在 11211、11212、11213 等 sequence 上 redo 切换和归档也正常。
所以本次不是因为归档日志缺失、删除或归档失败导致 Extract 异常。
故障时间段两台主机 CPU、I/O、swap、运行队列都比较正常。
脱敏后的统计大概如下:
节点一:
CPU idle 约 99%
iowait 约 0%
swap in/out 0
blocked 0
节点二:
CPU idle 约 99%
iowait 约 0%
swap in/out 0
blocked 0
所以也不是主机 CPU、内存、I/O、swap 资源瓶颈。
节点一 RAC 私网网卡在故障时间段检查结果大概如下:
rxerr/s = 0
txerr/s = 0
rxdrop/s = 0
txdrop/s = 0
rxfifo/s = 0
txfifo/s = 0
%ifutil = 0.04 - 0.07
这说明网卡层没有直接记录硬错误或明显丢包,链路带宽也没有打满。
但是这里要注意:
网卡层没有 rxdrop ,不代表 IP 层没有分片重组失败。
这次真正有价值的证据,是 OSWatcher netstat 里 IpReasmFails 在故障窗口明显增长。
把关键时间点串起来,链路会更清楚。
T1
节点二 PPA7 进程开始在 ASH 中持续出现 IPC send completion sync 等待。
T2
Extract 日志出现 OGG-01028 ,内部 consumer 线程状态切换超时。
T3
Extract 日志出现 OGG-15429 , Redo_Thread_2 对 Stop 命令无响应。
T4
Extract 日志出现 OGG-01668 ,进程异常终止。
T5
人工重新启动 Extract ,进程恢复运行。
时间线里最重要的是 T1。
OGG 真正 ABEND 是后面的结果,前面数据库侧的 RAC IPC 等待已经持续了一段时间。
先说结论:
本次 OGG Extract 异常停止,根因不是业务表 DDL 、归档缺失、主机资源打满,也不是 GoldenGate 参数本身异常。
根因定位为 RAC 私网通信异常,具体表现为节点一私网接收方向存在大量 IP 分片重组失败。
完整链路如下:
OGG Extract 元数据线程查询 GV$INSTANCE
=> RAC 节点间触发跨实例通信
=> 节点二 PPA7 进程向节点一发送 Oracle IPC 包
=> IPC 报文载荷约 16KB ,大于 MTU 1500 ,需要 IP 分片和重组
=> 节点一接收方向出现大量 IpReasmFails
=> 节点二发送端持续 Unacked Sends / RETRANS
=> 节点一对端持续 ERRCH K / Deferred NAK
=> OGG 元数据线程长时间阻塞
=> Extract 内部线程状态切换超时
=> Redo_Thread_2 无响应
=> Extract ABEND
这次比较有代表性的一点是:触发等待的 SQL 本身非常简单,只是查了 GV$INSTANCE 。
但在 RAC 环境里,简单 SQL 只要涉及 GV$ 跨实例访问,就可能触发节点间通信。如果底层私网链路存在分片重组异常,上层就可能表现成 GoldenGate 元数据线程卡住。
这类问题如果后续还要继续排查,我建议重点放在 RAC 私网接收方向,而不是只盯着 OGG 进程本身。
建议检查:
9. 节点一 RAC 私网 bond1 当前 active slave 对应交换机端口的 discard、drop、pause frame、CRC、microburst 记录。
10. 节点二到节点一私网链路中间交换设备,是否存在瞬时拥塞、分片丢弃或重组超时。
11. 两节点网卡驱动、固件版本以及系统日志,是否存在网卡 reset、link flap、driver warning。
12. 当前 MTU 为 1500,而 Oracle IPC 大包通信依赖 IP 分片,建议评估 RAC 私网全链路启用 jumbo frame 的可行性。
13. 如果再次发生,建议两节点同时在私网网卡上抓包,确认是否存在分片丢失、分片乱序或重组超时。
另外可以同步关注内核 IP 分片重组相关参数:
sysctl net.ipv4.ipfrag_high_thresh
sysctl net.ipv4.ipfrag_low_thresh
sysctl net.ipv4.ipfrag_time
sysctl net.ipv4.ipfrag_max_dist
这些参数不要看到就直接改。生产环境里,内核参数、MTU、交换机配置、网卡 offload、RAC 私网要求都要一起评估,尤其是 jumbo frame,必须保证全链路一致,否则问题可能更隐蔽。
—— 睿 | Oracle性能优化老司机
专注硬核干货,欢迎一起卷技术!

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047128/viewspace-3179976/ ,如需转载,请注明出处,否则将追究法律责任。