
1. 写在前面为什么RAC开归档比单实例麻烦先别急着敲命令。我在接手第一套RAC环境的时候也以为开启归档就是两条ALTER DATABASE ARCHIVELOG;加shutdown重启的事结果在RAC上翻了车——具体原因后面细说先把结论抛出来RAC开启归档本质上是“所有实例协同修改控制文件状态归档路径必须放在共享存储”这两件事同时做对缺一个都会导致启动失败或者日志根本存不下来。这文章适用的读者分两类一类是刚接触RAC的DBA照着步骤能把归档开起来另一类是已经被归档问题坑过的看完能明白自己当时错在哪。整个过程我会按“为什么要这么设计—事前检查—实际操作—事后验证—踩坑记录”的顺序来写尽量把每一步背后的逻辑讲透。先说个基本概念RACReal Application Clusters是多个实例共享一套数据库文件控制文件、数据文件、redo日志全部放在共享存储上。开启归档模式意味着数据库从NOARCHIVELOG切换到ARCHIVELOG这个状态记录在控制文件里所以必须让所有实例都安静下来由其中一个实例去修改状态其余的实例重启后自然就知道数据库已经是归档模式了。单实例开归档网上教程一抓一大把无非是shutdown immediate、startup mount、alter database archivelog、alter database open四步走。但RAC不行因为多个实例同时处于open状态任何一人在线改归档模式都会报ORA-00265要求实例恢复或者干脆卡住必须先把所有实例都shutdown再从一个实例执行mount和alter操作最后把其余实例带起来。这也就解释了为什么热词搜索里“oracle rac的表空间满了”会跟归档绑定出现——很多库开完归档不设置清理策略归档写满ASM磁盘组是迟早的事。所以RAC开归档真正的难点不在“执行那几条SQL”而在于归档日志不是写本机磁盘而是写共享存储ASM磁盘组或共享文件系统每个实例都要单独配置归档路径参数且路径必须可见快速恢复区Fast Recovery Area的配置直接影响归档密度和磁盘占用日志切换频率和归档空间增长需要提前估算否则开着开着磁盘就满了这一套设计思想理解了后面的命令才不是“背下来的”而是“推出来的”。2. 开启归档前的环境检查与方案设计2.1 确认当前数据库模式与集群状态我习惯先做三件事查实例、查模式、查磁盘组。这三件事做完基本就能确定方案了。第一确认集群有几个节点每个节点上实例是什么状态。用crsctl status resource -t或者crsctl status cluster都能看重点看ora.dbname.db这个资源的状态正常是ONLINE分布在多个节点上。这一步不是废话因为后面关库是逐个节点来少停一个实例后面就会报错。第二确认当前日志模式。用sqlplus / as sysdba登录其中一个实例执行SELECT name, log_mode FROM v$database;log_mode显示NOARCHIVELOG就说明还没开归档。顺手再查一下db_unique_nameSELECT db_unique_name FROM v$database;这个在配置归档路径的时候有用因为RAC的默认归档路径如果你开了快速恢复区是DATA/下按db_unique_name划分目录如果是Data Guard环境主备的db_unique_name必须不同归档路径才不冲突。第三看ASM磁盘组剩余空间。归档日志是写共享存储的磁盘组满了就什么也干不了。查法-- 在grid用户下执行 asmcmd lsdg看USABLE_FILE_MB可用空间或者用SQL查SELECT name, total_mb, free_mb FROM v$asm_diskgroup;这一步的核心目的是为后面的空间估算提供基数不是说看到剩余空间几十GB就放心了得结合数据库的日志切换频率来算一天产生多少归档。2.2 选择归档目标快速恢复区 vs 自定义ASM目录RAC环境下归档日志有两个存放思路各有利弊我只说实际中经常遇到的。第一种是使用快速恢复区Fast Recovery AreaFRA数据库级别设置DB_RECOVERY_FILE_DEST_SIZE和DB_RECOVERY_FILE_DEST所有归档日志、控制文件自动备份、闪回日志都放这里。RMAN备份和灾难恢复都默认从这里读写运维上省心不少。缺点是快速恢复区是一锅烩归档和其它文件共享空间一旦估算不准RMAN备份可能因为“磁盘空间不足”而失败并且归档满后数据库会直接hang住这个坑我踩过。第二种是不用FRA直接为每个实例显式指定LOG_ARCHIVE_DEST_1路径指向ASM磁盘组下的独立目录。这种方式的好处是归档路径可控归档和备份互不影响排查归档空间问题非常直观缺点是要手动处理目录规划RMAN的一些自动管理特性如快速恢复区自动清理享受不到得额外配置归档删除策略。实操中我倾向于推荐生产库用FRA但把归档单独放一个磁盘组比如ARCH。这样既保留了RMAN快速恢复区的特性又能避免归档和数据库文件争抢空间。如果条件有限只有一组DATA那就老老实实用FRA但必须在后续做好空间监控和归档清理策略。2.3 归档日志空间估算别等满了再后悔日志切换一次生成一个归档日志文件一个文件大小由redo log组大小决定。所以估算逻辑很简单每小时归档量 每小时日志切换次数 × redo log组大小 每天归档量 峰值每小时归档量 × 24保守可按峰值算具体查一下在线日志有几组、每组多大SELECT group#, thread#, bytes/1024/1024 AS mb, status FROM v$log;一个实例一般有2-3组每组200MB到2GB不等。RAC下每个线程thread独立一组节点1是thread 1节点2是thread 2。举个例子你查出来redo组大小为1GB高峰期每小时切换20次那么高峰期每小时归档大约20GB一天下来可能400-500GB。如果ASM剩余空间只有300GB那就算归档能开也撑不了一天。这种情况下就得先考虑加磁盘组空间、加大redo日志组大小降低切换频率或者接受开启归档后立刻挂掉的风险。实际操作中很多库平时每小时切换十几次一到月底报表高峰期每小时切几十次。所以估算别按平均值按峰值算并且建议预留30%余量。这个数值后面配置监控阈值时用得上。2.4 集群参数文件与归档参数的关系RAC环境统一用spfile服务器参数文件一般放在ASM磁盘组里归档参数属于“全局参数”形式上用sid*设置保证所有实例拿到一致配置。这一点和单实例有本质区别单实例改个pfile就行RAC如果用了pfile每个节点的init.ora都要改漏一个就是归档路径不一致报错排查的时候极其痛苦。实操中强烈建议确认当前使用的是spfileSELECT value FROM v$parameter WHERE namespfile;有值就说明是spfile启动。如果没有说明用的pfile先想办法恢复成spfile再继续。因为后续改LOG_ARCHIVE_DEST、LOG_ARCHIVE_FORMAT这些参数如果存不进spfile重启后就直接还原了。这个坑我见过不少人踩。另外需要先确认归档进程数量。默认LOG_ARCHIVE_MAX_PROCESSES是4对绝大多数场景够用。如果日志切换特别频繁每秒几百KB的redo生成量可以考虑调到8、12但一般DBA不会去动它因为归档瓶颈通常不在这里而在磁盘IO。3. 核心实操步骤RAC开启归档全流程3.1 第一步逐个节点安全关闭实例关闭实例是有顺序讲究的。RAC的核心原则是“先关业务节点最后关管理节点”实际操作中从哪个节点开始其实不绝对但要保证在所有实例都关闭之前没有新会话连接到数据库。最稳妥的做法是先通知业务侧停应用确认没有活动会话再操作。如果库是7x24的得提前安排维护窗口。从节点1开始关登录节点1执行sqlplus / as sysdba SQL shutdown immediate;再到节点2、节点3……依次执行同样的操作。每个实例都关闭之后用crsctl stat res -t确认数据库资源变成OFFLINE。这里强调一下为什么要shutdown immediate而不是shutdown abort。immediate会回滚未提交事务、断开客户端连接正常关闭redo和归档状态都很干净abort相当于直接杀掉实例实例恢复需要redo做前滚后续启动时归档模式切换虽然也能做但增加了故障恢复的复杂度。维护窗口内能用immediate就不要用abort。有个小技巧关闭实例之前先看下有没有正在运行的备份任务RMAN备份过程中关闭实例会把备份任务搞残。等备份job结束后再进入维护窗口比较稳。3.2 第二步在单实例模式下将数据库置为mount并开启归档所有实例关闭后随便挑一个节点通常选节点1登录后执行sqlplus / as sysdba SQL startup mount;这里你会发现不需要指定实例名因为节点1的实例启动后自动把共享的控制文件mount进来集群其它实例此时都是停机状态不会冲突。这个状态下数据库只能做管理和恢复操作不能对外服务。接着执行最关键的一条SQL ALTER DATABASE ARCHIVELOG;执行完毕可以查一下确认SQL SELECT log_mode FROM v$database;显示ARCHIVELOG就是成功了。此时再顺手打开数据库SQL ALTER DATABASE OPEN;理论上这一步完成后节点1已经以归档模式运行了。但RAC的复杂之处在于其它实例还没起来当前节点是“单实例模式运行在归档模式下”。下面配置参数和启动其余节点要一气呵成。3.3 第三步配置各实例归档路径与归档日志格式这一步是整个RAC开归档最核心、最容易出错的地方。先说归档路径。使用FRA方案下只需设置数据库级参数SQL ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE 512G SID* SCOPEBOTH; SQL ALTER SYSTEM SET DB_RECOVERY_FILE_DEST ARCH SID* SCOPEBOTH;DB_RECOVERY_FILE_DEST_SIZE要多大就是前面估算的归档日产量乘预留天数比如保留7天闪回日志和控制文件自动备份的空间。注意DB_RECOVERY_FILE_DEST_SIZE是硬上限超过了就会报ORA-19809或者数据库hang住所以必须留足余量。如果不用FRA直接按实例设置LOG_ARCHIVE_DEST_1SQL ALTER SYSTEM SET LOG_ARCHIVE_DEST_1LOCATIONARCH/arch SIDnode1 SCOPEBOTH; SQL ALTER SYSTEM SET LOG_ARCHIVE_DEST_1LOCATIONARCH/arch SIDnode2 SCOPEBOTH;这里要注意ASM目录写在LOCATION后面不需要带数据库名字Oracle会自动拼接db_unique_name/archivelog/...的目录结构。如果节点之间目录不一致后面查看归档日志和RMAN恢复时会找不到文件。所以实际生产里我更推荐统一用FRA让Oracle自己管理目录结构例子如下。然后是归档日志命名格式。不设置也行Oracle有默认格式但为了便于排查和后续RMAN恢复强烈建议显式设置SQL ALTER SYSTEM SET LOG_ARCHIVE_FORMATarch_%t_%s_%r.arc SID* SCOPEBOTH;这个格式的含义是%t是线程号对应实例%s是日志序列号%r是resetlogs ID。RAC下每个实例有独立的线程号所以节点1产生的归档和节点2产生的归档不会重名。格式里包含%r尤其重要数据库经历过不完全恢复resetlogs后旧的归档文件名和新的归档文件名有可能冲突带%r就绝对不会。再顺手设置归档进程数量默认4就够了SQL ALTER SYSTEM SET LOG_ARCHIVE_MAX_PROCESSES8 SID* SCOPEBOTH;这个值根据实际日志量来保守起见不开额外花活。参数都设置完后选择重启节点1还是直接open后面再说这里先把节点1置为open状态。3.4 第四步启动其余集群实例并验证归档进程状态节点1已经open后去其余节点上逐个启动实例。这一步可以直接用集群资源管理# 用grid用户执行 srvctl start instance -d dbname -i instance_name或者直接到节点2上用SQL*Plussqlplus / as sysdba SQL startup;RAC的特性决定了实例启动时会自动读取spfile里的公共参数所以此前配置的DB_RECOVERY_FILE_DEST、LOG_ARCHIVE_FORMAT会一并生效。节点起来之后检查每个实例是否都正常开启归档-- 在每个节点分别执行 SELECT instance_name, log_mode FROM v$database, v$instance;每个节点返回的log_mode都应该是ARCHIVELOG。然后看当前归档日志的生成状态SELECT thread#, sequence#, archived, status FROM v$log;archived字段显示YES说明这一组redo已经归档完成NO说明还没切换过。让日志切几次就知道是否真正工作了SQL ALTER SYSTEM SWITCH LOGFILE;执行两次以后再去查归档目录asmcmd ls ARCH/db_unique_name/archivelog能看到以日期和时间命名的目录里面就是新生成的归档文件。这一步做通了RAC归档就算真正跑起来了。3.5 第五步配置集群资源属性并测试重启我见过有人开完归档不测重启结果下次机房断电后数据库启不来一查是归档参数没进spfile或者资源属性不对。所以最后这步别省。先确认集群数据库资源里归档相关的属性没问题。用crsctl查一下crsctl stat res ora.dbname.db -p | grep -i arch正常应该能看到ORA_DB_ARCHIVELOG_MODEARCHIVELOG这类属性具体属性名可能因版本而异这表示集群管理的数据库资源已经知道当前是归档模式以后crsctl start database启动时不会误认为非归档而跳过某些步骤。然后做一次完整体验用srvctl stop database -d dbname和srvctl start database -d dbname关停、启动整个数据库观察所有节点是否都能正常进入归档模式。这个测试防的是“单个节点手工startup时正常但集群整体拉起时异常”的情况。等整个库起来后再用第3.4节的检查方法验证一遍。这一步做完RAC开启归档的实操部分才算完整落地。4. 归档参数深度解析与日常监控4.1 各参数取值逻辑与优先级很多人开完归档就完事了归档参数长期不检查直到出问题才回头看。这里把关键参数列个表写清楚推荐值和为什么。参数名推荐值说明与注意点LOG_ARCHIVE_FORMATarch_%t_%s_%r.arc%r必须带否则resetlogs后可能重名DB_RECOVERY_FILE_DEST_SIZE估算日归档量×保留天数20%缓冲设太小会报ORA-19809设太大会浪费磁盘DB_RECOVERY_FILE_DESTARCH或DATA建议独立磁盘组不与数据文件抢空间LOG_ARCHIVE_DEST_STATE_1ENABLE如果设为DEFER该路径不写归档极易被忽略LOG_ARCHIVE_MAX_PROCESSES默认4切换频繁时可调到8调前先观察IO能力ARCHIVE_LAG_TARGET0不限制想控制最大归档间隔可设置秒数如1800第二个参数LOG_ARCHIVE_DEST_STATE_1我特意列出来是因为在RACData Guard环境里主库经常把LOG_ARCHIVE_DEST_2配成备库位置如果备库地址变化或维护中被误设为DEFER状态主库的归档日志就少一份副本而数据库不会报警最后备库出问题才找到主库头上。还有一个容易被忽略的是DB_FLASHBACK_RETENTION_TARGET这货不是归档参数但开着闪回时会自动产生闪回日志也吃FRA的空间。如果你不想开闪回确保它是0否则FRA大小计算就得额外加这部分。4.2 监控归档空间的三板斧归档空间监控是DBA的日常功课。我推荐三层监控手段按重要程度排序。第一层是ASM磁盘组空间使用率。最简单粗暴写个脚本定时执行asmcmd lsdg或者用EMCC、Zabbix这类监控工具把v$asm_diskgroup采集出来。阈值建议归档所在磁盘组使用率超过85%就该预警90%就该处理95%以上基本是灾难边缘了。第二层是归档生成速率。这个决定了“磁盘组还能撑多久”比单看空间更有用。计算方式SELECT thread#, COUNT(1) archive_count, ROUND(SUM(blocks*block_size)/1024/1024/1024, 2) size_gb FROM v$archived_log WHERE first_time SYSDATE - 1 GROUP BY thread#;这个SQL统计每个实例过去24小时归档数量和总量。连续观察几天基本能摸清日归档量规律再结合磁盘组剩余空间就能估算出还能撑几天。第三层是快速恢复区空间使用。如果开了FRA看一眼使用率SELECT * FROM v$recovery_area_usage;能看到FRA被归档、备份、闪回日志各占了多少。如果归档占了快90%的空间说明RMAN删除策略没跟上或者归档还没有被RMAN备份消费掉。4.3 归档清理策略RMAN配置不能省开启归档后归档文件会持续增长手动清理是下策RMAN的删除策略才是正道。一个典型的配置是rman target / CONFIGURE ARCHIVELOG DELETION POLICY TO BACKED UP 1 TIMES TO DEVICE TYPE DISK;这条策略的意思是只要归档日志被磁盘备份设备备份过一次就可以删了。这样RMAN执行BACKUP ARCHIVELOG ALL DELETE INPUT时会自动清理已经备份过的归档。如果没有配置这个策略归档会一直保留到手动删除为止这就是为什么很多库跑着跑着磁盘就满了。对于RAC环境RMAN备份归档时还会自动协调多个实例的归档不需要额外配置。重点在于定时任务每天晚上全备或增备后执行一次DELETE ARCHIVELOG ALL BACKED UP 1 TIMES TO DEVICE TYPE DISK;把已备份的归档清掉。有同学会问“能不能只保留几天、直接按时间删”比如DELETE ARCHIVELOG UNTIL TIME SYSDATE-3;。这也可以但风险是“3天前的归档即使没被备份也会被删”如果中间备份任务挂了几天归档先于备份被删后果是灾难恢复时找不到需要的归档。所以更推荐按“已被备份”作为删除条件而不是按时间。这是我的实际教训。5. 常见问题与排查技巧实录5.1 错误ORA-00265需要实例恢复无法修改归档模式这个错误一般出现在执行ALTER DATABASE ARCHIVELOG时报错信息类似“Instance recovery needed to open database”。原因是之前有实例不是干净关闭比如用了shutdown abort控制文件里记录着需要实例恢复的状态。出现这种情况先别慌也不用去把归档模式硬怼上。解决方案是先把数据库正常open一次让它完成实例恢复然后再走“shutdown immediate → startup mount → alter database archivelog → open”的流程。注意RAC环境下如果是正常的一套库所有节点都shutdown后基本不会出现这个错误出现这个错误十有八九是某个节点的实例没完全关闭还在跑或者处于abort状态。用srvctl status database -d dbname先确认所有实例状态是OFFLINE再操作。5.2 参数已设置但归档日志没生成我遇到过一种情况log_mode显示ARCHIVELOGv$log里的archived也显示YES但ASM目录里找不到归档文件。排查下来是LOG_ARCHIVE_DEST配置了两个路径第一个路径写满了第二个路径还没接管过来Oracle在等待第一个路径有空间实际表现为“归档好像没在写”。排查思路先看v$archive_dest检查每个目标的状态SELECT dest_name, destination, status, error FROM v$archive_dest WHERE statusDEFERRED OR error IS NOT NULL;有ERROR字段不为空的就是失败的目标。常见错误是“ORA-19809: limit exceeded for recovery files”说明FRA满了需要扩容或清理。还有一种情况是LOG_ARCHIVE_DEST_1设了路径但对应的ASM目录不存在Oracle不会自动创建目录结构归档进程会不断报错。解决办法是用asmcmd mkdir手动建目录或者干脆改用FRA方案让Oracle自己管。5.3 归档空间满导致数据库Hang住这是所有RAC归档问题里最严重的。FRA满了以后数据库会报ORA-00257: archiver error. Connect internal only, until freed然后实例会话基本全部被阻断等于雪崩。遇到这种情况第一反应不是去删归档而是先让数据库恢复可用状态。因为FRA满了数据库连正常查询都可能被阻塞。最快的办法是先扩容FRAALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE600G SID* SCOPEBOTH;如果磁盘组本身没空间了那就得赶紧用RMAN清理过期归档。注意此时DELETE ARCHIVELOG ALL可能也会因为归档进程卡死而影响性能可以先手动用asmcmd找到最老的归档目录删除几个小时的归档释放空间再让数据库缓过来再走正常RMAN流程。实际经验是尽量避免走到这一步。前面第四节的监控三板斧就是为这一刻准备的。5.4 节点间归档线程号与序列号不一致RAC天然每个实例一个线程thread节点1坏掉后用节点2的归档恢复时可能会遇到“线程1和线程2的seq顺序互相交织、看起来不连续”的情况这是正常现象。v$archived_log里每个线程的sequence#是独立递增的不会全局统一。实操中做恢复时要注意RMAN能自动识别各线程的序列号但手工做RECOVER DATABASE时Oracle也会自动找各线程对应的归档。容易出问题的是有人手动拷贝归档做异地恢复没按%t分目录全部堆一起结果Oracle找不到某线程的归档序列恢复中断。所以前面强调的LOG_ARCHIVE_FORMAT里带%t、归档目录按实例分开不是洁癖是必要设计。5.5 开归档前后一定要做的备份策略衔接开启归档模式之后数据库的一致性备份和非归档模式下的备份策略是两回事。非归档模式下做全库备份后不需要管归档归档模式下灾难恢复通常要求最近一次全备 全备之后的全部归档。所以开完归档第一件事是做一次全库备份作为归档历史的基准点否则之前的备份在归档模式下恢复会很尴尬——归档从开库那一刻才开始有备份如果在开归档之前那备份和归档之间出现断层恢复时可能无法恢复到最新状态。具体操作建议开归档的维护窗口内顺手冲一把RMAN全库备份然后立刻验证备份可恢复性。这一步多做几分钟后面恢复演练会省掉无数个凌晨三点。5.6 双节点归档路径不一致的典型症状如果当时配置时图省事节点1的LOG_ARCHIVE_DEST_1指向ARCH节点2的指向DATA平时看不出来因为各实例只写各自的路径。但一旦做RMAN恢复或者Data Guard的redo传输就会因为归档目录不统一而找不到文件。症状是节点1的日志正常节点2的日志也在生成但v$archived_log里name字段的路径前缀不一致备份脚本按一个路径匹配时漏掉另一部分。这类问题没有办法在开归档当时立刻暴露属于潜在的“定时炸弹”。所以我每次开完归档都会统一检查所有实例的v$archive_dest输出确保每个节点的目标路径一致。命令是SELECT instance_name, dest_name, destination, status FROM gv$archive_dest WHERE dest_name LIKE LOG_ARCHIVE_DEST_% AND destination IS NOT NULL;gv$视图跨实例返回一眼就能对比。6. 写在最后几点实战补充开RAC归档这事说难不难说简单也不算简单核心是把“为什么每步这么做”想清楚。再多说几个零碎的经验希望对你有用。第一个是加redo日志组大小。如果开归档后发现日志切换过于频繁比如每小时几百次而磁盘IO又不富裕与其加归档进程数量不如把redo log加得大一点。日志从200M加到1G切换频率直接降到原来的五分之一归档压力立刻缓解。改法就是ALTER DATABASE ADD LOGFILE THREAD 1 GROUP 4 DATA SIZE 1G;加完删除旧的组注意一次加一组、删一组别同一时刻把某线程的所有日志组删掉否则会报ORA-00349。第二个是ARCHIVE_LAG_TARGET参数。RAC两个节点负载不均衡时可能出现一个节点疯狂切日志、另一个节点半天不切一次。如果备库是ADG主库某个线程很久没有新归档备库那边的归档gap会越来越大。可以给ARCHIVE_LAG_TARGET设个值比如3600秒让每个线程最多一小时必须强制切换一次日志保证归档线基本齐平。第三个是别忘记开启归档后跟备份软件联动。如果用的是第三方备份软件比如NetBackup、CommVault开完归档要在备份策略里加上归档日志备份并且确认备份软件能识别新生成的归档路径和命名格式。我见过有人在数据库侧开了归档但备份软件那边的归档备份策略还指向旧路径导致备份每天都在报错愣是拖了半个月才发现。最后说一句掏心窝的开归档是个高频却又不允许出错的运维动作步骤本身不复杂复杂的是操作前的“设计”和操作后的“验证”。把环境检查、空间估算、参数统一、备份衔接这四个环节做扎实RAC开归档就是一件很稳的事反过来跳步骤图快早晚会在某一个凌晨被数据库hang住叫起来补课。希望这篇总结对你有实质帮助。如果你在操作中有别的坑欢迎交流我把自己踩过的坑写出来就是想让后来的人少踩一遍。