一次归档日志把磁盘撑满的故障处理

周三下午三点,监控群里突然炸了:归档目录使用率 100%,LGWR 状态变成 WAITING,所有新会话都卡在连接阶段,老会话还在跑的业务也开始报 ORA-00257。这种故障处理过太多次了,但每次都很刺激,因为时间窗口极窄——归档一满,数据库就像被掐住脖子的鸭子,扑腾不了几下。

5.1 归档满后的连锁反应

很多人以为归档满了只是"日志没地方存",实际上它触发的连锁反应更致命:LGWR 写完当前在线日志后,需要 ARCn 进程把在线日志拷贝到归档路径,然后才能复用该日志组。归档路径满了,ARCn 写不进去,在线日志组全部处于 ACTIVE 状态,LGWR 找不到可用的日志组,只能挂起。这时候所有需要生成 redo 的操作(DML、DDL、甚至部分 SELECT FOR UPDATE)都卡住。更恶心的是,PMON 发现大量会话挂起后,会尝试清理死会话,但清理过程本身也要写 redo,于是 PMON 也卡住,形成死锁。

5.2 根因:不是空间不够,是监控没配

客户这套库其实有 2TB 的归档盘,但那天被一个临时 ETL 任务灌了 1.8TB 的归档,再加上 RMAN 备份脚本挂了三天没删过期归档,直接爆表。根因不是空间规划问题,而是监控阈值设得太高——告警阈值是 90%,但从 90% 到 100% 只用了 12 分钟(ETL 任务在跑大表 DELETE),DBA 根本来不及反应。

5.3 应急处理与模拟验证

-- 应急第一步:确认哪些日志组被卡住
SELECT group#, sequence#, bytes/1024/1024 mb, status, archived
FROM v$log;
-- 所有组都是 ACTIVE,archived = NO

-- 应急第二步:如果磁盘确实没空间了,先挪走部分旧归档
-- 注意:不要直接 rm,否则 control file 里的归档记录还在,会报 ORA-19625
-- 正确做法:用 RMAN 删除过期归档
RMAN> DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-1';
-- 但如果 RMAN 目录也满了,连 RMAN 都启动不了,那就只能 OS 层 mv 到别的盘

-- 应急第三步:临时扩容(如果用的是 ASM,可以加盘)
ALTER DISKGROUP ARCHDG ADD DISK '/dev/oracleasm/disks/ARCH04';

-- 应急第四步:切换日志,让 LGWR 继续
ALTER SYSTEM SWITCH LOGFILE;

-- 事后模拟:故意把归档文件系统填满到 99%
dd if=/dev/zero of=/archivelog/fillup bs=1M count=50000
-- 然后执行大量 DML,观察 LGWR 从正常到挂起的时间窗口
-- 实测:从 95% 到 100% 并触发 LGWR 挂起,只花了 4 分钟(业务高峰期)

那次恢复后,我们做了三件事:第一,把归档空间告警阈值从 90% 降到 75%,并且加了一个二级告警——如果 10 分钟内归档增长率超过 20GB,直接电话告警;第二,RMAN 的归档删除策略从 DELETE INPUT 改成 DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-2',并且每天中午跑一次,避免积压;第三,给 ETL 任务单独设了一个 ARCHIVE_LAG_TARGET = 0(不强制归档),但要求 ETL 必须在低峰期跑,且每次提交间隔不超过 10 万行,控制单次事务的 redo 量。

最后说句实在的:归档满这种故障,技术上没有难度,难的是流程和意识。很多 DBA 觉得"空间够大就没事",但生产环境的增长曲线是非线性的,一个临时任务就能把规划好的空间吃光。监控和预案比空间规划更重要。


请使用浏览器的分享功能分享到微信等