Data Guard Broker 主备切换:switchover 检查、排错与演练实践 1. 先弄清楚 switchover 和手动命令切换的本质区别1.1 一条命令背后 Broker 干了什么很多 DBA 是从手工维护 Data Guard 的时期过来的习惯在主库上执行ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY、在备库上执行ALTER DATABASE COMMIT TO SWITCHOVER TO STANDBY这一套动作。这套流程本身不算难真正难的是在两个实例之间协调状态主库能不能安全地把 redo 交接给备库、备库的归档日志是不是完整、有没有 gap、备库的临时文件和 standby redo log 数量够不够、两边参数是否需要联动调整。任何一环没确认到位切到一半卡住是常事甚至会出现两边都认为自己是主库的脑裂场景。Data Guard Broker 的核心价值就是把这一长串人工检查和状态判断统一收口。Broker 启动后会在主备库上都维护一份 broker 配置文件通过dgmgrl命令行入口统一管理。你执行show configuration看到的不是数据库自己单方面报告的 status而是 Broker 综合了主备两边的实例状态、日志传输状态、日志应用状态、网络连通性之后得出的结论。Broker 还能自动补齐一部分主备切换需要互动的步骤不需要你再去对比两边视图里十几个字段。1.2 什么时候该用 Broker什么时候别勉强以我的实践看只要你的环境是标准的 Oracle Data Guard 物理备库并且数量在 3 个以内Broker 几乎总是比手工流程更稳妥。原因很简单它把切换动作变成了一件事先声明好的事务性操作每一步都有明确的失败回滚语义。手工切换则要求操作者脑子里装着一张完整的检查清单少一项都可能埋雷。但有些场景我不建议用 Broker。比如备库是用非常规方式搭出来的standby redo log 缺失、参数文件里残留了奇怪的log_archive_dest_n配置或者主备的 db_unique_name 混乱这类环境 Broker 初始化时就会因为配置校验不过而拒绝工作你还不如先把手工链路理清楚。还有一种情况数据库版本太老。10gR2 之前的 Broker 功能不完整管理逻辑也比较粗我在生产环境只推荐 11gR2 之后使用。版本太老时 Broker 对 standby 实例的参数管理存在较多限制切换过程中因为参数覆盖导致启动失败的案例不少。2. switchover 前这三项检查能拦住 80% 的切换事故2.1 实例状态和日志应用状态怎么看在真正执行 switchover 前先登录dgmgrl看状态是最基本的一步。命令很简单dgmgrl sys/口令主库地址 DGMGRL show configuration输出里最关键的是每个库的Database Status字段。正常应该是SUCCESS如果出现ERROR或者WARNING先解决掉再谈切换。很多人只看这个状态就够了但我会再多做一步分别查看每个库的日志传输和应用状态DGMGRL show database PRIMARY_DB statusReport; DGMGRL show database STANDBY_DB statusReport;这里要说一个容易误解的点状态报告里Log Transport Services显示正常只代表主库把日志发出去的动作没报错并不代表备库已经把这些日志应用到数据文件里。你要同时看Log Apply Services的状态。如果只是传输正常、应用滞后很多切过去之后新主库的数据并不完整切换动作本身可能还是会被 Broker 阻止但提前发现和应用滞后是完全不同的事。2.2 日志缺口检查GAP 不一定显示在 alert 里很多人以为备库 alert 日志没有报 gap 就等于没有 gap这个认知在 Broker 环境里尤其危险。Broker 的日志缺口判断依赖的是它自己记录的 redo 日志序列号和数据库内部视图的判定之间有时存在延迟特别是备库刚刚重启过、或者主库发生过归档日志删除时。我的习惯是在切换前直接查备库的数据字典SELECT sequence#, applied, first_time, next_time FROM v$archived_log WHERE applied NO ORDER BY sequence#;以及检查主备日志序列的差值-- 主库执行 SELECT max(sequence#) FROM v$log_history; -- 备库执行 SELECT max(sequence#), max(applied_seq#) FROM v$standby_log;对比这两个数字就能快速确认差了多少个归档日志。这一步做到位switchover 卡在半路的概率会直线下降。即使是 Broker 正常管理的环境我也会在做切换之前手动执行一次ALTER SYSTEM ARCHIVE LOG CURRENT让主库强制切换日志确保最后一批 redo 已经归档并传递到备库。2.3 网络连通性和 FastStartFailover 的干扰还有一个非常诡异的问题Broker 在 switchover 过程中会反复通过内部链路探测两个库如果网络存在间歇性丢包命令可能执行到一半报 ORA-16467 之类的时间超时错误。所以切换前用操作系统层的 ping 检查丢包率只是基础我更建议做一次端口级的连通性测试比如用tnsping之间交叉测试主备库的监听服务名是否互通。如果配置了 Fast-Start FailoverFSFO还要额外检查 observer 进程的状态。我遇到过一种情况observer 挂掉了但 Broker 配置文件里还残留着 fast-start failover 的属性导致 switchover 命令被 Broker 以fast-start failover 配置不完整为由拒绝。处理方式可以是临时禁用 FSFODGMGRL disable faststart failover;等 switchover 完成后再重新启用。这一点如果你不看 Broker 日志光看数据库 alert很容易被带偏方向。3. 标准 switchover 流程与命令输出解读3.1 标准命令序列一条命令完成角色互换在完成上面所有检查后switchover 本身的命令非常短。我先说一个常见误区很多人以为要先在备库执行什么命令让备库追日志其实 Broker 管理下不需要它会自己处理。完整流程就是DGMGRL connect sys/口令主库地址 DGMGRL show configuration DGMGRL validate database PRIMARY_DB DGMGRL validate database STANDBY_DB DGMGRL switchover to STANDBY_DB DGMGRL show configurationvalidate database这一步很多人会跳过其实它非常值得执行因为它会一次性检查备库是否能切换到主库角色包括参数文件、临时文件、redo 日志配置、MTTR 等输出里会写清楚潜在风险。我不会把它省掉因为这条命令本身不产生任何副作用只是读状态。switchover to执行后Broker 会做这些事顺序很重要锁定当前主库停止日志传输服务把最后一批 redo 归档并发送到目标备库让目标备库应用完所有已接收的日志把目标备库转为 primary 角色把原主库转为 physical standby 角色恢复两个库之间的日志传输和应用这个流程是否完整执行成功直接决定了你后续要不要花几个小时收拾残局。3.2 切换中的状态流转和内部动作当你在 dgmgrl 里看到Switchover succeeded字样时只代表 Broker 认为角色切换成功了。但我不会就此收工。主备库的会话状态是需要确认的特别是原来的主库自动变成 standby 之后它需要重新打开 standby 日志应用SELECT database_role, open_mode FROM v$database;正常情况新主库应该是PRIMARYREAD WRITE新备库应该是PHYSICAL STANDBYREAD ONLY WITH APPLY取决于版本和设置。如果你看到新备库是MOUNTED且没有任何应用进程说明 Broker 切换过程中日志应用没有自动拉起需要手工执行ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;这里有个细节很多人不知道切换完成后新备库的监听服务名并不会自动更新。如果你使用了 service_name 而不是 db_unique_name 去连接数据库应用层可能还连着旧的主库地址需要配合数据库服务和监听配置一起调整这部分不在 Broker 的管理范围内。3.3 切换完成后的验证清单我会固定跑一遍这个核对单show configuration是否显示所有库为SUCCESS新主库v$database.database_role是否为PRIMARY新备库是否处于日志应用状态新主库上执行ALTER SYSTEM SWITCH LOGFILE然后确认新备库 instantiation 能在一分钟内收到新日志检查新备库的 MRP0 或相关进程是否在运行检查应用连接的是否已经切换到新主库最后一步经常被忽略。很多团队做切换演练数据库层面角色已经换过来了但应用层配置没改于是业务仍然连接到旧主库上而旧主库此时已经是备库角色无法接收写入最终表现为全部应用报错。建议在切换前就把应用连接串的主备地址准备好切换后第一时间修改。4. 一次切不过去的实战排错从 ORA-16501 到 ORA-164674.1 报错出现时的第一反应和错误定位我在某次按计划做 switchover 时执行switchover to STANDBY_DB命令返回ORA-16501: The Data Guard broker operation failed ORA-16467: switchover timed out waiting for a redo transport destination to process the redo received from the primary看到这种错误我的第一反应不是去翻数据库 alert而是先看 Broker 的日志。理解 Broker 的日志结构很重要它不在alert_log里而是写在$ORACLE_HOME/rdbms/log/drc*.log这类文件中。日志里会告诉你 Broker 认为哪个环节超时了。在这条错误里ORA-16467 直译过来是主库把 redo 发给了某个目标但目标没有在限定时间内处理完成。所以有两个方向可以查网络传输问题和目标端日志应用问题。我先检查的是备用库的 MRP 进程是否还活着。结果发现新备库确实没有 MRP0 进程说明切换过程中 Broker 在等待备库应用日志时备库的应用状态已经卡住。此时再去看备库的 alert 日志看到大量归档日志应用等待重做的信息并且有一个归档日志文件缺失这才意识到真正的问题不是切换超时而是备库早就有一个日志缺口没被发现Broker 的等待只是把这个缺口暴露了出来。4.2 日志序列缺口比想象中更隐蔽回到前面说的Broker 状态显示SUCCESS时并不代表日志没有缺口。这是因为 Broker 的日志缺口检测机制基于归档日志心跳如果主库恰好有一段时间没有新日志产生gap 评估就一直处于静止状态看不到实际缺了多少。我那次环境的缺口其实是这样产生的主库某次归档日志传输因为监听瞬间中断失败随后log_archive_dest_n设置了reopen参数传输会自动重试并很快恢复。正常情况下这条日志会被补传但因为备库的归档日志删除策略设置了删除 7 天前的归档而那条缺失的日志恰好已经被删掉了于是 gap 固化成了一个无法自动修复的缺口。查询缺口的 SQL 是SELECT thread#, low_sequence#, high_sequence# FROM v$archive_gap;有这条记录但备库 MRP 端却没有对应报错的情况原因是 MRP 在等待期间不会主动重复刷错误信息到 alert只在初始化阶段报过一次。这种静默 gap最坑人。4.3 修正后重试切换与回切验证定位到缺口后我做的事很直接从主库找到缺少的归档日志对应的 redo 段通过手工 copy 归档文件到备库目录再注册到控制文件ALTER DATABASE REGISTER LOGFILE /归档目录/归档名.arc;注册完成后再启动 MRPALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;这次我等 MRP 完全把缺口追平确认v$archive_gap查询结果为空并且v$archived_log中applied字段没有NO的记录后重新回到dgmgrl执行switchover to。这次一次通过。回切验证这一步也很重要不是切一次成功就算结束。我在首次切到新主库后观察了半小时然后再执行一次 switchover 切回原主库。两次切换都成功后才认为这套环境的切换链路真正可靠。因为第一次切换可能恰好避开了某些未暴露的问题而回切会强制走一遍完全对称的流程能发现单向隐藏问题。5. 把 switchover 变成定期演练的制度5.1 回切时最容易翻车的细节回切操作看起来就是把 switchover 命令的源和目标反过来但有几个细节会不一样。首先是新主库的角色已经变化网络服务名、连接池、监听配置都要跟着换回来。很多团队切过去之后发现应用还连在旧地址上仓促调整了一部分配置回切时又忘改另一部分结果两边各有一半应用指向错误。其次是临时表空间和审计文件。切换后新主库会用原来的备库临时表空间如果没建好切换本身可能成功但业务一执行排序就报 ORA-00959。所以回切前我会确认两边临时表空间文件都在ONLINE状态SELECT tablespace_name, status FROM dba_tablespaces WHERE tablespace_name LIKE TEMP%;最后是角色相关的触发器。有些环境会在主库上建AFTER STARTUP ON DATABASE触发器来限制或记录访问角色切换后触发器会被禁用回切时也要确认这些触发器是否自动恢复。Broker 对这类对象的管理比较有限不会替你处理。5.2 定期演练的价值和脚本化思路我在这套环境里养成的习惯是每个月做一次无业务窗口的 switchover 演练并且把它脚本化。脚本的核心逻辑不复杂就是按顺序执行以下动作调用dgmgrl的show configuration检查所有状态自动抓取主备库 gap 相关视图执行validate database执行 switchover 并记录耗时切换后执行验证 SQL自动比对主备角色确认无误后回切脚本化之后演练才有意义。因为手工切换即使成功你也很难保证每次都踩到同一套检查步骤。脚本能保证至少没有遗漏关键检查项。不过有一点提醒脚本里不要直接写数据库口令。dgmgrl支持通过外部口令文件或者操作系统的安全存储方式调用生产环境千万别把明文口令写进脚本文件否则权限管理失控会带来更多问题。5.3 给团队后人的几条提醒最后分享几条实打实的经验都是踩过坑之后总结的切换窗口不要太短。即使是一套小库Broker 执行切换本身可能只要几十秒但切换后的应用验证、日志追平确认、回切预留都需要时间。建议至少留半小时观察期不要切完就跑。备库的 redo 应用延迟要看趋势不要看瞬时值。有时候备库因为系统负载短暂落后几秒不代表它追不上但如果持续落后且越来越远就要考虑是不是备库 IO 能力不够而不是盲目进行切换。归档日志保留策略要结合 gap 修复的容错能力设置。如果归档只保留 3 天一旦主库断网超过 3 天gap 就只能通过重建备库解决那时候 Broker 再强大也帮不上忙。切换失败后不要立刻重试。先搞清楚失败原因是网络、日志缺口还是配置问题盲目重试可能把两边状态搞得更乱。我见过因为切换失败后立即重试导致备库出现两张 redo 应用线程互相抢占的情况。Data Guard Broker 的 switchover 是一个典型的关键动作配置得当可以非常可靠但前提是你真的理解它背后的检查逻辑和失败边界。把检查做在前面把演练做成习惯切换这件事才会从高危操作变成常规操作。