暂无图片
暂无图片
4
暂无图片
暂无图片
暂无图片

一次 Oracle RMAN 备份失败排查实录:从 ORA-07445 到 NetBackup 的 SBT 库

背景

  • 现象:Windows 上一套 Oracle 10.2.0.5(实例 orcl)每天凌晨 4 点的 RMAN 备份发起即失败,NetBackup 报 bphdb exit status 6
  • 表面错误RMAN-03009 + ORA-03113(allocate channel 时通道中断),对应数据库侧 ORA-07445 服务端进程崩溃。
  • 根因:RMAN 分配 SBT 通道、初始化 NetBackup 介质管理接口(sbtinit)时,加载第三方 SBT 库失败(Windows 异常码 0xc06d007e),导致服务端进程崩溃。
  • 决定性佐证:用 DISK 通道(不加载 SBT 库)本地手动备份成功;用 SBT 通道(加载 SBT 库)则必然崩溃。唯一变量就是那个 SBT 库。
  • 与数据库参数(SGA/PGA)无关。 这个崩溃自 2019 年起每天复现,备份很可能已长期失效——先确认有没有可用备份,再修链路。

起因

某天接到反馈:“5 月 16 号凌晨 4 点的备份发起失败了。”

这是一套 Windows 上的 Oracle 10.2.0.5(实例名 orcl),备份策略是每天凌晨 4 点定时执行。运维的第一反应往往是先看数据库本身有没有问题——比如内存参数:

SQL> SHOW PARAMETER pga_aggregate_target;
NAME                    TYPE         VALUE
----------------------- ------------ -------
pga_aggregate_target    big integer  500M

SQL> SHOW PARAMETER sga_target;
NAME                    TYPE         VALUE
----------------------- ------------ -------
sga_target              big integer  1528M

先说结论:这两个参数和本次故障毫无关系。这恰恰是排查中最容易踩的第一个坑——一看到"备份失败"就先怀疑数据库内部,方向就跑偏了。下面把完整的排查路径还原一遍。

第一步:从 alert 日志锁定时间点

备份相关问题,第一手证据永远是数据库的 alert 日志。直接定位到 5 月 16 日凌晨 4 点附近:

Sat May 16 04:00:19  2026
Errors in file d:\oracle\product\10.2.0\admin\orcl\udump\orcl_ora_4260.trc:
ORA-07445: exception encountered: core dump [UNKNOWN] [unable_to_trans_pc] [PC:0x7C80BF93] [] [] []

Sat May 16 04:10:56  2026
Errors in file d:\oracle\product\10.2.0\admin\orcl\udump\orcl_ora_4496.trc:
ORA-07445: exception encountered: core dump [UNKNOWN] [unable_to_trans_pc] [PC:0x7C80BF93] [] [] []

ORA-07445 是 Oracle 服务端进程收到操作系统级异常后强制 core dump,也就是服务端进程崩溃了。备份一启动进程就挂,作业自然发起失败。

两个细节值得停下来想一想:

第一,4:00 崩一次、4:10 又崩一次,间隔 10 分钟——这通常意味着备份软件在第一次失败后自动重试了一次,结果第二次同样崩溃。

第二,也更关键——这真的是 5 月 16 号才冒出来的"新问题"吗?

第二步:确认这是不是偶发事件

把整个 alert 日志里的 ORA-07445 全部捞出来统计:

$ grep -c "ORA-07445" alert_orcl.log
81

81 次,而且全部是同一个错误、同一个崩溃地址 0x7C80BF93。再翻到最早一次:

Tue Apr 23 04:00:09  2019
Errors in file ...orcl_ora_1704.trc:
ORA-07445: exception encountered: core dump [UNKNOWN] [unable_to_trans_pc] [PC:0x7C80BF93] [] [] []

这个崩溃从 2019 年 4 月就开始了,几乎每天凌晨 4 点准时上演,一直延续至今。

这个发现直接改变了问题的性质:

  • 它不是"某天突然坏了",而是一个长期存在、从未被真正解决的老问题;
  • 同一个固定崩溃地址,强烈暗示这是静态的、可稳定复现的问题(如某个库加载失败),而非与数据变化相关的偶发错误;
  • 最值得警惕的是——如果每天的备份都在崩,那这套库很可能已经很久没有一份可用的有效备份了

第三步:搞清楚备份到底是怎么跑的

alert 日志只能告诉我们"进程崩了",但不知道是谁触发的。这套环境用的是 Veritas NetBackup,在它的 Job Details 里能看到完整的失败链条(Job ID 1030292,状态 Done (Failed)):

Recovery Manager: Release 10.2.0.5.0 - Production
connected to target database: ORCL (DBID=********)
using target database control file instead of recovery catalog
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03009: failure of allocate command on ch00 channel at 05/16/2026 04:10:57
ORA-03113: end-of-file on communication channel
...
bphdb exit status = 6: the backup failed to back up the requested files

备份的真实形态清楚了:凌晨 4 点跑的是 RMAN 经 NetBackup 调度执行的物理备份(走 SBT_TAPE 通道),不是 expdp 之类的逻辑导出。

错误栈很有信息量:

  • connected to target database: ORCL —— RMAN 已成功连上库;
  • RMAN-03009: failure of allocate command on ch00 channel —— 失败发生在**分配通道(allocate channel)**这一步;
  • ORA-03113: end-of-file on communication channel —— 通信通道意外中断。

ORA-03113 本质上是 RMAN 这个客户端发现"我连着的那个服务端进程突然没了"。和 alert 日志里同一时刻(04:10:56)的 ORA-07445 一对照,因果就接上了:不是 RMAN 自己出错,而是它一去分配通道,对端的 Oracle 服务端进程就崩溃了,连接被打断。

时间线还原:

4:00:19  备份发起(attempt 1)→ 服务端进程 ORA-07445 崩溃 → 失败
4:10:42  NetBackup 自动重试(attempt 2)
4:10:54  RMAN 连上 ORCL
4:10:57  RMAN allocate channel ch00 → 服务端进程再次崩溃
         → ORA-03113 → RMAN-03009
4:11:01  Job 失败退出,exit status = 6

第四步:trace 文件揭开根因

崩溃发生在"分配通道",但分配通道为什么会让进程崩?答案在 udump 目录下的 trace 文件里。打开它,三条证据浮出水面。

证据一:异常码不是普通的内存越界

Process Id: 0x00000648  Thread Id : 0x00000b84
Excp. Code: 0xc06d007e  Excp. Type:    UNKNOWN    Flags: 0x00000000

注意异常码 0xc06d007e。这里要给同行多说一句,因为这个码本身就是破案的钥匙:

  • 我们最熟悉的 0xc0000005ACCESS_VIOLATION,野指针/越界访问,属于"代码在乱读内存";
  • 0xc06d007e 属于 0xc06d00xx 这一族,是 Microsoft C++ / 模块加载相关的异常,语义指向加载某个模块(DLL)时失败(找不到 DLL 或其依赖项)。

也就是说,进程不是在"乱读内存",而是卡在"加载某个 DLL"这件事上崩的。问题性质从一开始就被这个码框定在了"库加载",而不是数据库内部逻辑。

证据二:崩溃就卡在初始化 SBT 库那一步

client info: rman channel=ch00
program: rman.exe
waiting for 'Backup: sbtinit' wait_time=0, seconds since wait started=0
...
longest_non_idle_wait: 'Backup: sbtinit'

'Backup: sbtinit' 这个等待事件是关键。sbtinit 是 RMAN 初始化介质管理层(Media Management Layer, MML)接口的入口函数——即 RMAN 去调用 NetBackup 提供的那个 SBT(System Backup to Tape)接口库。trace 显示进程恰好就崩在这个等待里

会话生命周期采样更是把它钉死:

sample interval: 1 sec
  [1 sample,  10:39:48]  waited for 'Backup: sbtinit'  (still in wait)
  [1 sample,  10:39:47]  idle wait at each sample
  [session created at: 10:39:47]

会话 10:39:47 创建,10:39:48 进入 sbtinit,随即崩溃。整个生命周期 1 秒——连上来、试图初始化 SBT、当场挂掉。

证据三:调用栈指向第三方 DLL

----- Call Stack Trace -----
calling              call     entry
location             type     point
-------------------- -------- --------------------
7C80BF93                      00000000
5F6BCB23             CALL???  00000000
5F6BC6EC             CALLrel  5F6BC9EC

栈顶 7C80BF93 落在 Windows kernel32.dll 区间(负责 LoadLibrary 等模块加载);下一层 5F6BCB23 这个 5F... 地址段,属于运行时注入进来的第三方 DLL(NetBackup 的 SBT 接口库),而非 Oracle 自身代码段。

三条证据拼起来,根因指向:

RMAN 分配 SBT 通道、初始化 NetBackup 介质管理接口(sbtinit)时,加载第三方 SBT 库失败(异常码 0xc06d007e),触发 Oracle 服务端进程崩溃(ORA-07445),进而通道分配失败、备份整体失败。

第五步:一个对照实验,把根因彻底坐实

到这里逻辑已经很完整,但还差一脚——怎么排除"是不是 Oracle 自己有毛病、或者环境哪里不对"?答案是做一次干净的对照实验:换一种不经过 SBT 库的方式跑 RMAN,看还崩不崩。

于是在数据库服务器上,用操作系统用户手动执行了一次 RMAN 备份到本地磁盘(DISK 通道)

RMAN> RUN {
  ALLOCATE CHANNEL c1 DEVICE TYPE DISK;
  BACKUP DATABASE FORMAT 'D:\rman_backup\%U';
}

结果:完全成功,没有任何崩溃。

这一下,变量就收敛干净了。把两次执行摆在一起看:

执行方式 是否加载 NetBackup SBT 库 结果
调度的 SBT 通道(走 NetBackup) sbtinit 加载 SBT DLL) 进程 ORA-07445 崩溃
本地 DISK 通道(备份到磁盘) (直接写磁盘,不碰 SBT 库) 成功

两次都是同一套 Oracle、同一个库、同样的 RMAN 二进制,唯一的区别就是要不要去加载那个 NetBackup 的 SBT 库

  • 加载它 → 崩;
  • 不加载它 → 一切正常。

这恰好和前面 trace 的结论严丝合缝:问题不在 Oracle,不在数据库参数,也不在数据库整体环境,而在 Oracle 与 NetBackup 之间那座"桥"——NetBackup 装在 Oracle 服务器上的 SBT 接口库本身坏了或加载不起来。 RMAN 一去调它,进程就崩。

这也完美解释了为什么从 2019 年起每天同一时间、同一个固定地址崩溃:这是一个静态的库加载问题,与备份数据内容无关,只要那座"桥"不修,它就每天准时复现。

一个容易混淆的点要提醒同行:DISK 备份成功,并不能给 SBT 库"洗清嫌疑"——恰恰相反,正因为 DISK 通道压根不加载 SBT 库,它的成功才反过来把矛头更精准地指向了 SBT 库。如果当初本地是用 SBT 通道跑成功的,那才需要怀疑是不是调度账户/环境差异;而这里是 DISK 成功、SBT 失败,对照变量只剩库加载这一项,结论无可回避。

完整因果链

NetBackup 调度触发 RMAN 备份
        ↓
RMAN 连接 target database(成功)
        ↓
allocate channel ch00(SBT_TAPE 类型)
        ↓
调用 sbtinit 初始化介质管理层
        ↓
LoadLibrary 加载 NetBackup SBT 接口 DLL
        ↓
异常 0xc06d007e:DLL 加载失败
        ↓
服务端进程 ORA-07445 崩溃 core dump
        ↓
通道断开 → ORA-03113 → RMAN-03009
        ↓
NetBackup Job exit status 6,备份失败

(对照:换 DISK 通道,跳过 sbtinit / 不加载 SBT 库 → 备份成功)

解决方向

根因锁定后,修复的重点全部落在 NetBackup 客户端侧(Oracle Agent / SBT 库),而不是 Oracle 数据库参数。

1. 检查并修复 NetBackup 的 Oracle SBT 库

确认 NetBackup Client / Oracle Agent 安装完整、版本与这套 Oracle 兼容;确认 SBT 接口库(Windows 上通常是 orasbt.dll 一类,位于 C:\Program Files\Veritas\NetBackup\bin\)存在、未被杀软或权限拦截。0xc06d007e 很多时候是它所依赖的某个运行时 DLL(如 VC++ 运行时)缺失导致的,要顺着依赖链一起查(可用 Dependency Walker / dumpbin /dependents 检查 SBT DLL 的依赖是否齐全)。

2. 用最小命令复现,把加载错误暴露出来

在数据库服务器上手动分配一个 SBT 通道,绕开调度逻辑直接看报错:

RMAN> ALLOCATE CHANNEL ch00 DEVICE TYPE SBT
      PARMS 'SBT_LIBRARY=C:\Program Files\Veritas\NetBackup\bin\orasbt.dll';

如果立刻 ORA-03113,就再次坐实 SBT 库加载失败,报错信息往往会提示缺哪个库。

3. 翻 NetBackup 客户端日志

C:\Program Files\Veritas\NetBackup\Logs\ 下的 dbclientbphdbuser_ops 等目录会记录更具体的加载失败原因。注意这些 log 目录有时需手动创建并调高日志级别才会输出。

4. 必要时联系 Veritas 支持

"Windows + Oracle 10.2 + NetBackup + 0xc06d007e SBT 加载崩溃"是一个相对典型的组合性问题,厂商侧通常有对应的兼容性补丁或处理方案。

最重要的事:先保证有可用备份

排查根因固然重要,但有一件事优先级更高——这个崩溃已存在数年,意味着这套库可能长期没有一份能用的物理备份。 务必尽快确认:

RMAN> LIST BACKUP SUMMARY;

或查询 v$rman_backup_job_details / v$rman_status,看最近一次成功的完整备份究竟是哪天。

而本次排查刚好附赠了一个现成的兜底方案:既然 DISK 通道备份是通的,那就先把每天的备份临时切到 RMAN 备份到本地磁盘(再辅以脚本把备份集拷到其他存储/网络位置),抢先拿到可用的物理备份,再从容去修 NetBackup 那条 SBT 链路。否则在修好之前,数据库等于一直在"裸奔"。

复盘与经验

别被"备份失败"带偏到数据库本身。 第一反应去查 SGA/PGA 参数是最常见的弯路。备份失败相当大比例落在"备份软件 ↔ 数据库"的对接层,而非数据库内部。

异常码会说话。 ORA-07445 本身信息有限,但跟在它后面的 Windows 异常码(这里是 0xc06d007e)往往直接点出问题性质——是内存越界(0xc0000005)还是 DLL 加载失败(0xc06d00xx),方向南辕北辙。养成看异常码的习惯能少走很多弯路。

统计错误的"历史分布"比只看最新一条更值钱。 只盯着 5 月 16 号那一条,很容易当成偶发问题草草重启了事。把 81 次崩溃的时间线拉出来,才看清这是长期顽疾,也才意识到备份可能早已失效——这个判断比修好崩溃本身更要紧。

用对照实验把变量收敛到一个。 这次排查最有力的一步,是 DISK 通道与 SBT 通道的对照:同一套库、同样的 RMAN,唯一差别是加不加载 SBT 库,一个成功一个崩。当你能把问题压缩到"只剩一个变量在变",结论就从"推测"变成了"证明"。

多数据源交叉验证,证据链才闭合。 alert 日志(进程崩了)+ NetBackup Job 报告(崩在 allocate channel)+ trace(崩在 sbtinit 加载 DLL)+ 对照实验(DISK 通),四者在时间和环节上严丝合缝,结论才真正站得住。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论