1. 环境规划与搭建前准备
1.1 先理清楚你要的ADG到底解决什么问题
在动手敲命令之前,我建议大家先把需求捋清楚。ADG(Active Data Guard)说白了就是主库产生的redo日志实时传到备库,备库不仅处于恢复状态,还能以只读方式打开对外提供查询服务。很多人会把ADG和普通的DG混为一谈,其实区别就在于那个"Active",备库是否以只读打开、是否能在应用日志的同时跑查询,这决定了你能不能用它分担读流量。
我从接触Oracle 9i的Standby Database一路用到19c,最大的感受是:ADG在19c这个版本已经非常成熟,搭建方式和运维体验都比以前舒服太多。尤其是19c对Data Guard Broker的完善程度,几乎能做到全图形化操作和自动故障转移。但前提是,你得把底子打好,比如存储路径、网络配置、初始化参数这些基础工作做得够不够规整。
适合用ADG的场景主要是这几类:核心业务库的容灾备份、读写分离减轻主库压力、报表查询跑在备库避免影响生产、以及作为跨机房或者跨城市的数据同步底座。如果你的需求只是做逻辑备份,用expdp或者rman就够了,没必要上ADG;如果你要的是秒级的物理同步,并且备库还要能查数据,那ADG就是正解。
1.2 版本和部署形态怎么选
Oracle 19c目前是Oracle数据库长期支持版本里用得最广的一个,官方支持周期很长,所以它最适合作为新建ADG环境的版本。19c的ADG搭建一般分为单机对单机、单机对RAC、RAC对RAC、RAC对单机这几种形态。这里有个重要的知识点:19c的ADG在单机到单机的场景下,主备库的安装路径和目录结构建议保持完全一致,否则后面配置pfile、控制文件路径、数据文件路径时会有大量额外工作。
如果你计划让备库跑在同一台物理机的不同目录下做演练,理论上也可以,但我强烈不建议在生产这么搞。ADG本身的价值就在于跨机故障域隔离,放到同一台机器上意义大打折扣。参考我们最常见的项目需求,这里我以两台独立Linux服务器为例来说明整个搭建过程,操作系统为CentOS 7.6,数据文件目录统一规划为/u01/app/oracle/oradata/ORCL。
1.3 两个节点的基础检查和配置
在开始安装Oracle软件之前,有几项系统层面的检查非常关键。第一步是配置/etc/hosts,主备库都要把对方的主机名和IP写进去,并且建议用主机名而不是IP来连接,这样后续维护和搬迁会更方便。第二步是关闭firewalld和SELinux,19c对这两个东西的兼容性比较敏感,尤其是SELinux如果开着,经常会报一些奇怪的权限错误,排查起来很费时间。第三步是检查磁盘空间,因为ADG备库需要完整接收主库的数据文件,磁盘空间至少要预留主库数据文件总大小的1.5倍以上,如果把闪回恢复区也放到同一块盘,空间要更大。
然后是Oracle用户的参数配置,我记得很多刚接触Oracle的同行会忽略ulimit的设置。建议在/etc/security/limits.conf里配置好oracle用户的nofile、nproc、memlock等参数,memlock建议设为锁定不上限,也就是unlimited,否则后续ADG搭建时归档进程或lgwr进程可能因为内存交换出现性能抖动。
注意:Oracle 19c安装时至少要准备2.2GB的swap,物理内存建议8GB以上。如果服务器内存较小且没有条件上大内存,至少在搭建时把sga_target和pga_aggregate_target调低一点,避免因内存不足导致数据库启动直接报ORA-00845。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 主库侧的基础配置与关键参数调整
2.1 开启归档模式和强制日志
ADG搭建的基础是主库必须运行在归档模式下,这个我做过很多次测试,确认是绝对前置条件。如果主库还在非归档模式,配置不管多完美都跑不起来,日志传输在第一个日志切换就会断掉。
先查看当前状态的命令:
sql复制SQL> archive log list;
Database log mode No Archive Mode
Automatic archival Disabled
Archive destination /u01/app/oracle/archive
Oldest online log sequence 25
Next log sequence to archive 26
Current log sequence 28
如果显示No Archive Mode,执行如下命令开启:
sql复制SQL> shutdown immediate;
SQL> startup mount;
SQL> alter database archivelog;
SQL> alter database open;
再次确认状态变成Archive Mode之后,还需要设置归档目录和格式。19c默认的归档路径可能不太合适,我建议在spfile里把db_recovery_file_dest和log_archive_dest_1都配置好:
sql复制SQL> alter system set db_recovery_file_dest='/u01/app/oracle/fast_recovery_area' sid='*';
SQL> alter system set db_recovery_file_dest_size=50G sid='*';
SQL> alter system set log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST valid_for=(all_logfiles,all_roles) db_unique_name=ORCL' sid='*';
log_archive_dest_1用USE_DB_RECOVERY_FILE_DEST的好处是归档会统一写到闪回恢复区,而且RMAN在备份清理归档时能自动管理空间。这一点比手动指定一个传统目录要省心很多。很多人在这里有个误区,以为ADG只要配置log_archive_dest_2指到备库就够了,其实log_archive_dest_1也会参与备库的日志接收校验,配置不当会发生日志应用不连续的问题。
强制日志(Force Logging)也一定记得打开:
sql复制SQL> alter database force logging;
这个操作的作用是确保即使有人对表执行了nologging操作,所有变更也都会记入redo日志,保证备库不会因为缺少redo信息而出现数据不一致。我曾经遇到过某个项目因为没有开强制日志,备库的数据文件某几块内容始终和主库对不上,最后排查半天发现是应用侧在建表时用了nologging。这个坑说大不大,但绝对能让DBA加班到半夜。
2.2 初始化参数里必须调整的几项
主库的DB_UNIQUE_NAME建议设置为ORCL,备库设置为ORCLDG,这样后面在broker里区分角色一清二楚。如果希望主备库有相同的db_name,db_unique_name就扮演了区分节点的关键角色。初始化参数里和ADG相关的主要有下面这几个:
sql复制alter system set db_unique_name='ORCL' scope=spfile sid='*';
alter system set log_archive_config='dg_config=(ORCL,ORCLDG)' scope=both sid='*';
alter system set log_archive_dest_2='service=ORCLDG async valid_for=(online_logfiles,primary_role) db_unique_name=ORCLDG' scope=both sid='*';
alter system set log_archive_dest_state_2=enable scope=both sid='*';
alter system set fal_server=ORCLDG scope=both sid='*';
alter system set fal_client=ORCL scope=both sid='*';
alter system set standby_file_management='AUTO' scope=both sid='*';
alter system set db_file_name_convert='/u01/app/oracle/oradata/ORCLDG','/u01/app/oracle/oradata/ORCL' scope=spfile sid='*';
alter system set log_file_name_convert='/u01/app/oracle/oradata/ORCLDG','/u01/app/oracle/oradata/ORCL' scope=spfile sid='*';
这里面我要专门解释一下log_archive_dest_2中的async参数。Oracle 19c的Data Guard提供了三种日志传输模式:SYNC、ASYNC和LGWR SYNC。默认推荐用ASYNC,它的含义是主库的LGWR进程写redo时不会等待备库的确认,这样对主库的性能开销最小,但极端情况下日志有丢失的风险。如果业务对数据零丢失敏感,就必须用SYNC,也就是主库commit前要等redo日志完整到达备库,这个适合同机房或同城低延迟网络。实际项目里,同城容灾经常用SYNC,异地容灾基本都选ASYNC,这个决策要结合业务的RPO要求来定。
FAL_CLIENT和FAL_SERVER这两个参数很多人不理解,其实它们是解决日志断档时自动补拉日志的关键配置。备库在发现应用日志有gap时,会通过FAL机制从FAL_SERVER指定的库上请求缺失的归档日志。所以主库的FAL_SERVER要指向备库,备库的FAL_SERVER要指向主库,形成双向解析。DB_FILE_NAME_CONVERT和LOG_FILE_NAME_CONVERT则是用来做数据文件和日志文件路径转换的,当主备库目录结构不一致时必须有这个设置,否则备库创建数据文件时会因为找不到目录而报ORA-01186。
2.3 主备库的监听与网络配置
ADG对网络延迟和安全连接也有一定要求,虽然不强制使用Oracle Net Manager,但tnsnames.ora必须写正确。我在主库和备库的$ORACLE_HOME/network/admin/tnsnames.ora里都配置了两个连接别名:
code复制ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.10)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCL)
)
)
ORCLDG =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.20)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCLDG)
)
)
注意主备库的service_name要在各自数据库的初始化参数中设置,并且监听器listener.ora里要配置好对应的服务名。备库的监听同样需要提前启动,否则主库的lgwr或arc进程无法连接到备库。用lsnrctl status命令可以快速检查监听状态。
很多初次搭建的人容易在这里卡住,最常见的原因是tnsnames.ora里的主机名无法解析。我的建议是先在主库上执行tnsping ORCLDG命令,确认能ping通备库再继续,这一步花不了30秒,却能节省后面大量排错时间。
3. 从零搭建备库的完整过程
3.1 搭建前必须完成的备份与参数文件导出
在备库数据库还没有建好之前,我们需要先准备一套主库的完整备份。我习惯用RMAN来做全库备份,并同时生成备库需要的standby controlfile。具体流程是登录RMAN,先做一个全库备份,然后执行backup current controlfile for standby命令,把控制文件备份成备库专用的格式。
bash复制rman target /
RMAN> backup database plus archivelog;
RMAN> backup current controlfile for standby format '/tmp/standby_control.ctl';
数据文件备份完成后,还需要从主库导出pfile。注意这里不是spfile,pfile是文本形式的,便于在备库上修改路径和参数。在主库执行:
sql复制SQL> create pfile='/tmp/initORCLDG.ora' from spfile;
拿到这个pfile之后,把里面的db_unique_name改成ORCLDG,并把db_file_name_convert和log_file_name_convert里的路径对调,同时把control_files指向备库实际使用的控制文件路径。用最简单的方式,我先用scp把备份和pfile传到了备库服务器,然后逐一修改。
3.2 备库软件安装与目录结构准备
备库的Oracle 19c软件安装,按照安装向导正常操作就行。我要强调的是,安装Oracle软件时不要建库,数据库我们后面用RMAN duplicate的方式创建。如果你在安装过程中顺手建了一个空库,后面还得删掉重建,反而多绕一圈。
目录结构方面,备库我规划为:
code复制/u01/app/oracle/oradata/ORCLDG/
/u01/app/oracle/fast_recovery_area/ORCLDG/
因为pfile里已经设置了db_file_name_convert和log_file_name_convert,主库的数据文件路径会自动映射到备库的ORCLDG目录。如果你不想做自动转换,那就必须保持主备库的数据文件路径完全一致,包括目录名都不能有差别,否则RMAN在restore数据文件时会找不到目标路径。
备库还需要准备好口令文件。最简单的方式是从主库把$ORACLE_HOME/dbs/orapwORCL文件直接拷贝到备库,重命名为orapwORCLDG,因为SYS密码要保持一致,否则后面建立DG时会报ORA-01017。
注意:备库的参数文件中,control_files一定要指向备库自己的文件路径,不要直接沿用主库的control_files配置。如果控制文件路径设置错,startup mount阶段就会报错,压根走不到后面。
3.3 RMAN duplicate实现备库创建
一切准备就绪后,在备库上执行RMAN的duplicate命令。这一步是整个搭建过程中最有成就感也最容易出错的部分。
首先在备库上把数据库启动到nomount状态,确保控制文件可以正常创建。然后登录RMAN,使用auxiliary连接方式:
bash复制rman target sys/oracle@ORCL auxiliary sys/oracle@ORCLDG
RMAN> duplicate target database for standby from active database
dorecover
nofilenamecheck;
这里from active database表示直接从运行中的主库实时复制数据文件,不需要先把备份文件拷贝到备库,简单省事。DORECOVER会让备库在复制完成后自动恢复,节省一次手动recover操作。NOFILENAMECHECK是配合目录转换用的,因为路径不一致时RMAN默认会检查文件名,加上这个参数它才会接受convert后的结果。
duplicate执行时间取决于主库数据量大小和网络带宽。我在测试环境大概是50GB的数据,千兆网络下跑了约20分钟。跑完之后,备库会自动关闭并退到nomount状态。这时候我们再手动把备库启动到mount,开始正式的日志应用流程:
sql复制SQL> startup mount;
SQL> alter database recover managed standby database using current logfile disconnect from session;
执行完这行命令后,备库开始从主库接收redo日志并完成恢复。观察一下alert日志,如果出现类似"Media Recovery Start"和"Started redo scan"的信息,说明日志应用线程已经跑起来了。
3.4 验证同步状态
备库起来之后,验证同步是必须的。我在主库执行一次日志切换,然后在备库上查:
sql复制SQL> select sequence#, first_time, next_time, applied from v$archived_log order by sequence# desc;
如果新切出来的日志能在备库的v$archived_log中看到,且applied显示为YES,说明ADG的基本链路已经通了。还可以用:
sql复制SQL> select database_role, open_mode from v$database;
正常情况下备库应该显示为PHYSICAL STANDBY,OPEN_MODE为MOUNTED。如果你想更加严格地确认应用没有延迟,可以对比主库和备库的当前SCN,差值很小或者为0说明完全追平了。
ADG和普通DG的差别在于备库以只读方式打开,而不仅仅是mount状态。如果业务确实需要只读查询能力,那么在确认日志应用正常后,就可以打开备库:
sql复制SQL> alter database open;
SQL> alter database recover managed standby database using current logfile disconnect from session;
注意顺序不能反,必须先open,再恢复应用。如果是RAC备库,还需要在第二个节点执行alter database recover managed standby database using current logfile disconnect from session,但单机环境一条命令就够。
4. 用Data Guard Broker接管日常管理
4.1 为什么建议用Broker而不是手写命令
早期版本里,很多人习惯手写SQL来管理DG,比如切换时执行alter database commit to switchover to physical standby之类的命令。19c里Data Guard Broker已经非常成熟,我强烈建议把DG配置交给Broker管理。Broker的好处是可以统一管理主备库的状态,故障转移、角色切换、监控延迟都提供了现成的命令,还能在日志应用异常时自动重新启动恢复进程。
启用Broker前,主备库都要设置dg_broker_start参数:
sql复制SQL> alter system set dg_broker_start=true sid='*';
然后主库上执行:
bash复制dgmgrl sys/oracle@ORCL
DGMGRL> create configuration dg_config as primary database is ORCL connect identifier is ORCL;
DGMGRL> add database ORCLDG as connect identifier is ORCLDG maintained as physical;
DGMGRL> enable configuration;
创建出来后,可以用show configuration查看整体状态。如果看到SUCCESS,说明主备关系被Broker正确识别了。从这以后,常规的SQL操作和日志应用建议都通过Broker来做,双人复核模式也方便些。
4.2 通过Broker做一次switchover
ADG搭建完成后,最好马上做一次switchover演练,验证角色切换功能。很多人在搭建后第一周不测,等到真要切换的时候才发现配置有问题,那才叫痛苦。
切换前先检查主备库的同步状态:
bash复制DGMGRL> show database ORCL;
输出里会有Database Status、Role、Intended State之类的字段,确认状态是SUCCESS后执行:
bash复制DGMGRL> switchover to ORCLDG;
Broker会自己完成主库转备库、备库转主库的全流程,全程不用人工介入。执行过程中会输出每步操作的状态。切换完成后,再用show configuration确认当前主库已经是ORCLDG,旧主库ORCL变成了备库。
切换后要在新备库上把日志应用恢复起来。有时候switchover执行完后新备库的回放进程没有自动启动,需要手动:
bash复制DGMGRL> edit database ORCL set state='apply-on';
如果你打算长期保持这个状态,那么原来的主库现在就是备库了;如果只是演练,再执行一次switchover to ORCL切回来即可。切换回来后,记得把两边数据库的TNS和Listener状态再检查一遍。
4.3 处理归档日志gap的小技巧
日志gap是ADG运维中最让人头疼的问题之一。我在实际项目中遇到过主备断开几个小时甚至一天的情况,备库重新连上后,需要追赶大量归档。19c的FAL机制会自动处理大多数gap,但还是有极少数情况下需要手动干预。
先查gap:
sql复制SQL> select * from v$archive_gap;
如果返回空,说明没有gap。如果有,记下缺的日志序列号,然后去主库找到对应归档,用scp传到备库,在备库上执行:
sql复制SQL> alter database register logfile '/path/to/archive_xxx.arc';
SQL> alter database recover managed standby database using current logfile disconnect from session;
这个操作能把缺口补上。补完之后再查一次v$archive_gap,确认恢复到空集。整个过程要小心,不要在备库追日志的时候并发做控制文件的alter操作,否则可能导致恢复链路直接中断。
5. 搭建过程中常见的坑和排查技巧
5.1 日志传输断开的排查思路
遇到备库接收不到日志的情况,我一般按这个顺序排查:
首先看主库的v$archive_dest_status:
sql复制SQL> select dest_name, status, error, type from v$archive_dest_status;
如果LOG_ARCHIVE_DEST_2的状态是ERROR,后面的error列会直接告诉你具体原因。最常见的报错是ORA-12541(监听没起来)或者ORA-12154(TNS解析失败)。如果ERROR列显示ORA-16191,那多半是主备库的SYS密码不一致或者口令文件有问题。
其次看备库的alert日志。备库重做应用中断一般会在alert日志里留下明确的线索,比如ORA-00313、ORA-00312这类文件相关的错误。如果备库的redo log成员路径不对或者控制文件里记录的文件路径和实际磁盘不符,就会出现这类问题。
最后看主库的lgwr/arc进程有没有报错。用ps -ef | grep arc查看归档进程是否正常,或者查询v$log_history确认主库是否正常归档。日志传输链路是主库生成日志、传输到备库、备库注册归档、应用归档这四个环节,任何一个环节出问题,现象都类似:备库的sequence一直不往前走。有耐心地逐链路排查,问题通常半小时内能定位。
5.2 备库一直处于mount状态无法open
这个坑我踩过一次。备库执行alter database open时,如果日志应用还在进行中,会报ORA-01154: database busy。解决办法是先停掉日志应用:
sql复制SQL> alter database recover managed standby database cancel;
SQL> alter database open;
SQL> alter database recover managed standby database using current logfile disconnect from session;
还有一种情况是备库在做redo apply的过程中有pending的恢复操作,直接open会提示需要执行recover,那就先recover database再open。
另外,如果你配置的是Active Data Guard,备库打开后还需要开启实时查询。19c默认的ADG会在open后自动启用这个特性,但如果你发现备库只读打开后查询报ORA-16000,就需要确认是否用了标准版或者某些受限版本。标准版不支持Active Data Guard,只能跑普通物理备库,这是许可层面的限制,和配置无关。
5.3 时空不同步带来的隐患
ADG依赖redo的SCN和时间戳,因此要求主备库的服务器时间尽量保持一致。如果两台服务器时间相差太多,虽然不一定会报错,但备库的归档应用时间点可能错乱,影响比较日志和监控判断。建议主备库都配置NTP同步,且时区保持一致。不要小看这个问题,有些DBA排查半天日志不同步,最后发现是备库的时间比主库快了10分钟导致的。
我在生产环境还遇到过另一种情况:备库的system表空间或undo表空间不够,导致日志应用过程中ORA-01652报错,从而中断恢复。备库虽然不跑业务,但日志应用同样需要undo和temp空间。搭建时就要把备库的undo表空间和临时表空间建得和主库一样甚至更大,否则应用大事务时备库很可能无法完成恢复。
5.4 主库参数修改后需要同步到备库的规则
这是ADG运维中最容易被忽略的地方。主库用alter system设置参数后,这些参数并不会自动同步到备库的spfile。19c里通过Broker管理的配置,部分参数(比如log_archive_config、log_archive_dest_n)会自动同步,但像MEMORY_TARGET、SGA_TARGET这类参数就不会。我的习惯是,主库改完重要参数后,把spfile生成的pfile对比一下,确认备库需要的参数也改了,再重启备库加载。
当然,19c也提供一个另类方案:直接用RMAN duplicate刷新整个备库的环境。但那个操作成本太高,不推荐作为日常运维手段。
6. 适配更多场景的扩展思路
6.1 从单机ADG扩展到RAC ADG
如果你的主库是RAC,备库计划也是RAC,那么前面的搭建思路要稍作调整。RAC环境下,备库的节点各自需要设置自己的SID、本地监听和ASM磁盘组。在RMAN duplicate时,备库需要用srvctl来配置数据库资源,并且每个节点都要配置对应的tnsnames和监听。整体流程可以类比单机,但细节上多了很多东西。
比如RAC备库的初始化参数里,需要把cluster_database设为true,control_files要放在ASM磁盘组中,db_create_file_dest指向+DATA。日志传输的架构仍然是主库任意节点产生日志,通过GLOBAL NAME访问备库的service。切换时,Broker对RAC环境的处理比手工SQL要可靠得多,因此RAC ADG基本都走Broker管理。
6.2 快照备库在测试环境中的使用
19c的ADG还支持把一个物理备库转换为快照备库(Snapshot Standby),它允许你在备库上临时进行读写操作,方便做升级演练或者报表开发。转换命令很简单:
bash复制DGMGRL> convert database ORCLDG to snapshot standby;
但要注意,转为快照备库后,原来的日志应用会中断,备库数据会暂时脱离主库同步。等你测试完,再执行convert database ORCLDG to physical standby,备库会自动丢弃快照期间的修改并重新开始日志应用。这个特性在测试环境里非常实用,我经常用它做应用或数据库的升级演练。
6.3 结合闪回功能提升灵活性
如果备库不小心因为某些误操作产生了不一致,或者希望切换后有快速回退能力,可以考虑启用闪回数据库。主备库都可以开启flashback on:
sql复制SQL> alter database flashback on;
开启后,DB_FLASHBACK_RETENTION_TARGET设置一个合理的保留时间,比如120分钟。角色切换失败时,可以通过flashback database恢复到切换前的状态,再重新建立同步。这算是ADG之外的又一层保险,在重要系统上非常值得做。
7. 最后的几点经验
搭建Oracle 19c ADG并不算难,真正难的是理解每一个参数背后的作用和角色切换时的完整链路。我每次和团队讨论ADG方案时都会强调一点:ADG值钱的不只是备库那些数据文件,而是那份随时可切换、可验证的容灾能力。这个能力需要定期演练才能保持,不演练的ADG和堆冷备没有本质区别。
我个人的实操习惯是,ADG搭完后至少做三件后续动作:一是把主备库的初始化参数、TNS配置、归档目录结构整理成文档;二是在测试窗口做一次switchover和一次failover演练,记录下切换耗时;三是配置好监控告警,重点盯日志传输延迟和备库的open_mode状态。这些工作看上去琐碎,但在真正发生故障时能救命。
再说一个很多人不知道的小技巧:在备库查询同步状态时,不要只看v$archived_log里的applied字段,那个字段有时会滞后。更靠谱的是查看v$standby_log的恢复进度,或者用dgmgrl的show database命令看transport lag和apply lag。尤其是apply lag,它反映的是备库实际应用日志与主库当前日志的延迟秒数,如果长时间不为零说明备库处理能力不足,需要评估备库硬件配置或检查是否有大事务在跑。
如果你正在准备搭建自己的第一套19c ADG,我的建议是先在一个可控的测试环境完整跑通一遍,把主库和备库的切换操作练熟,再去碰生产环境。网上能搜到的每篇教程都只能帮你少踩一部分坑,真正的经验还是得靠自己那一次成功和那几次排错堆出来。
最后分享一个我常用的备库健康巡检SQL,每周跑一次,能很清楚地看出主备状态:
sql复制select name, value, unit, time_computed
from v$dataguard_stats
where name in ('transport lag', 'apply lag');
看到这两个值长期保持在0秒,就可以放心地让ADG在后台继续工作了。
