记录在Oracle生产中归档爆满的事故

标签: Oracle, 数据库, 生产事故, DBA, 故障排查, 性能优化, 运维

前言

每个DBA的职业生涯中,总有那么几个不眠之夜,让你心跳加速,让你在海量日志和监控数据中奋力寻找那一线生机。今天,我想分享一次我亲身经历的、堪称教科书级别的Oracle生产事故。它从一个最常见的“CPU使用率100%”告警开始,最终却揭示了一个隐藏在系统深处的“定时炸弹”。我希望通过这次复盘,能给所有奋战在一线的技术同学带来一些启发和警示。

一、事故背景:风平浪浪静的周五下午
  • 时间: 一个周五的下午16:30

  • 系统: 公司核心CRM(客户关系管理)系统

  • 数据库: Oracle 19c RAC (双节点),部署在Linux服务器上

  • 业务特征: 7x24小时运行,读写并发高,是公司的生命线系统之一。

那天下午,一切如常。我正在整理下周的数据库巡检报告,心里盘算着一个轻松的周末。然而,运维的宿命就是,你越是计划周末,麻烦就越是会找上门。

二、告警响起

16:45,监控系统Zabbix突然爆出一连串刺耳的告警:

[High] Oracle Node 1: CPU Utilization > 95% for 5 mins
[High] Oracle Node 2: CPU Utilization > 95% for 5 mins

紧接着,应用团队的电话就打了进来:“我们的CRM系统响应非常慢,很多用户反馈页面卡顿,甚至无法登陆!”

我的心一沉,知道这绝对不是小问题。双节点CPU同时飙高,意味着整个数据库集群都处于高压状态。

三、第一轮排查:CPU、锁与慢SQL

这是DBA处理性能问题的标准流程,但这次,它却把我带入了一个“兔子洞”。

Step 1:确认服务器状态

我立即SSH登录到两台数据库服务器,执行 top 命令。果然,oracle 进程几乎吃满了所有CPU核心,us(用户空间CPU)和 sy(内核空间CPU)都异常高。

# top 命令输出摘要
PID   USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
12345 oracle    20   0   30.5g  25.1g  24.9g R  98.7 78.5  123:45.67 oracle_p001_...
12346 oracle    20   0   30.5g  25.1g  24.9g R  95.4 78.5  122:33.11 oracle_p002_...
... (大量Oracle进程CPU占用率极高)

Step 2:进入数据库,寻找元凶

我以 sysdba 身份登录数据库,开始排查会话和等待事件。

-- 查询当前活跃会话及其等待事件
SELECT sid, serial#, username, status, event, sql_id
FROM v$session
WHERE status = 'ACTIVE' AND type != 'BACKGROUND';

查询结果让我眉头紧锁。大量的应用会话处于 ACTIVE 状态,但等待事件却五花八门,最突出的是 latch free 和 log file sync。

  • latch free:通常意味着内部锁(latch)的严重争用,CPU飙高时很常见。

  • log file sync:表示用户session在等待LGWR(日志写入进程)将redo log buffer中的数据写入在线重做日志文件。这个等待事件的普遍出现,是一个非常危险的信号。

Step 3:AWR报告分析

我手动生成了一份过去15分钟的AWR(自动工作负载信息库)报告。报告结果如下:

  • Top Timed Events:DB CPU 排名第一,log file sync 和 latch: cache buffers chains 紧随其后。

  • Top SQL by CPU Time:排名第一的是一条非常简单的 UPDATE 语句,来自CRM的核心模块。这条SQL本身逻辑简单,执行计划也走了索引,平时执行效率极高。

这条 UPDATE 语句本身没有问题,但由于它被海量并发调用,在数据库整体性能恶化的情况下,它成了CPU消耗的“背锅侠”。

此时,应用团队、领导的电话和IM消息不断涌来,压力巨大。我尝试杀掉几个持有锁时间最长的会话,但无济于事,新的会话马上又会遇到同样的问题。

排查陷入了僵局。CPU高、latch争用、log file sync等待,这些都是症状,但真正的病根是什么?

四、峰回路转:从日志切换到归档空间

在巨大的压力下,我强迫自己冷静下来,重新审视 log file sync 这个等待事件。它意味着LGWR写入日志变慢或受阻。为什么会受阻?

我立刻去查看数据库的 alert.log(告警日志),这是Oracle DBA的“黑匣子”,记录了数据库运行的所有关键事件和错误。我从后往前翻,很快,一条关键的错误信息映入眼帘:

Fri Oct 27 18:35:10 2023
ARC3: Archiving not possible: No primary destinations available
...
Fri Oct 27 18:35:15 2023
Errors in file /u01/app/oracle/diag/rdbms/orcl/ORCL1/trace/ORCL1_arc2_34567.trc:
ORA-19815: WARNING: db_recovery_file_dest_size of 536870912000 bytes is 100.00% used, and has 0 remaining bytes available.

真相大白了!

问题的原因是:数据库的快速恢复区(Fast Recovery Area, FRA)空间被100%占满了!

事故的逻辑链条是这样的:

  1. 某个操作产生了海量的 redo 日志。

  2. 在线重做日志(Online Redo Log)被迅速写满,需要频繁切换并进行归档。

  3. 归档进程(ARCH)尝试将写满的在线日志归档到FRA。

  4. 由于FRA空间已满(ORA-19815),归档进程失败并挂起 (Archiving not possible)。

  5. 由于归档进程无法归档,写满的在线日志文件不能被覆盖和重用。

  6. LGWR进程在等待可用的在线日志文件,无法继续写入,导致所有提交(COMMIT)操作都在等待 log file sync。

  7. 大量的用户会话因为无法完成提交而挂起,持有各种资源(如latch),导致了严重的latch争用。

  8. 新来的会话请求资源时,因争用而空耗CPU,最终导致整个数据库集群CPU 100%,系统濒临崩溃。

这个原因解释了所有症状!CPU高是结果,log file sync 是中间环节,而 FRA空间耗尽 才是真正的罪魁祸首!

五、深挖根因:失控的“数据清理”定时任务

为什么FRA会突然被撑爆?我立刻检查归档日志的生成速度。

-- 查看每小时归档日志生成量
SELECT TO_CHAR(completion_time, 'YYYY-MM-DD HH24') AS hour,
       ROUND(SUM(blocks * block_size) / 1024 / 1024 / 1024, 2) AS gb
FROM v$archived_log
WHERE completion_time > SYSDATE - 1
GROUP BY TO_CHAR(completion_time, 'YYYY-MM-DD HH24')
ORDER BY hour;

结果令人震惊。从下午16:00开始,归档日志的生成量从平时的每小时10GB左右,飙升到了 150GB/小时!

我立刻联系了应用开发负责人,询问今天下午是否有任何上线或变更。一开始他们也一头雾水,但在我的追问下,一位年轻的开发工程师想了起来:

“哦,对了,我们今天下午上线了一个功能优化。为了解决CRM历史数据过多的问题,我们写了一个数据清理的存储过程,并通过DBMS_JOB设置了每小时执行一次,第一次执行时间就是下午16:00。”

我让他把代码发我。一看代码,我差点晕过去。这个清理任务的逻辑是:

这是一个一次性删除海量数据的大事务!HUGE_TRANSACTION_TABLE 是一个有数亿行记录的流水表。这个 DELETE 操作没有分批,没有加 NOLOGGING 选项(虽然对DELETE无效,但体现了开发者的意识),一次操作删除了上千万行数据,产生了天文数字般的 redo 和 undo,瞬间就把FRA给撑爆了。

六、紧急处理与业务恢复

原因找到了,接下来就是与时间赛跑。

  1. 紧急联系应用团队: 立刻停止那个该死的 DBMS_JOB!EXEC DBMS_JOB.BROKEN(job_id, TRUE);

  2. 释放FRA空间:

    • 登录RMAN,执行 CROSSCHECK ARCHIVELOG ALL; 确认物理文件与目录信息一致。

    • 执行 DELETE NOPROMPT EXPIRED ARCHIVELOG ALL; 删除过期的归档日志。

    • 最关键的一步:在确保备份有效的前提下,手动删除一部分较早的归档日志来快速腾出空间。DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-2'; (删除2天前的归档)。

  3. 监控恢复: FRA空间被释放后,挂起的ARCH进程立刻恢复工作,开始疯狂归档。

    • alert.log 中不再出现 Archiving not possible 的错误。

    • v$session 中的 log file sync 等待事件迅速减少。

    • 服务器的CPU使用率在10分钟内从100%降至了30%以下的正常水平。

  4. 业务验证: 应用团队确认,CRM系统恢复正常,用户可以正常登录和操作。

20:30,在经历了4个小时的紧张抢修后,系统终于恢复了平稳。办公室里响起了疲惫而又如释重负的掌声。

七、复盘总结与改进措施

这次事故虽然最终得以解决,但暴露出的问题是深刻的。我们在事后的复盘会上,制定了以下改进措施:

  1. 技术层面:

    • DBA: 将FRA使用率、归档日志生成速率加入核心监控项,设置更灵敏的告警阈值(例如,使用率超过80%就告警)。

    • 开发:

      • 严禁在生产环境中使用未经充分测试的大事务SQL。

      • 所有涉及大量数据操作(DELETE, UPDATE, INSERT)的代码,必须采用分批、小事务的方式进行,并加入适当的等待间隔,避免对数据库造成冲击。例如,使用 LOOP 循环,每次处理1000条记录后 COMMIT。

      • 加强对开发人员的数据库基础知识培训,让他们理解redo, undo的机制和影响。

  2. 流程层面:

    • 变更管理: 任何涉及数据库的变更,无论大小,都必须经过DBA的评审(Code Review)。特别是定时任务和数据处理脚本。

    • 测试流程: 类似的数据清理任务,必须在与生产环境数据量级相当的预发环境中进行充分测试,评估其对数据库性能(IO, CPU, Redo)的影响。

    • 应急预案: 完善此类故障的应急预案(SOP),当log file sync或FRA告警出现时,能有更快的反应路径。

结语

这次事故像一面镜子,照出了我们在技术、流程和沟通上的盲点。它提醒我们,在复杂的系统中,任何一个微小的、看似无害的改动,都可能通过一系列链式反应,最终演变成一场灾难。

排查问题时不能只看表面现象(如CPU高),而要深入挖掘等待事件背后的逻辑,alert.log 永远是你的第一手信息来源。对于开发同学,要敬畏生产环境,你写的每一行代码,都在“看不见”的底层消耗着实实在在的资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值