ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DB2+NBU异机恢复:归档日志、授权与时间点恢复实操

DB2+NBU异机恢复:归档日志、授权与时间点恢复实操

简介:《DB2异机恢复》是一份面向数据库管理员与备份运维人员的技术文档,围绕借助 NetBackup 实现 DB2 数据库异机恢复展开,适合需要掌握跨主机恢复流程、归档日志配置与备份策略编排的初中级读者参考。资源包共 1 个 doc 文件,大小约 314KB,内容集中梳理 DB2 Agent 配置、用户出口程序 db2uext2 部署、数据库参数调整、db2_backup 脚本及 db2.conf 策略设置等关键环节。已有 340 人学习,说明其在 DB2 备份恢复场景中具有一定参考价值。文档对备份策略、归档日志保存、ARCFUNC 与 RETDIR 等配置项给出了较具体的说明,可帮助读者理解异机恢复前的准备条件、备份脚本参数含义以及策略文件组织方式,便于对照实际环境梳理恢复思路与排查配置遗漏。

1. 异机恢复不是一条 restore:先搞清备份归属和授权边界

DB2 异机恢复真正卡人的地方从来不在 restore 这条命令本身。备份在 A 机上,要在 B 机上把库拉起来,中间横着三件事:源库是不是归档日志模式、日志有没有被用户出口程序接管、NBU 侧允不允许另一台客户端来取这份备份。任何一环没落地,restore 都会停在 restore pending 或者授权失败上,翻来覆去敲命令也没用。

这篇拆的是一套基于 NBU for DB2 的落地流程:从db2_config铺用户出口程序,到userexit、logretain、trackmod三个参数改到位,再到db2.conf里补CLIENT_NAME、master server 上放No.Restrictions,最后用bplist定位时间点、restore加rollforward把库拉回指定时刻。适合手里有 DB2 实例、正在用 NBU 做集中备份、又必须做异地演练或机房搬迁的 DBA 和运维。新手能照着命令走完,熟手能对着参数和报错边界做判断。

2. DB2 侧的归档日志与 userexit:让备份能被另一台机器读懂

异机恢复能不能成,八成取决于源库当初是怎么配的。很多环境里的 DB2 一直是默认的循环日志模式,备份文件本身是完整的,但没有归档日志,恢复端只能回到备份结束那一刻,做不了时间点恢复;更麻烦的是,循环日志模式下日志被覆盖,一旦备份镜像不完整或者需要在异机补齐增量链,就没有任何补救余地。所以这一章先把 DB2 侧的地基打牢,再谈 NBU 那边怎么接。

2.1 循环日志与归档日志:先想清楚要恢复到哪

DB2 的日志模式由LOGRETAIN和USEREXIT两个参数共同决定,默认都是 OFF,也就是循环日志。循环日志模式下,日志写满就覆盖,数据库只保证崩溃一致性,不保证你能把库恢复到任意时间点;归档日志模式把日志保留下来,配合一次全备份,才有「恢复到某个时刻」这个能力。

NBU for DB2 走的是用户出口(user exit)这条路:DB2 需要归档日志时,不自己写本地目录,而是调用供应商提供的db2uext2程序,由这个程序把日志文件交给 NBU,落到备份策略指定的存储单元里。所以USEREXIT打开意味着日志归档动作被外部接管,LOGRETAIN打开意味着日志不再被覆盖而是保留待归档。两个参数要一起开,只开一个的结果是日志堆积在活动日志目录里把磁盘撑满,或者归档动作根本没被触发。

这里有个容易忽略的连带效应:参数改完之后数据库会进入备份待定(backup pending)状态,必须做一次全备份才能继续正常连接。也就是说,切换日志模式这个动作本身就是一次小型停机窗口,不要在生产高峰做。

2.2db2_config到底铺了什么

DB2 Agent 装完之后,第一件事是跑db2_config。这个脚本做的是把 NBU 提供的用户出口程序db2uext2复制到实例的sqllib/adm目录下,同时生成后续要用的备份脚本骨架。DB2 在需要归档日志时,会去sqllib/adm找这个程序,路径不对或者权限不对,它就静默失败,只在db2diag.log里留一行。

执行前确认两件事:用实例用户执行,不是 root;<db2instance>要换成真实的实例家目录。常见写法是:

# 以实例用户身份执行,路径按实际安装位置调整 su - db2inst1 /usr/openv/netbackup/bin/db2_config # 确认用户出口程序已经落位,且属主是实例用户 ls -l $HOME/sqllib/adm/db2uext2

逻辑说明:db2_config依赖 NBU 客户端已经安装完成,否则源路径不存在,脚本会报错退出。参数说明:$HOME在实例用户下就是实例家目录,等价于<db2instance>;如果实例家目录不在默认位置,用绝对路径替换。执行完检查db2uext2的属主和权限,至少保证实例用户可执行,否则 DB2 调用时会报权限拒绝,而这个错误在数据库层面看只是一句归档失败。

2.3 三个参数落到实例上,并用db2 get db cfg复核

参数修改用db2 update db cfg,库名换成你自己的。三个参数分别对应日志归档、日志保留、增量备份跟踪:

# 断开所有应用连接,否则修改不会生效 db2 force applications all # 打开用户出口,日志归档交给 NBU 的 db2uext2 处理 db2 update db cfg for sample using userexit on # 打开日志保留,日志不再被循环覆盖 db2 update db cfg for sample using logretain on # 打开增量备份跟踪,后续才能做差异/累积增量 db2 update db cfg for sample using trackmod yes # 复核,三项都应该是 ON/YES db2 get db cfg for sample | grep -Ei "userexit|logretain|trackmod"

逻辑说明:userexit和logretain是配套的,只开logretain会让日志堆在活动日志路径下等人来搬,只开userexit则因为日志被覆盖而没有东西可归档。参数说明:trackmod打开后,DB2 会维护页级变更信息,增量备份才有依据;代价是少量写放大,这个代价在需要增量备份的场景里是必须付的。

一个硬性前提:这三个参数在还有应用连接的情况下改了也不生效,db2 get db cfg显示新值,但数据库内部状态没切过去。所以要先把连接清干净再改,改完再查一次。如果环境里有连接池或者定时任务反复连进来,清完连接立刻改,别留空档。

2.4 一次全备份是通行证

参数改完之后,数据库处于备份待定状态,此时任何连接都会被拒绝,提示数据库需要备份。这一步绕不过去,必须先做一次全备份。如果只是本地验证,可以备到文件系统;如果是走 NBU,就带 vendor 库:

# 本地文件系统验证,确认库能正常备份 db2 backup database sample to /tmp # 走 NBU 的全备份,指定 vendor IO 库 db2 backup database sample online load /usr/openv/netbackup/bin/nbdb2.so64

逻辑说明:第一条命令只验证数据库本身能不能备份,出问题时排错范围小;第二条才是真正进 NBU 的备份,load后面接的是 vendor IO 库。参数说明:nbdb2.so64是 Linux 64 位环境的库名,32 位是nbdb2.so,AIX 或 HPUX 上是nbdb2.sl和nbdb2.sl64,写错库名的典型表现是 restore 或 backup 立刻报共享库加载失败,而不是等到传输阶段才报错。

全备份做完,用db2 list history backup all for sample能看到一条记录,同时数据库状态恢复正常,应用可以重新连上来。到这一步,DB2 侧的地基才算打完,后面db2.conf和 NBU 策略才有意义。

3.db2.conf与备份脚本拆解:CLIENT_NAME 决定异机能不能取到备份

异机恢复失败,很大一部分不是恢复端的问题,而是db2.conf里少了一行CLIENT_NAME。这个文件的定位是「告诉 NBU 这份备份属于谁、用哪个策略、哪个计划」,源端备份时写错,恢复端就只能看到本机的镜像列表,翻不到别的客户端的东西。这一章把文件结构、脚本变量和策略对应关系拆开讲。

3.1db2.conf的两段结构:数据库对象和归档日志对象

db2.conf分为两段,第一段描述数据库备份,第二段描述归档日志备份。两段的字段名一样,但POLICY指向的策略类型完全不同:数据库段必须是 DB2 类型的策略,归档日志段必须是 Standard 类型(UNIX 客户端)的策略。搞混了就会在归档日志时找不到策略,日志堆在本地。

源端备份用的典型内容如下:

# 数据库备份段 DATABASE DWDB OBJECTTYPE DATABASE POLICY s80a_DB2_everyday_to_tape SCHEDULE Default-Application-Backup ENDOPER # 归档日志段 DATABASE DWDB OBJECTTYPE ARCHIVE POLICY DB2_log SCHEDULE user_backup ARCFUNC SAVE ENDOPER

逻辑说明:OBJECTTYPE DATABASE和OBJECTTYPE ARCHIVE是两段的分界线,NBU 靠这个字段区分是取数据库镜像还是取日志文件。参数说明:POLICY写策略名,必须和 NBU 控制台里建好的策略名逐字符一致;SCHEDULE写计划名,同样要精确匹配;ARCFUNC SAVE表示归档日志直接进 NBU 存储,改成COPY则写到本地目录,此时需要配ARCDIR(备份目的地)和RETDIR(恢复源目录)。

关于文件位置,常见做法是放在/usr/openv/netbackup/db2.conf,并保证实例用户可读。不同环境也可能放在实例用户家目录下由脚本显式指定,关键是备份脚本和恢复端读到的必须是同一份配置内容,否则源端记录和恢复端查询就对不上。

3.2 备份脚本db2_backup逐段拆

Agent 安装后会生成脚本骨架,核心是读环境变量、拼命令行、用实例用户执行。变量由 NBU 在调度时注入,不需要手工传:

#!/bin/sh # 以下变量由 NetBackup(bphdb) 在调度时注入,打印出来便于排错 echo "DB2_CLIENT = $DB2_CLIENT" echo "DB2_SERVER = $DB2_SERVER" echo "DB2_POLICY = $DB2_POLICY" echo "DB2_SCHED = $DB2_SCHED" echo "DB2_FULL = $DB2_FULL" # 1 表示本次是全备份 echo "DB2_CINC = $DB2_CINC" # 1 表示本次是累积增量 echo "DB2_INCR = $DB2_INCR" # 1 表示本次是差异增量 # vendor IO 库,按平台和位数选择,Linux 64 位用 nbdb2.so64 MY_LIB=/usr/openv/netbackup/bin/nbdb2.so64 # 实例名,必须和 db2ilist 输出一致 MY_DB2=DWDB # 执行备份的实例用户 MY_USER=db2inst1 # 根据调度类型决定增量选项 if [ "$DB2_FULL" = "1" ] ; then MY_SCHED="" elif [ "$DB2_CINC" = "1" ] ; then MY_SCHED="INCREMENTAL" elif [ "$DB2_INCR" = "1" ] ; then MY_SCHED="INCREMENTAL DELTA" else MY_SCHED="" fi # 拼出完整备份命令,ONLINE 表示在线备份 CMD_LINE="db2 BACKUP DATABASE $MY_DB2 ONLINE $MY_SCHED LOAD $MY_LIB" echo "Executing: $CMD_LINE" su - $MY_USER -c "$CMD_LINE" # 返回码透传给 NBU,非 0 即作业失败 RETURN_STATUS=$? exit $RETURN_STATUS

逻辑说明:脚本本身不判断业务逻辑,只把调度类型翻译成 DB2 的备份选项。DB2_FULL、DB2_CINC、DB2_INCR三个变量互斥,由 NBU 根据触发的 Schedule 类型置位。参数说明:MY_LIB写错位数会在执行瞬间报共享库加载失败;MY_DB2和实例名不一致会报数据库找不到;MY_USER必须是能连库并且有备份权限的实例用户,用 root 直接跑会因为环境变量缺失而找不到实例。

把多个库写进同一个脚本时,常见做法是复制一行CMD_LINE改成CMD_LINE1再执行一次,但要注意返回码只保留最后一条命令的结果。这点在避坑章节会展开。

3.3 NBU 控制台侧的策略与 Schedule 对应关系

DB2 类型的策略里,Schedule 类型是有专门含义的:全备份对应 Automatic Full Backup,差异增量对应 Automatic Differential Incremental Backup,累积增量对应 Automatic Cumulative Incremental Backup。这三种类型会直接映射成脚本里的DB2_FULL、DB2_INCR、DB2_CINC,所以控制台里选错类型,脚本拼出来的命令就是错的,备份也能「成功」,只是备份的性质变了。

归档日志走的是另一条线:因为USEREXIT打开后日志归档由db2uext2触发,需要一个 Standard 类型策略加一个 User Backup 类型的 Schedule 来接收。这条策略在恢复阶段同样要配进db2.conf,否则rollforward找不到日志,只能恢复到备份结束那一刻。策略建好之后,客户端列表里必须有对应主机名,名字的解析方式要和bpclntcmd -hn的结果一致,短名和全限定名混用是后面「找不到客户端」类报错的主要来源。

4. 异机恢复实操:从No.Restrictions到rollforward的时间点

前面的配置都是为这一步服务。异机恢复和本机恢复的命令行差别很小,差别全在授权和归属:目标机不是备份的原始客户端,NBU 默认不允许它去取别人的镜像,必须显式放开;db2.conf也必须指明源客户端名,否则 NBU 只按本机名去查,查不到就报对象不存在。

4.1 恢复前置:放开异机授权并补上CLIENT_NAME

在 master server 上用 root 创建一个空文件,放开异机恢复限制:

# 在 master server 上执行,文件名和路径固定 touch /usr/openv/netbackup/db/altnames/No.Restrictions ls -l /usr/openv/netbackup/db/altnames/No.Restrictions

逻辑说明:这个目录下的文件名本身就是策略,No.Restrictions表示不限制恢复目标客户端。参数说明:目录必须存在,不存在就逐级建;文件名大小写敏感,写成no.restrictions不生效。更细粒度的做法是在该目录下按客户端名建文件做白名单,演练环境图省事就直接用不限制,但生产上建议收到具体客户端粒度。

恢复端的db2.conf要在原来的基础上补CLIENT_NAME,指向备份的源客户端:

DATABASE BI OBJECTTYPE DATABASE POLICY DB2_Backup SCHEDULE Default-Application-Backup CLIENT_NAME gdccas670 ENDOPER DATABASE BI OBJECTTYPE ARCHIVE POLICY User_Backup SCHEDULE UserBackup CLIENT_NAME gdccas670 ARCFUNC SAVE ENDOPER

逻辑说明:CLIENT_NAME是异机恢复和本机恢复在配置上唯一的结构性差别,两段都要加。参数说明:值必须和源端备份时 NBU 记录的客户端名完全一致,包括大小写;如果源端策略里登记的是全限定名,这里也要写全限定名。策略名和 Schedule 名同样要指向源端的策略,不是恢复端临时建的策略。

配置就位后,先用bplist确认能看到备份镜像:

# -C 指定源客户端,-t 18 表示 DB2 类型的备份,-R 递归列出 bplist -C gdccas670 -t 18 -R /

输出里会出现形如/DB2/BI/node0000/20050226120711/...的路径,路径里的时间戳就是备份作业的精确时间点,后面的taken at要用它。看不到任何输出时,优先查CLIENT_NAME、策略名、master server 上的授权文件这三处,而不是急着敲 restore。

4.2 OFFLINE 备份的异机恢复

离线备份的恢复最简单,因为不涉及日志,恢复到备份结束时刻即可:

su - db2inst1 # 恢复到最新一次离线备份,不滚日志 db2 restore db bi load /usr/openv/netbackup/bin/nbdb2.so64 \ without rolling forward without prompting

逻辑说明:without rolling forward明确告诉 DB2 不要进入前滚阶段,without prompting避免交互确认卡住自动化脚本。参数说明:load后面接 vendor IO 库,平台位数要对;如果目标实例上不存在同名数据库,需要加to指定数据文件落盘路径:

# 目标库不存在时,指定数据文件落地目录 db2 restore db bi load /usr/openv/netbackup/bin/nbdb2.so64 \ to /db2data/db2inst1 \ without rolling forward without prompting

to后面是容器所在目录,不是数据库目录名的别名,写错会报路径不可写或者空间不足。恢复完成后数据库处于前滚待定状态,离线备份可以用db2 rollforward db bi to end of logs and complete收尾,也可以直接db2rfpen on bi重置前滚待定状态,两者选一个,别都做。

4.3 ONLINE 备份的时间点恢复与rollforward

在线备份的恢复分两步:先 restore,再 rollforward。恢复最新备份时:

su - db2inst1 db2 restore db bi load /usr/openv/netbackup/bin/nbdb2.so64 db2 rollforward db bi to end of logs and complete

恢复到指定时间点,则要先从bplist拿到时间戳,再用taken at:

db2 restore db bi load /usr/openv/netbackup/bin/nbdb2.so64 \ taken at 20050226120711 db2 rollforward db bi to 2005-02-26-12:07:11 using local time and complete

逻辑说明:taken at只接受bplist输出的那个 14 位时间戳格式,不要自己拼;rollforward的时间格式是另一套,带横杠和冒号。参数说明:using local time表示按本地时间解释目标时刻,部分版本没有这个选项,此时要手动把系统时间与标准时间的偏差补进去或者减出来。恢复前先用db2 rollforward db bi query status看一眼当前状态,能省掉不少「为什么 rollforward 报已经完成」的困惑。

如果目标机上已经有同名库、又不想覆盖,用into重定向到新库名:

db2 restore db bi load /usr/openv/netbackup/bin/nbdb2.so64 \ taken at 20050226120711 into bi_rst redirect db2 restore db bi continue redirect db2 rollforward db bi_rst to end of logs and complete

逻辑说明:redirect分两阶段,第一阶段只还原控制文件信息,第二阶段在容器路径调整完之后继续。参数说明:into后面是新库名,恢复完成后所有后续命令都要用新库名。这套做法在「同一台机器上做恢复演练、不能停原库」的场景里几乎是唯一选择。

4.4 增量链的恢复顺序

有增量备份时,恢复不是一条命令能解决的。DB2 的恢复顺序是:先恢复全备份,再按时间顺序恢复累积增量,最后恢复差异增量,每一次都要指定对应的时间戳。异机环境里目标实例的恢复历史是空的,指望 DB2 自动找链并不可靠,手动排链更稳。

可以用db2ckrst让 DB2 自己算出这条链:

# 让 DB2 根据时间点推算需要哪些备份,-r database 表示数据库级 db2ckrst -d bi -t 20050226120711 -r database

输出会列出按顺序执行的 restore 命令,照着抄一遍即可。参数说明:-t是目标时间点,格式和bplist输出的时间戳一致;-r指定恢复类型。这个命令在异机恢复里价值很高,因为它是本地推算,不依赖 NBU 的接口,能快速判断「到底缺哪一层增量」。

5. 避坑与排查:五条踩过的记录

这一章都是实际环境里反复出现的现象,按「现象、原因、解决」写,能对上号就直接照做。

5.1 坑一:参数改完数据库连不上,应用全报错

现象:执行完userexit on和logretain on之后,所有应用连接被拒,提示数据库需要备份。

原因:切到归档日志模式后数据库进入备份待定状态,这是设计行为,不是故障。很多人以为参数改坏了,又去回滚参数,来回折腾反而把日志状态搞乱。

解决:老老实实做一次全备份,做完状态自动解除。顺序是db2 force applications all、改参数、立刻全备份、再放应用进来。参数切换要放在维护窗口里做,不要在线改完就等着。

5.2 坑二:异机 restore 报客户端无权重定向

现象:在目标机上执行 restore,报错大意是客户端没有被授权从其他客户端恢复,作业直接失败。

原因:master server 上没有放开异机恢复,或者No.Restrictions文件建在了错误路径、文件名大小写不对、权限不可读。

解决:确认/usr/openv/netbackup/db/altnames/No.Restrictions存在且为空文件,属主和权限允许 NBU 读取。改完不需要重启服务,重新发起恢复即可。生产环境建议改成按客户端建白名单文件,别长期开着不限制。

5.3 坑三:bplist能看到镜像,restore 却说找不到对象

现象:bplist -C 源客户端 -t 18 -R /能列出备份,但 restore 报找不到备份映像或者恢复到了错误的客户端。

原因:db2.conf里数据库段加了CLIENT_NAME,归档日志段漏了;或者策略名、Schedule 名和源端有一个字符的差异;也可能恢复端读的根本不是改过的那份db2.conf。

解决:两段都补CLIENT_NAME,逐字符核对策略名和 Schedule 名,然后确认恢复端读取的配置文件路径。排查时把db2.conf内容打印到恢复会话里,比猜快得多。注意DATABASE后面跟的库名也要和备份时一致。

5.4 坑四:rollforward报缺少日志,恢复到一半停住

现象:restore 成功,rollforward执行到中途报找不到某段日志,数据库停在前滚待定状态。

原因:USEREXIT打开后日志由db2uext2归档,如果归档日志那条策略的 Schedule 名和db2.conf不一致,或者 Standard 策略的客户端列表里没有这台机器,日志就没进 NBU,链断了。另一种情况是日志归档本身失败,日志堆在活动日志目录,db2diag.log里有对应的归档错误。

解决:先查db2diag.log里的归档记录,再核对db2.conf归档段的策略和 Schedule,最后用bplist按 Standard 类型列一下日志镜像是否存在。链断了没有后悔药,只能退到最近一个完整的时间点恢复。所以归档日志的监控要做在前面,别等恢复时才发现。

5.5 坑五:时间点恢复差了几个小时

现象:指定to 2025-02-26-12:07:11恢复,结果数据停在早上或者晚上,偏差固定在几个小时。

原因:using local time没写,或者当前 DB2 版本不支持这个选项,时间被按标准时间解释;也有环境是操作系统时区和数据库记录不一致。

解决:先确认版本是否支持using local time,不支持就手动换算,把系统时间与标准时间的差值补进去。恢复前用db2 rollforward db bi query status和db2 list history对一遍时间基准,别凭感觉填。

6. 用db2ckrst和一致性检查把恢复结果验一遍

恢复命令跑完不等于事情结束。我一般会做三层验证,顺序固定,任何一层不过就不往下走。

第一层验备份链完整性。用db2ckrst推算目标时间点需要的备份序列,和bplist列出的镜像逐条对,缺哪一层当场就能看出来:

# 推算恢复链,输出里会按顺序列出需要的 restore 命令 db2ckrst -d bi -t 20050226120711 -r database # 对照 NBU 侧实际存在的镜像 bplist -C gdccas670 -t 18 -R /DB2/BI

第二层验数据库状态。恢复完成后必须是正常状态,不是前滚待定:

db2 rollforward db bi query status db2 list history backup all for bi db2 connect to bi

query status输出里前滚待定为否、数据库可用,才算收尾干净。如果还是待定,说明rollforward没加and complete,或者被中途中断了。

第三层验数据。这一步最容易被跳过,也最容易在演练汇报时翻车。我的习惯是固定查三样:

检查项命令判断标准
表数量db2 "select count(*) from syscat.tables where tabschema not like 'SYS%'"与源库同时间点对比一致
关键表行数db2 "select count(*) from <业务表>"落在预期区间,不接受「差不多」
索引与约束db2look -d bi -e -o bi_ddl.sql与源库 DDL 对比无缺失

行数检查建议挑两三张写入频繁的表,恢复前后各查一次,差值是判断时间点是否准确的直接证据。DDL 导出后和源库对比,能发现重定向恢复时表空间映射错误导致的索引丢失。

还有一个细节:db2ckbkp -h只能验本地文件系统上的备份镜像,走 vendor 库的镜像在 NBU 存储里,验不了,别在这上面浪费时间,改用bplist加恢复实测。

从那以后我每次做异机恢复演练,都强制先跑一遍db2ckrst把链算出来,再动手敲 restore,宁可多花五分钟排链,也不在恢复中途停下来找日志。希望帮到你。这套配置项、脚本骨架和排查顺序我整理成了一份对照清单,配合文末的资源包一起取用即可。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进