1. 把 Switchover 这件事说透:概念与场景
干数据库运维的人,恐怕没有谁能绕开 Data Guard。主备复制、灾备切换、高可用兜底,这套机制几乎占了大半个高可用方案,而 Switchover 又是其中最典型、也最需要认真对待的动作。系统升级、硬件更换、机房搬迁,一个计划好的维护窗口,靠的就是 Switchover 让主库体面地让位给备库,业务几乎无损。很多人一听到 Switchover 就手心冒汗,真实原因往往不是命令不会敲,而是不了解 Data Guard Broker 在背后替你做了多少事。把概念理清楚,命令才有意义。
1.1 Broker 到底帮你省了什么
Data Guard Broker 不是额外安装的独立组件,它内嵌在 Oracle 数据库里。核心是一个叫 DMON 的后台进程,主库、备库都得跑起来。它维护一份配置元数据(就是数据库目录下那类 dr*.dat 文件),里面记录角色、日志传输模式、保护模式、健康状态等信息,所有信息分布在配置里的每台数据库上,Broker 负责让它们保持同步。
没有 Broker 的裸 Data Guard,角色切换得靠人肉运维:两边同时盯 SCN、打日志、执行 ALTER DATABASE COMMIT TO SWITCHOVER,任何一步错位都可能翻车。有了 Broker 之后,最直观的变化是你只需要在一个入口——DGMGRL 命令行里操作,就能看到整个配置的健康状态,并且执行角色切换时,Broker 会在内部自动完成校验、关闭旧主库、挂载新主库、拉起 redo 应用这一整套动作。你在外面看到的,就是一条命令加几句提示。
这就是我为什么强调,搞 Data Guard 一定要尽量用 Broker 来管理配置。它带来的不只是效率,更是切换过程中"先确认再执行"的严谨逻辑。手动 SQL 切换时,两台库之间的角色转换信息是异步的,谁先执行、谁后执行,全靠运维人员自己的判断;而 Broker 会把前置条件逐项检查清楚,目标备库不满足条件时,它会直接拒绝执行,而不是给你一个事后补救的机会。
1.2 Switchover 和 Failover,一字之差天壤之别
这两个词经常被混着说,但在 Data Guard 语境里是完全不同的运维动作。
| 对比维度 | Switchover | Failover |
|---|---|---|
| 触发原因 | 计划内维护,主动发起 | 主库故障,被动救火 |
| 数据损失 | 设计上零损失,禁止丢 redo | 取决于保护模式,MaxPerformance 下可能丢数据 |
| 切换后原主库 | 自动变成备库,保留在配置内 | 通常被移出配置,需要重建或 reinstate |
| 典型场景 | 升级、换硬件、机房迁移 | 主库宕机、恢复遥遥无期 |
| 风险等级 | 可控,可退回 | 高风险,切换后原主库基本作废 |
用一句大白话总结:Switchover 是你安排好时间、主动请备库上位,Failover 是主库已经趴下了,你被迫把备库顶上。运维文档如果连这两个动作都分不清,后面所有预案都是空中楼阁。
Failover 在做决定之前一定要先想清楚保护模式。MaxProtection 下备库的 redo 已经同步,丢数据的概率很小;但如果平时跑的是 MaxPerformance 异步传输,Failover 很可能意味着丢失最后一段日志,业务数据对不上账,那才是数据运维最不愿意面对的局面。而 Switchover 没有这个纠结,它是角色互换,两边的数据都是完整的。
1.3 什么场景必须安排 Switchover
实践里最常见的几类,我一个个列出来:
- 主库服务器或存储要做硬件更换,需要把生产流量暂时挪到备库;
- 给数据库打补丁、做小版本升级,先切到备库,避免主库直接停机;
- 机房搬迁或网络割接,主库所在链路要断,提前把角色换过去;
- 定期做高可用演练,验证切换流程和配套脚本是否真的能用;
- 想给主库留出窗口做性能压测或者批量任务,临时把读写压到备库。
这里有个容易被忽略的点:在 RAC 环境下,Switchover 的对象是整个数据库,不是单个实例。主备都是 RAC 集群时,Broker 一次性处理所有实例,不需要也没有办法逐个实例切换。另外 12c 以上多租户架构里,切换也是容器级动作,整个 CDB 连同所有 PDB 一起换角色,不存在只切某一个 PDB 的玩法。
2. 切换前准备:把"地基"检查清楚再动手
很多 Switchover 事故不是发生在执行那一刻,而是发生在检查环节。你想,主备两边的日志有一点点断层,Broker 执行切换的时候就会卡壳,轻则命令重试,重则角色状态错乱。所以我的原则是:切换前宁可多花五分钟做体检,也不要切换后花五小时救火。
2.1 用 SHOW CONFIGURATION 看整体健康状态
首先登录 DGMGRL,连接到当前主库:
DGMGRL> CONNECT sys/口令@主库服务名 Connected. DGMGRL> SHOW CONFIGURATION;正常情况下的输出大概是这样的结构:
Configuration - dg_config Protection Mode: MaxPerformance Members: orcl - Primary database orclstby - Physical standby database Configuration Status: SUCCESS这里的关键点在最后一行。Configuration Status 必须是 SUCCESS。如果出现 WARNING 或者 ERROR,哪怕只是某一个成员的状态不对,也不建议直接执行 Switchover。先用 SHOW DATABASE 去定位问题,否则就是带着隐患上路。
我还会顺手把两个成员的详细状态都看一遍:
DGMGRL> SHOW DATABASE orcl; DGMGRL> SHOW DATABASE orclstby;输出里重点看Role、LogXptMode、TransportLag、ApplyLag。TransportLag 和 ApplyLag 在 12c 以上版本会直接显示,分别代表日志传输的延迟和应用延迟。理想状态是两个值都无限接近于 0,如果备库 apply 落后一大截,切换命令执行下去会等很久,甚至直接失败。
2.2 日志传输和归档状态核查
没进 Broker 之前,我习惯在主库上跑一段 SQL 看归档目的地状态:
SELECT DEST_ID, STATUS, GAP_STATUS, APPLIED_SCN, ERROR FROM V$ARCHIVE_DEST WHERE DEST_ID <= 3;正常情况下 STATUS 应该是 VALID,GAP_STATUS 是 NO GAP。如果 ERROR 字段里有内容,说明传输链路出了问题,得先去解决再考虑切换。
备库那边也不闲着,查一下接收和应用进度:
SELECT THREAD#, SEQUENCE#, APPLIED, STATUS FROM V$ARCHIVED_LOG WHERE SEQUENCE# > (SELECT MAX(SEQUENCE#) - 10 FROM V$ARCHIVED_LOG);更直接的方式是查 V$ARCHIVE_GAP:
SELECT * FROM V$ARCHIVE_GAP;这个视图只要有返回,就说明备库缺归档,属于铁定不能切换的状态。为什么这么严格?因为 Switchover 要求主备角色互换之后两边数据完全一致,日志断层意味着新主库在切换完成那一刻就已经丢了日志,后面想补都找不到源头。
2.3 三个特别容易翻车的细节
第一,备库的数据文件完整性。很多环境里主库新建了表空间,备库这边由于 StandbyFileManagement 参数配置有问题或者人为建库时漏了文件,导致切换过去之后新主库直接报文件缺失。切换前最好确认备库文件列表和主库一致,重点脚本如下:
SELECT COUNT(*) FROM DBA_DATA_FILES;主备两边各跑一次,数量对不上就必须先处理。
第二,会话和事务状态。Switchover 虽然允许在线执行,但如果有长时间未提交的大事务或者大批量作业正在跑,Broker 会等它们结束,表现就是命令迟迟不返回。更稳妥的做法是把切换排进维护窗口,提前通知业务侧停止写入型任务,必要的话用登录触发器限制新会话。
第三,监听和网络可达性。DGMGRL 能连上不代表两个数据库实例之间所有网络路径都通畅。切换时 Broker 需要在两边来回下发指令,如果主备之间某些端口不通、或 sqlnet.ora 里配置了奇怪的连接超时,会出现命令发出去半天没反应。折腾到最后往往只是防火墙规则没放行,这种坑我踩过不止一次。
3. 实操:DGMGRL 完整 Switchover 过程实录
前面铺垫了这么多,现在进入正题。我用一个双节点物理备库的典型拓扑来演示,主库叫orcl,备库叫orclstby。步骤本身不复杂,难的是每一步都要知道自己在干什么。
3.1 切换前留一份现场快照
我的习惯是在执行之前把两边数据库的当前角色、SCN 和开启模式记录下来,既是给自己留底,也是出问题时的排查起点:
SELECT DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE, CURRENT_SCN FROM V$DATABASE;主备各执行一遍,把结果保存到变更记录里。尤其记住主库的 CURRENT_SCN,后面一旦需要对照日志应用进度,这个数字就是锚点。
如果环境允许,切换前做一次短暂的 RMAN 备份或者确认近期已有可用备份,也是负责任的做法。Switchover 本身不丢数据,但万一切换过程中出现极端异常,有备份在手心里不慌。不需要为了切一次主备就停业务做全备,确认"最近备份可恢复"这条底线就够了。
3.2 执行 Switchover 的标准命令序列
先验证两个数据库的 Switchover 就绪状态:
DGMGRL> VALIDATE DATABASE orcl; DGMGRL> VALIDATE DATABASE orclstby;如果一切正常,输出会明确告诉你Database role: Primary、Status: SUCCESS。如果备库这边报了某个条件不满足,VALUE 列会直接列出原因,照着排除就行。
然后执行切换:
DGMGRL> SWITCHOVER TO orclstby;这是我特别想强调的一步。很多人去查资料会看到不同的写法,比如SWITCHOVER TO orclstby WITH WAIT,这是 12c 之后新增的选项,意思是让 Broker 等待目标备库日志应用完全追上主库之后再做角色翻转。对于追求稳妥的生产变更,我强烈建议用带 WITH WAIT 的版本。11g 上没有这个关键词,那就手动在主库多切几次日志:
ALTER SYSTEM SWITCH LOGFILE;等备库 apply 追赶上来,再执行普通版本的 SWITCHOVER。
命令下去之后,控制台会出现类似下面的过程:
Performing switchover NOW, please wait... Operation requires a shutdown of instance "orcl" on database "orcl" Shutting down instance "orcl"... ... Switchover succeeded, new primary is "orclstby"看到最后一行才能松一口气。注意中间那句Operation requires a shutdown,这不是报错,是 Broker 在把旧主库降级为备库时的正常操作,它会自动把实例关闭、重新挂载,然后启动 managed recovery。整个过程通常在几十秒内完成,取决于实例大小和归档量。
3.3 切换完成后的状态验证与收尾
切换成功之后不要急着退出 DGMGRL,立刻再看一遍配置:
DGMGRL> SHOW CONFIGURATION;此时角色应该已经互换,状态保持 SUCCESS:
Configuration - dg_config Protection Mode: MaxPerformance Members: orclstby - Primary database orcl - Physical standby database Configuration Status: SUCCESS接下来到新主库orclstby上确认它能正常读写:
SELECT DATABASE_ROLE, OPEN_MODE FROM V$DATABASE;期望看到PRIMARY、READ WRITE。再去新备库orcl上看恢复进程是否真正在跑:
SELECT PROCESS, STATUS FROM V$MANAGED_STANDBY;正常应该有MRP0且状态为APPLYING_LOG之类的输出。如果 Broker 没有自动拉起 MRP,可以手动补一下:
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;最后是应用侧验证。用应用账号连一次新主库的服务名,执行一条简单查询确认连接正常;如果架构里有独立备库服务或者 VIP,还要确认这些地址已经跟着角色切换做了漂移。很多切换后的事故不是数据库本身有问题,而是应用还在连旧地址,报错之后误以为切换失败。
4. 切换中的常见故障与恢复路径
Switchover 做得多了,总会遇到翻车的情况。关键是遇到问题的时候别慌,按角色、按日志、按 Broker 状态一层层排查,大多数问题都有明确的恢复路径。我把我自己趟过的坑整理成一套速查思路。
4.1 卡在中间出不来怎么处理
最典型的症状是 SWITCHOVER 命令执行后长时间没有返回,或者控制台报了一个 Broker 通用错误码(比如 ORA-16610 这类)。这时候第一件事不是重跑命令,而是先确认两边的角色到底变成什么样了:
在主库和备库分别执行:
SELECT DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE FROM V$DATABASE;如果是"旧主库还是 PRIMARY,备库还是 STANDBY",说明切换根本没有真正开始,或者前置校验没过。回到 DGMGRL 执行SHOW DATABASE看具体报错,把问题修掉后重新执行 SWITCHOVER 即可。
如果出现旧主库的状态是MOUNTED、PHYSICAL STANDBY,而新主库也已经是 PRIMARY,那其实切换已经完成了,只是 Broker 的元数据可能没来得及刷新。再执行一次 SHOW CONFIGURATION 看看是不是只是显示问题,必要时 DISABLE CONFIGURATION 再 ENABLE CONFIGURATION 让 Broker 重新读取两端状态。
这里有个必须强调的禁忌:不要在这个节骨眼上手动执行ALTER DATABASE COMMIT TO SWITCHOVER去跟 Broker 抢控制权。Broker 管理下的配置,手动 SQL 一旦插进来,两边角色状态很容易变成"各自为政"的脑裂局面,到时候连 Broker 都不敢接管。
4.2 日志 Gap 的定位与补齐
Gap 是 Switchover 前常见的拦路虎。备库的 V$ARCHIVE_GAP 有数据,说明主库产生的某些归档序列号在备库永远等不到。常规处理思路是先把缺的日志从主库找出来。
先在主库查一下缺失的序列号对应文件:
SELECT THREAD#, SEQUENCE#, NAME FROM V$ARCHIVED_LOG WHERE THREAD# = 1 AND SEQUENCE# BETWEEN 1000 AND 1020;找到文件之后想办法送到备库,再在备库注册:
ALTER DATABASE REGISTER LOGFILE '/u01/archive/1_1001_123456.arc';多线程环境里要注意每个 THREAD 都可能缺不同的序列号,得分别补齐。补完再查 V$ARCHIVE_GAP,直到没返回为止,然后继续正常切换流程。如果在 RAC 下归档路径在 ASM 上,手工拷贝会麻烦一些,可以临时用FAL_CLIENT、FAL_SERVER参数配合网络传输,但最终验证标准仍然是 V$ARCHIVE_GAP 为空。
防 Gap 比补 Gap 更重要。平时监控里一定要盯住主库 V$ARCHIVE_DEST 的 ERROR 字段和备库的应用延迟,日志传输中断超过十几分钟没被发现,遇到切换窗口就只能干着急。
4.3 角色状态乱掉之后的止损动作
最糟糕的情况是切换中途主库宕机、备库已经变成 PRIMARY,两边同时以为自己是主库。这种时候不要幻想还能优雅地继续 Switchover,该考虑的是 Failover 和后续的重新纳管。
如果原主库还能起来,并且你想让它重新回到配置里当备库,可以用 Broker 的 REINSTATE 命令,这是 11g 之后比较顺滑的恢复方式:
DGMGRL> REINSTATE DATABASE orcl;Broker 会自动把原来的主库重新拉回物理备库角色并开始追赶日志。如果原主库已经不能用了,那只能重建备库,或者用 RMAN duplicate 出来一个新的成员。
这些恢复操作都要求你对当前配置的保护模式有清醒认识。MaxPerformance 下发生过 Failover,原主库即使重新加入,也可能因为日志缺失导致 reinstate 失败,那就只能走重建路线。止损的核心原则是:先保住新主库正常服务,再回头收拾旧主库,不要反过来。
5. 让 Switchover 真正成为低风险操作
命令本身已经讲完了,但这个话题背后的运维理念更值得展开。Switchover 不是一次性的"绝活",而是一个需要反复练习、不断打磨的标准动作。只有把它变成团队的常规能力,才能在高可用建设里真正抬得起头。
5.1 把切换演练排进运维日历
很多生产环境的 Data Guard 从搭建那天起就没做过切换演练,等真到要切换的时候才手忙脚乱。数据库不是越不动越安全,恰恰相反,长期不演练的主备链路,最容易在关键时刻暴雷。
我建议至少每个季度安排一次完整的 Switchover 演练,演练范围不止是数据库层面,还要带上业务连接、监控告警、值班人员整个链路一起走一遍。演练时故意留着某些检查项不做,观察监控能不能准确告警,观察应用会不会自动重连,这些都比切换本身更有价值。一次成功的演练,能逼出至少两三个平时根本注意不到的隐性配置问题。
5.2 应用层要配合角色切换
数据库角色切换得再漂亮,应用还在连旧主库,那这次切换就是不完整的。生产环境里,应用连接串一定要基于服务名而不是 SID,并且服务名要使用 Data Guard 的角色感知服务。
简单说,一个服务可以设置 SERVICE_ROLES=PRIMARY,这样它只在新主库上对外提供服务;备库上也有自己的只读服务。切换之后,Broker 会按角色自动调整服务状态,应用只要连固定的服务名,不需要跟着改地址。
对于要求更高的环境,客户端可以做 TAF(透明应用故障转移),在连接串里配置 FAILOVER_MODE,这样主库角色变化的瞬间,已经建立的会话能被引导到新主库,减少应用报错窗口。数据库做得好,应用侧配合得也好,才能叫完整的高可用。
5.3 脚本化执行和留痕
手工敲 DGMGRL 适合学习和小规模环境,生产切换务必把流程脚本化。我自己习惯写一个带日志输出的 shell 脚本,把整个流程封装起来:
#!/bin/bash PRIMARY=orcl STANDBY=orclstby dgmgrl sys/$ORACLE_SYS_PASS@$PRIMARY <<EOF spool /tmp/switchover_$(date +%Y%m%d%H%M).log show configuration validate database $PRIMARY validate database $STANDBY switchover to $STANDBY with wait show configuration exit EOF脚本里一定要用 spool 把全部输出落盘,一旦切换出现问题,这个日志就是排查的第一手材料。口令的处理也要注意,不要把明文密码硬编码在脚本里,用环境变量或者外部秘钥文件引用,安全性和可追溯性兼顾。
最后再分享一个我的个人习惯:每次切换完成之后,我会把确认过的当前主备角色、SCN 差值、归档缺失情况、应用重连日志这几样东西整理成一条记录,放进运维档案。下次再做切换时,翻出上一次的记录,对整个环境的健康走势心里就有数了。切换本身虽然只有几分钟,但把它做扎实,依赖的是长期积累的细致,而不是临场发挥的运气。