数据库运维12 min read次阅读

单库跑着不算保险:用 Oracle 19c Data Guard 物理备库扛住主机房塌了

早些年有次生产库所在的主机主板故障,业务全停。我们没有备库,只能从最近的 RMAN 备份恢复——恢复本身花了四十多分钟,而那四十分钟里的交易全没了,因为备份是前一天半夜的。后来补上 Data Guard,再遇到主机维护或者硬件抽风,就是一条命令把角色切到备库,业务几乎无感。这件事让我觉得,单库跑得再稳,也算不上「高可用」,真正的保险是旁边还躺着一份实时跟得上的副本。

RMAN 备份恢复我另写过专文,日常运维里那些 ORA 报错也写过,这篇只讲 Data Guard(后面简称 DG)——怎么从零建一套物理备库,怎么用 broker 管理,以及切换时那些会咬人的细节。

DG 是个什么东西

简单说,DG 是在主库(primary)之外放一个或多个备库(standby),主库产生的 redo 日志实时传到备库,备库再把 redo 应用(apply)到自己的数据文件上,从而保持和主库一致。

备库分两种:物理备库(physical standby)是按块级别复刻,和主库一模一样,靠 Redo Apply(MRP 进程)回放;逻辑备库(logical standby)是把 redo 转成 SQL 再执行,备库可以是不一样的 schema,用来做报表分流之类。绝大多数容灾场景用物理备库就够了,这篇也只讲物理备库。

redo 怎么传、怎么应用,决定了你能丢多少数据:

  • MAXIMUM PROTECTION(最大保护):redo 必须同步写到备库才提交,备库挂了主库也跟着停。零数据丢失,但牺牲可用性,一般只在同机房、网络极稳时才敢用。
  • MAXIMUM AVAILABILITY(最大可用):正常情况下同步写,备库不可用时自动降级成异步,不阻塞主库。是保护性和可用性的折中,生产常用。
  • MAXIMUM PERFORMANCE(最大性能):异步传 redo,主库不等备库,性能最好,极端故障可能丢一点已提交事务。跨机房 DR 基本都选它。

我们线上是同城主备用异步(性能模式),redo 传过去通常也就毫秒到秒级延迟,够用了。

动手前先把前置条件捋清楚

别急着敲命令,下面这些不满足,后面全是坑:

  1. 主备 Oracle 大版本一致,都是 19c(小版本尽量也对齐,避免 apply 阶段出问题)。
  2. 主库必须开归档SELECT log_mode FROM v$database; 得是 ARCHIVELOG,否则 DG 无从谈起。
  3. 强制日志ALTER DATABASE FORCE LOGGING;,否则某些 nologging 操作不会进 redo,备库就对不上了。
  4. db_name 相同,db_unique_name 不同:主备是同一个「数据库家族」,但各自要有唯一名,redo 传输靠 unique_name 寻址。
  5. 两端都要有 Standby Redo Log(SRL):这是最常被漏掉的一项。SRL 用于在备库接收主库 redo,大小和组数要匹配主库 online redo。没它,apply 会卡。
  6. 网络通、监听通、密码文件一致:主备 SYS 密码必须相同,否则 redo 传输连不上(ORA-16191)。

目录结构尽量一致最省心;如果不一致,靠 db_file_name_convert / log_file_name_convert 参数做路径映射。

主库先改参数

-- 强制日志(如果还没开)
ALTER DATABASE FORCE LOGGING;

-- 配置 DG 配置名,两端都要能解析到对方
ALTER SYSTEM SET LOG_ARCHIVE_CONFIG='DG_CONFIG=(orcl_pri,orcl_stb)' SCOPE=BOTH;

-- 2 号归档目的地指向备库,ASYNC 异步,VALID_FOR 指定角色
ALTER SYSTEM SET
  LOG_ARCHIVE_DEST_2='SERVICE=orcl_stb LGWR ASYNC
  VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE)
  DB_UNIQUE_NAME=orcl_stb' SCOPE=BOTH;

ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=ENABLE SCOPE=BOTH;

-- 备库角色时的回连配置(提前设,切换后直接生效)
ALTER SYSTEM SET FAL_SERVER=orcl_stb SCOPE=BOTH;
ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT=AUTO SCOPE=BOTH;

-- 切几次日志,让配置生效、也顺手验证归档能生成
ALTER SYSTEM SWITCH LOGFILE;

tnsnames.ora 里要能解析 orcl_priorcl_stb 两个连接串,监听也要配好。这里有个坑:备库在 mount 状态还没 open,动态注册不上监听,所以备库这边的 listener.ora 必须配静态注册,否则 RMAN 复制时连不上 auxiliary:

# 备库 listener.ora 片段
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = orcl_stb)
      (ORACLE_HOME = /u01/app/oracle/product/19.0.0/dbhome_1)
      (SID_NAME = orcl)))

备库参数文件与密码文件

先把主库密码文件原样拷到备库,保证 SYS 密码一致:

# 在主库所在机器,scp 到备库
scp $ORACLE_HOME/dbs/orapworcl standby:/u01/app/oracle/product/19.0.0/dbhome_1/dbs/orapworcl

从主库导出 pfile,改出备库版:

-- 主库执行
CREATE PFILE='/tmp/initpri.ora' FROM SPFILE;

拷到备库后,至少改这几项:

*.db_unique_name='orcl_stb'
*.control_files='/u01/app/oracle/oradata/orcl/control01.ctl'
*.log_archive_dest_1='LOCATION=/u01/app/oracle/arch VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=orcl_stb'
*.log_archive_dest_2='SERVICE=orcl_pri ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=orcl_pri'
*.fal_server='orcl_pri'
*.fal_client='orcl_stb'
*.standby_file_management='AUTO'
*.db_file_name_convert='/u01/app/oracle/oradata/orcl/','/u01/app/oracle/oradata/orcl/'
*.log_file_name_convert='/u01/app/oracle/oradata/orcl/','/u01/app/oracle/oradata/orcl/'

路径一致的话 convert 可以写自己映射到自己;不一致就填真实的主/备路径对。

用 RMAN 复制建库,不用先备份

19c 最舒服的一点是 DUPLICATE ... FROM ACTIVE DATABASE,直接从运行中的主库复制,不需要提前做备份:

# 备库先用临时 pfile 起到 nomount
sqlplus / as sysdba <<EOF
STARTUP NOMOUNT PFILE='/tmp/initstb.ora';
EOF

# RMAN 同时连主库(target)和备库(auxiliary)
rman TARGET sys/@orcl_pri AUXILIARY sys/@orcl_stb <<EOF
DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE
  DORECOVER
  NOFILENAMECHECK;
EOF

DORECOVER 让复制完顺带追平到当前 SCN,NOFILENAMECHECK 在路径一致时跳过检查。如果路径不同,把 convert 配对,去掉 NOFILENAMECHECK。这一步跑完,备库控制文件、数据文件就都就位了。

复制成功后,启动日志应用(MRP):

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

DISCONNECT FROM SESSION 让它后台跑,不占用当前会话。

建完必须验,别凭感觉

-- 备库角色与状态,应为 PHYSICAL STANDBY / MOUNTED
SELECT name, open_mode, database_role FROM v$database;

-- MRP、RFS 进程是否起来
SELECT process, status, thread#, sequence#, block# FROM v$managed_standby;

-- 看归档有没有被应用
SELECT sequence#, applied FROM v$archived_log
  WHERE applied='YES' ORDER BY sequence# DESC FETCH FIRST 10 ROWS ONLY;

-- 有没有缺口
SELECT * FROM v$archive_gap;

-- 传输延迟和应用延迟
SELECT name, value, time_computed FROM v$dataguard_stats
  WHERE name IN ('transport lag','apply lag');

v$managed_standby 里能看到 MRP0(管理恢复进程)和 RFS(接收 redo)都在跑,才算链路通了。apply lag 一开始可能是几分钟(追初始量),稳定后应回落到秒级。

上 DG Broker,切换变成一条命令

手动管 redo 目的地和角色切换容易出错,Oracle 自带的 DG Broker 能把这些收拢成一个配置,还能自动监控。

-- 主备都开
ALTER SYSTEM SET dg_broker_start=true SCOPE=BOTH;
dgmgrl sys/@orcl_pri <<EOF
CREATE CONFIGURATION dg_config AS
  PRIMARY DATABASE IS orcl_pri
  CONNECT IDENTIFIER IS orcl_pri;
ADD DATABASE orcl_stb AS
  CONNECT IDENTIFIER IS orcl_stb
  MAINTAINED AS PHYSICAL;
ENABLE CONFIGURATION;
EOF

# 看状态
dgmgrl sys/@orcl_pri "SHOW CONFIGURATION"
dgmgrl sys/@orcl_pri "SHOW DATABASE orcl_stb"

broker 会自己管 LOG_ARCHIVE_DEST_2 和角色转换,比手写参数稳。配置里 StatusReport 显示 SUCCESS 才算健康。

切换:计划内和突发

Switchover(计划内,比如主机检修)——零数据丢失,主备角色互换,两边都还能继续用:

dgmgrl sys/@orcl_pri "SWITCHOVER TO orcl_stb"

执行完,原来的备库变主库并 open,原来的主库自动变成备库并 mount + 起 MRP。整个过程业务只断几秒连接。我经常拿它做容灾演练,半年切一次,既验证 DG 健康,也顺便确认应用连新主库没问题。

Failover(主库真挂了,突发)

dgmgrl sys/@orcl_stb "FAILOVER TO orcl_stb"

failover 之后,原主库就「废」了——除非它在挂之前开了闪回(flashback),否则不能简单 reinstate,得重建。所以有两个实践要点:一是给主库开 DB_FLASHBACK_ON 留出 reinstate 的余地;二是 failover 这种事,平时多演练,别等真出事才第一次敲命令。

broker 里 reinstate 旧主库的命令是 REINSTATE DATABASE orcl_pri,前提是闪回开着、且旧主库还能起来。

那些必踩的坑

  • 漏建 SRL:备库 apply 卡住,MRP 一直 WAIT_FOR_LOG,alert 里循环报缺日志。组数和大小对齐主库 online redo,一般多一组。
  • 密码文件不一致:RFS 连不上主库,报 ORA-16191。拷贝主库 orapw 是最稳的,别在备库单独设不同密码。
  • 备库没配静态监听:RMAN duplicate 直接报 auxiliary 没注册,连不上。记住 mount 状态的库不会动态注册。
  • convert 参数写反或漏写:数据文件落到奇怪路径,MRP 报找不到文件。复制前先在 pfile 里核对主备路径对。
  • 没开归档就建 DG:redo 没地方传,架构不成立。先 ARCHIVELOG 再谈 DG。
  • 归档缺口且缺备份v$archive_gap 报缺某段,而那段归档在主库也没了,就只能从 SCN 做增量备份滚备库,麻烦得多。所以 DG 之外,归档的保留和备份照样不能省。
  • 网络抖动:redo 传输挂起,看 SELECT dest_id, status, error FROM v$archive_dest_status; 定位,错误码会告诉你是对端监听没起还是密码不对。

最后一句大实话

DG 解决的是「主机、机房、站点挂了」这类故障,但它不是备份。你在主库上 DROP TABLE 删错表,这个删除会顺着 redo 秒级同步到备库,备库一样没这张表。真正的数据安全是 DG(抗硬件/站点故障)加 RMAN 备份(抗逻辑错误、保留历史)两条腿一起走。另外,别把 switchover 当成一年一次的稀罕事,定期演练才能让它在真出事时靠得住——你不会希望第一次执行 FAILOVER 是在凌晨三点、业务全停、而你还不确定命令敲得对不对的时候。

分享:

相关文章

透明大页不是免费午餐:THP 怎么把数据库延迟搞出毛刺,以及几种靠谱的关法
Linux运维11 min read

透明大页不是免费午餐:THP 怎么把数据库延迟搞出毛刺,以及几种靠谱的关法

有段时间 Redis 每隔几秒就冒一次百毫秒级的延迟尖刺,CPU 闲着、慢日志干净、大 key 也查不出来。最后定位到不是程序也不是网络,是内核在后台帮我们「好心」合并大页。这篇文章从一次真实的毛刺排查讲起,说清 THP 到底是啥、为什么延迟敏感的服务最怕它、怎么确认它在捣乱,以及临时关、systemd 关、grub 关、容器里关各自怎么落地、踩过哪些坑。

Oracle 19c 装完能连只是开始:表空间、内存、AWR 和那些半夜弹出来的 ORA 报错
数据库运维13 min read

Oracle 19c 装完能连只是开始:表空间、内存、AWR 和那些半夜弹出来的 ORA 报错

RMAN 备份那套另写过,这篇只讲上线之后每天真会撞上的事:表空间悄悄涨满、业务喊慢你却不知道慢在哪、ORA-01555 和 ORA-00257 半夜报警、还有一句 ALTER SYSTEM KILL SESSION 救活被锁死的接口。不堆概念,给能直接敲的命令、能看懂的判断,以及我踩过的几个弯。

评论区