资讯动态

Oracle ORA-00257 归档日志与快速恢复区满处理实战

发布时间:2026/9/17 11:01:51 来源:尧图企业网站定制
1. ORA-00257 卡住的是归档链路不是数据库本身凌晨两点被电话叫起来业务侧反馈数据库连不上报错只有一个ORA-00257: archiver error. Connect internal only, until freed.。这个错误的迷惑性在于它看起来像是数据库坏了实际上数据库进程活得好好的只是归档进程被堵住了——归档日志写不下去整个实例就进入了只准特权用户进、其他会话一律拦住的保护状态。ORA-00257的本质一句话能说清归档目的地没有可用空间了归档进程写不进新文件于是数据库拒绝一切会继续产生归档的普通连接。它和普通应用报错最大的区别在于这不是某个业务逻辑出错而是数据库主动采取的熔断措施。理解这一点很重要因为它决定了你的处理顺序——先腾空间再谈修复而不是重启实例。这个场景我见过太多版本有人第一反应是shutdown abort重启结果重启后归档还是写不进去连数据库都起不来有人直接上 OS 层面rm归档文件结果控制记录和实际文件对不上后面做恢复时踩了更大的坑。这些做法的共同问题是没有先搞清楚空间被谁吃了、删哪些是安全的、删完空间多久会释放这三件事。下面这套处理思路适合任何从事 Oracle 运维的读者不管你是刚接手生产库的新人还是被这个问题反复打扰的老手。它覆盖了从定位、应急解封、到长期根治、再到版本差异的完整链条命令都是可以直接抄的。1.1 报错文本里的三个关键信息先拆报错本身。archiver error说明是归档进程ARCn出错不是 LGWR、不是 DBWR问题出在归档日志落盘这一步。Connect internal only是历史遗留说法现在等价于只有具备SYSDBA/SYSOPER权限的会话还能连上internal这个内建用户早在 10g 就被SYS接管了但错误提示文本一直没改。until freed是最关键的两个词——它是一个明确的条件只要释放了空间限制就会自动解除不需要重启实例。很多人忽略了自动解除这个点。你删完归档日志如果删除是有效提交的下一次归档进程成功写入时数据库就会放开通路应用不需要重启连接池也会自己恢复。反过来说如果你删了半天连接还是不通那就说明空间根本没被真正释放这是后面要重点讲的坑。1.2 吃空间的不只是归档日志归档目的地空间无论是文件系统还是快速恢复区里的住户有明确分类用V$RECOVERY_AREA_USAGE或V$FLASH_RECOVERY_AREA_USAGE能一次看全文件类型典型来源是否可自动回收ARCHIVED LOG归档日志满足删除策略后可回收BACKUP PIECERMAN 备份集片段按保留策略过期后可回收IMAGE COPYRMAN 数据文件镜像副本按保留策略过期后可回收FLASHBACK LOG闪回数据库日志超出DB_FLASHBACK_RETENTION_TARGET后自动回收CONTROL FILE控制文件副本控制文件自动备份产物REDO LOG在线/备用重做日志副本一般不能直接删我在现场遇到最多的一种情况是DBA 一直以为归档日志删了就完事了结果发现删完归档空间只降了一点点因为闪回日志和 RMAN 备份集片段占了更大头。尤其是开了闪回数据库的库闪回日志增长速度可以非常吓人而且它不在你手动删除的清单里。1.3 为什么数据库不自己清理归档这是被问得最多的反直觉问题既然知道空间要满为什么 Oracle 不自动删最老的归档答案是删除归档属于策略问题不是技术问题。Oracle 无法判断你的归档日志是不是还有用于恢复、Data Guard、审计追溯的价值所以默认只让你设置保留策略和删除策略由数据库按你给的规则去删。RMAN 里两条命令决定了这件事CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;决定备份保留多久CONFIGURE ARCHIVELOG DELETION POLICY TO BACKED UP 1 TIMES TO DEVICE TYPE DISK;决定归档被删的前提条件只有这两个策略配置到位再加上定期的DELETE OBSOLETE/DELETE ARCHIVELOG作业空间才能形成循环。没有删除策略的库本质上就是在等ORA-00257出现只是时间早晚的问题。2. 五分钟定位先搞清楚空间被谁吃掉应急处理最忌讳盲删。我在处理这类问题时前五分钟只做三件事确认归档目的地到底在哪、确认使用率、确认哪些文件是可回收的。这三步做完采取哪种处理方式基本就有答案了。2.1 确认当前归档目的地和使用率先看归档日志写到哪show parameter log_archive_dest show parameter db_recovery_file_dest show parameter db_recovery_file_dest_size如果LOG_ARCHIVE_DEST_n直接指向DB_RECOVERY_FILE_DEST那归档日志就受快速恢复区总配额限制db_recovery_file_dest_size这个参数就是硬上限。接着看实际用量select name, space_limit/1024/1024/1024 as limit_gb, space_used/1024/1024/1024 as used_gb, space_reclaimable/1024/1024/1024 as reclaimable_gb, number_of_files from v$recovery_file_dest; select file_type, percent_space_used, percent_space_reclaimable, number_of_files from v$recovery_area_usage;这里有两个数字必须分清space_used是实际占用space_reclaimable是符合删除策略、可以立刻回收的部分。我用经验值告诉你如果reclaimable_gb接近used_gb那基本可以安静地删归档解决如果reclaimable_gb很小而used_gb顶到上限说明你的删除策略没配好或者占用大头是闪回日志、控制文件副本这类不能随手删的东西。2.2 分清楚快速恢复区和普通归档目录不是所有库都用快速恢复区。有的老系统直接配置LOG_ARCHIVE_DEST_1LOCATION/u01/arch归档写到普通文件系统目录。这种情况下db_recovery_file_dest_size完全不生效限制来自文件系统本身。判断方法很直接archive log list;输出里如果Archive destination显示的是USE_DB_RECOVERY_FILE_DEST那就是快速恢复区如果是一个具体路径就是普通目录去 OS 上df -h看对应挂载点就行。这两种情况的处理方式差别很大。快速恢复区满你可以直接在线调大db_recovery_file_dest_size前提是底层文件系统有空间不需要动文件普通目录满调参数没用必须清理文件系统或者扩容量。我见过有人对着普通目录疯狂调db_recovery_file_dest_size调完发现一点用没有就是因为搞错了类型。2.3 用 RMAN 核对归档清单和控制记录定位的最后一步是进 RMAN 看一眼归档清单rman target /RMAN list archivelog all; RMAN crosscheck archivelog all; RMAN report obsolete;crosscheck这一步非常关键它会把控制文件里记录的归档和磁盘上的实际文件做一次比对。如果之前有人手动在 OS 上删过归档控制记录和实际文件就会不一致此时space_used的统计也会失真。crosscheck之后执行DELETE EXPIRED ARCHIVELOG ALL;数据库才能把那些记录里有、文件已不在的条目清掉重新算准空间。我个人的习惯是只要进去排查不管最终删不删文件先跑一遍crosscheck让数字可信。这一步花不了两分钟但能避免后面基于错误的数据做判断。3. 应急解封的三条路径按代价从低到高排定位清楚后解封手段无非三类扩容、删归档、处理文件系统。它们的适用条件和风险各不相同顺序上我建议先试最安全、影响最小的再往上加码。3.1 路径一先扩db_recovery_file_dest_size如果底层文件系统还有足够剩余空间这一步是最快、最无痛的解封方式alter system set db_recovery_file_dest_size200G scopeboth sid*;执行完这条命令归档进程下一次写入就能成功ORA-00257会立刻解除不用重启不用删任何文件。RAC 环境下加上sid*让所有实例生效。但我要强调的是这只是止血不是治病。扩容相当于把水桶换大进水速度不变的话迟早还会满。所以扩完之后必须立刻去补删除策略和清理作业否则你只是把告警时间往后推了几周。我见过一个库三年内被同一个问题叫醒七次每次都是扩一点、再扩一点从来没人去看reclaimable为什么一直是零。扩容还有一个前提经常被忽略底层文件系统得真有空间。如果 FRA 落在的挂载点本身已经 100%你调大参数也没用归档还是写不进去因为物理上没有块可分配。3.2 路径二RMAN 删除已备份归档如果reclaimable空间足够直接删归档是更健康的做法因为它走的是数据库认可的逻辑删除流程控制文件记录会同步更新RMAN delete noprompt archivelog all completed before sysdate - 1;或者按时间点删RMAN delete noprompt archivelog until time sysdate - 7;noprompt是必须带的。不带这个参数RMAN 会逐条询问确认删除吗一百个文件就是一百次交互在紧急情况下这是灾难。我甚至建议把它写进所有自动化脚本避免半夜手工敲命令时被卡住。另一种更精准的方式是先删过期、再删备份过的RMAN crosscheck archivelog all; RMAN delete noprompt expired archivelog all; RMAN delete noprompt archivelog all backed up 1 times to device type disk;最后这条命令依赖ARCHIVELOG DELETION POLICY的配置如果策略没配它会报错提示你没有删除策略。这时候要么先去配策略要么用UNTIL TIME这种显式条件来删。两种方式都安全前提是你确认那些归档已经被备份过、且恢复窗口不再需要它们。3.3 路径三归档落在普通文件系统时的处理如果归档目的地是普通目录而不是 FRA处理逻辑就变成先保归档、再腾空间RMAN backup archivelog all format /backup/arch_%U delete input;delete input会在备份成功后自动删掉源文件这是我最推荐的方式——备份和清理一步完成安全性最高。如果你只想要空间、不在乎备份也可以先backup再手工删但手工删只能通过 RMAN 的delete archivelog不要用 OS 的rm。3.4 为什么我不建议在 OS 上直接rm归档这是踩过最多次的坑。直接在 OS 上rm /u01/arch/*.arc确实能让文件系统空间立刻释放ORA-00257也会解除但代价是第一控制文件里的归档记录还在RMAN 执行list archivelog时仍会列出这些文件后续做restore或recover时会报ORA-19625: error identifying file报错行还会指向那些已经不存在的老归档。第二FRA 场景下space_used的统计会长时间不准确。Oracle 不会实时扫描目录你删了文件它不知道得等到下一次crosscheck或者控制文件自动清理才更新期间你看到的空间已满完全是虚的会误导你继续扩大配额。第三如果你开了 Data Guard从库可能还需要这些归档做RECOVER删掉就直接断档了。一句话OS 层删文件是最后手段只在数据库完全起不来、RMAN 也连不上、十万火急的情况下用用完必须立刻进 RMAN 跑crosscheck delete expired把账对上。4. 根治思路让空间自己循环起来应急处理只解决当下真正让ORA-00257不再复发的是让归档空间形成产生—备份—过期—删除的闭环。这一节讲的配置值得每个生产库都检查一遍。4.1 保留策略和删除策略必须配套两个策略是相互配合的只配一个等于没配RMAN configure retention policy to recovery window of 7 days; RMAN configure archivelog deletion policy to backed up 1 times to device type disk;retention policy决定了 RMAN 认为哪些备份还需要保留archivelog deletion policy决定了归档日志在什么前提下可以被删。第二条是防止归档堆积的关键——它告诉数据库只要这份归档被成功备份过一次它就不再是恢复链上的必要条件可以删了。如果是 Data Guard 环境删除策略还要加上应用条件RMAN configure archivelog deletion policy to applied on all standby;这样归档只有在所有从库都应用完才允许删。我见过主库空间爆掉、排查半天发现是从库网络抖动导致归档传输积压、而删除策略又没考虑从库状态主库只能忍着。这类问题的根因往往不在数据库本身而在归档传输链路的稳定性。4.2 定时作业怎么设计才靠谱策略配好后需要有人或脚本定期执行删除动作。我一般用两个作业错开跑每天凌晨备份作业backup archivelog all delete input落到独立备份盘每天凌晨删除作业delete noprompt archivelog all completed before sysdate - 2加一点缓冲两者的时间点拉开比如备份 01:00 跑删除 03:00 跑避免删除时正好有备份在读取文件。删除操作如果碰到正在被备份读取的归档会等待或者跳过造成清理不彻底这一点在后面坑的章节还会细说。脚本里我强烈建议加日志和退出码判断不要静默执行。归档清理这种后台任务出错了没人知道就等于没跑。rman target / log/home/oracle/rman_del_$(date %F).log EOF crosscheck archivelog all; delete noprompt expired archivelog all; delete noprompt archivelog all completed before sysdate - 2; exit; EOF4.3 监控阈值设多少才不误报也不迟报监控是最后一道保险。我的经验是按百分比分级告警而不是按绝对值使用率级别建议动作70%通知观察趋势检查清理作业是否正常80%警告手工确认 reclaimable必要时提前清理90%严重立即介入准备扩容或加急清理95%紧急按应急流程处理防止业务中断监控项建议同时采space_used和space_reclaimable因为 90% 占比但全是可回收空间和 90% 且 reclaimable 为零危险程度完全不是一个级别。只看一个数字会误导判断这一点在实际运维里极其重要。4.4 Data Guard 场景的额外注意点主从架构下异步传输的从库可能是拖后腿的一方。如果从库端落后太多主库的log_archive_dest_2会积压ARCHIVED LOGFRA 增长会比单机快得多。排查时要同时看select dest_id, status, error, gap_status, archived_seq# from v$archive_dest_status where dest_id 2;gap_status出现GAP或者status是ERROR基本就说明传输有问题。这时候先修传输别急着删主库归档——删了从库就彻底追不上了。处理顺序永远是先保恢复链完整再考虑空间。5. 最容易踩的四个坑删了归档空间却没释放这一节全部来自实际踩坑经历理解它能帮你少走很多弯路。5.1 控制记录没同步空间统计是假的第一种情况手工在 OS 上删过归档或者用mv把归档挪到了别的地方。这时候V$RECOVERY_FILE_DEST.SPACE_USED仍然按老数据算你以为删了 50G参数显示还是满的然后开始怀疑人生。解决办法就是前面说的crosscheck delete expiredRMAN crosscheck archivelog all; RMAN delete noprompt expired archivelog all;执行完这两条控制文件里那些记录存在但文件不在的条目被清掉空间统计立刻校准。所以任何时候看到删了但没释放第一时间先跑 crosscheck而不是继续删。5.2 闪回日志和控制文件自动备份也在占地方第二种情况归档明明删干净了space_used就是居高不下。这时去看V$RECOVERY_AREA_USAGE的分布select file_type, percent_space_used, percent_space_reclaimable from v$recovery_area_usage order by percent_space_used desc;如果FLASHBACK LOG占比很高说明是闪回数据库在攒日志。它按DB_FLASHBACK_RETENTION_TARGET单位分钟保留到期自动清你手动删不了也删不掉。如果确实不需要闪回功能关掉它是最直接的解法alter database flashback off;关闭前要确认你没在用还原点V$RESTORE_POINT有还原点的话关不掉得先DROP RESTORE POINT。这是我踩过的坑闪回关了但还原点还在最后不得不先清理还原点才彻底释放。CONTROL FILE类型的占比看起来不大但如果你开了CONFIGURE CONTROLFILE AUTOBACKUP ON每次备份都会生成一份控制文件副本日积月累也是几 G 的量。它随备份集一起过期一般不用单独处理。5.3 删除操作被备份作业阻塞第三种情况脚本跑完了日志看着成功空间就是没降。原因很可能是删除时正好有备份在读取这些归档RMAN 为了保证备份一致性会把正在被读取的文件跳过或者延迟删除。判断方法是在删除日志里找skipping或者not deleted这类关键词。处理办法是把备份和删除的时间错开至少间隔半小时以上并且删除条件设成before sysdate - 2给正在进行的备份留出缓冲窗口不要删最近的生产归档。5.4 只扩容不清理问题只是被推迟第四种情况是最普遍、也最容易被忽视的每次报错就扩一次db_recovery_file_dest_size三年扩了七次从来没看过reclaimable为什么是零。这类库的问题在于根本没有形成清理闭环扩容的收益被持续增长的归档量吃掉。判断方法很简单——看space_reclaimable是不是长期接近零。如果是说明删除策略或清理作业一定有一个没生效光扩容治不了。真正要做的是回头去补第 4 节讲的那套策略配置。6. 版本差异与命令对照不同环境下的实操要点ORA-00257的处理逻辑在各版本大同小异但视图、参数作用域、容器边界这几个地方有实际差别值得单独拎出来说。6.1 视图和参数作用域的变化V$RECOVERY_FILE_DEST和V$RECOVERY_AREA_USAGE从 10g 起就存在是排查的绝对主力一直没变。但V$FLASH_RECOVERY_AREA_USAGE在新版本里基本被V$RECOVERY_AREA_USAGE替代两者信息重叠建议统一用后者字段更全。db_recovery_file_dest_size这个参数从 12.1 开始有个重要变化它可以在 PDB 级别单独设置形成每个 PDB 的 FRA 配额。多租户环境下如果某个 PDB 报ORA-00257你需要在对应容器里看清楚是 CDB 总配额满了还是这个 PDB 自己的配额满了。alter session set containerORCLPDB1; show parameter db_recovery_file_dest_size;在 11g 里没有 PDB 概念只能从实例级别看。所以在 11g 环境排查时直接看实例级参数就够了不用考虑容器切换。6.2 多租户环境下该连哪个容器这是一个很容易搞混的点。FRA 本身是 CDB 级别共享的资源V$RECOVERY_FILE_DEST在CDB$ROOT里查到的才是全局使用情况PDB 里查到的配额只反映这个 PDB 允许占用的上限。所以多租户排查顺序应该是在CDB$ROOT里查V$RECOVERY_FILE_DEST确认全局是否顶到上限在报错的 PDB 里查show parameter db_recovery_file_dest_size确认是否是该 PDB 配额耗尽在CDB$ROOT里查V$RECOVERY_AREA_USAGE看是哪个 PDB 的归档贡献了大部分占用我遇到过 PDB 管理员反复在自己容器里删归档、删不动的情况根因在 CDB 层别的 PDB 把总配额吃满了。找不到总配额这一层问题永远解决不了。6.3 常用命令对照表把前面用到的关键命令整理成一张表应急时可以直接对照执行目的命令查看归档目的地show parameter log_archive_dest查看 FRA 使用率select * from v$recovery_file_dest;查看文件类型分布select * from v$recovery_area_usage;校准控制记录RMAN crosscheck archivelog all;清理失效记录RMAN delete noprompt expired archivelog all;按时间删归档RMAN delete noprompt archivelog until time sysdate - 7;备份即删除RMAN backup archivelog all delete input;在线扩容alter system set db_recovery_file_dest_size200G scopeboth sid*;配置保留策略RMAN configure retention policy to recovery window of 7 days;配置删除策略RMAN configure archivelog deletion policy to backed up 1 times to device type disk;这里面有个顺序上的个人习惯我也想分享一下进任何现场先crosscheck再delete最后才考虑alter system set。原因是 crosscheck 成本最低、信息量最大它能一次性告诉你控制记录和实际文件是否一致而扩容是不可逆地改变了配置应该是最后手段而不是第一反应。很多次我本来准备扩容跑完 crosscheck 发现只是记录没同步delete expired 之后空间直接降下来了参数根本不用动。最后再说一个实际用下来很省心的小技巧把FRA 使用率和reclaimable 占比做成一个每日巡检项用space_used / space_limit和space_reclaimable / space_used两个比值来监控。只要这两个数字的走势正常ORA-00257基本就不会来找你一旦 reclaimable 连续几天贴近零就说明清理链路哪里断了趁早处理比半夜被叫起来强太多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价