面试宝典:Oracle数据库latch: redo writing等待事件处理过程

在这里插入图片描述

Oracle 数据库 latch: redo writing 等待事件深度解析

1. 等待事件本质

  • latch: redo writing
    当LGWR(日志写入进程)或其他进程尝试访问重做日志缓冲区进行写入操作时发生的闩锁争用。该闩锁保护重做日志缓冲区在写入磁盘期间的完整性。
  • 关键特性
    • 直接关联LGWR进程活动
    • 保护重做日志缓冲区的写入操作
    • 高频率出现表明重做日志子系统存在瓶颈
  • 与相关等待的区别
    等待事件触发进程保护资源典型原因
    latch: redo writingLGWR为主日志缓冲区写入过程I/O慢/日志配置不当
    latch: redo copy用户进程日志缓冲区数据插入高并发DML
    log file parallel writeLGWR日志文件物理写入磁盘性能不足

2. 产生过程详解

LGWR进程Redo Writing闩锁重做日志缓冲区磁盘日志文件请求获取闩锁(准备写入)授予闩锁锁定缓冲区区域写入日志文件写入完成确认标记缓冲区可重用释放闩锁进入等待队列记录latch: redo writingloop[等待]授予闩锁锁定缓冲区区域写入日志文件写入完成确认标记缓冲区可重用释放闩锁alt[闩锁可用][闩锁不可用]LGWR进程Redo Writing闩锁重做日志缓冲区磁盘日志文件
  1. LGWR准备写入
    日志缓冲区满或超时触发写入
  2. 请求redo writing闩锁
    LGWR进程申请闩锁以独占访问缓冲区
  3. 冲突检测
    • 如果闩锁可用 → 立即获取
    • 如果闩锁被其他进程持有 → 进入等待
  4. 执行写入操作
    获取闩锁后,将缓冲区内容写入磁盘日志文件
  5. 清理缓冲区
    写入完成后标记缓冲区为可重用状态
  6. 释放闩锁
    完成所有操作后释放闩锁

3. 高频场景

高负载事务系统
-- 每秒数千次提交
UPDATE accounts SET balance=balance-100 WHERE id=123;
COMMIT;  -- 高频提交触发LGWR
大批量数据加载
-- 大批量INSERT产生海量重做
INSERT /*+ APPEND */ INTO sales 
SELECT * FROM sales_staging;  -- 未使用NOLOGGING
日志切换频繁
-- 日志文件过小导致频繁切换
ALTER DATABASE ADD LOGFILE GROUP 4 ('+DATA') SIZE 100M;  -- 建议1G+
归档模式下的延迟
-- 归档速度跟不上日志生成
ALTER SYSTEM SWITCH LOGFILE;  -- 触发归档
RAC全局缓存操作
-- RAC中的全局事务
UPDATE gs_table SET status='P' WHERE node=2;  -- 跨节点事务

4. 根本原因分类

I/O系统问题
问题类型典型案例
日志磁盘慢重做日志位于7200转HDD,而非SSD
I/O带宽不足存储网络仅1GbE,无法处理高峰日志量
日志文件争用所有日志组位于同一物理磁盘
数据库配置问题
  • 重做日志文件过小
    SELECT group#, bytes/1024/1024 size_mb FROM v$log;  -- <500MB
    
  • 日志缓冲区过大
    SHOW PARAMETER log_buffer;  -- >128MB导致写入延迟
    
  • 归档目标响应慢
    SELECT dest_name, status, error FROM v$archive_dest;  -- 状态ERROR
    
应用设计问题
  • 过度提交
    BEGIN
      FOR i IN 1..100000 LOOP
        INSERT ...; COMMIT;  -- 每次插入都提交
      END LOOP;
    END;
    
  • 未用批量操作
    UPDATE huge_table SET col=val;  -- 未分批更新
    
Oracle内部机制
  • LGWR写入延迟
    I/O子系统无法及时处理写入请求
  • Bug导致争用
    • Bug 13542050:11g中高负载下的redo writing争用
    • Bug 21382587:12c RAC中闩锁分配不均
    • Bug 29936857:19c中并行DML引发问题
  • 检查点风暴
    增量检查点过于频繁导致LGWR过载

5. 深度排查流程

步骤1:系统级诊断
-- 确认等待强度
SELECT event, total_waits, time_waited_micro
FROM v$system_event 
WHERE event = 'latch: redo writing';

-- 关联LGWR活动
SELECT 
    (SELECT value FROM v$sysstat WHERE name='redo writes') redo_writes,
    (SELECT value FROM v$sysstat WHERE name='redo write time') write_time
FROM dual;
  • 严重性阈值
    time_waited_micro > 60秒/分钟 + redo_writes > 1000/秒
步骤2:闩锁争用分析
-- 检查redo writing闩锁
SELECT 
    name,
    gets,
    misses,
    ROUND((misses/DECODE(gets,0,1,gets))*100,2) miss_ratio,
    sleeps
FROM v$latch 
WHERE name = 'redo writing';

-- 实时争用监控
SELECT sid, event, p1raw, state 
FROM v$session_wait 
WHERE event LIKE '%latch%' AND state = 'WAITING';
步骤3:LGWR性能分析
-- LGWR进程状态
SELECT process, status, seq#, blocks, delay 
FROM v$log_writer;

-- 日志文件I/O统计
SELECT 
    l.group#,
    l.thread#,
    f.member,
    i.bytes/1024/1024 size_mb,
    i.blocks,
    i.block_size
FROM v$log l
JOIN v$logfile f ON l.group# = f.group#
JOIN dba_data_files i ON f.member = i.file_name;
步骤4:日志配置检查
-- 日志组配置
SELECT group#, bytes/1024/1024 size_mb, members, status, archived 
FROM v$log;

-- 日志切换频率
SELECT 
    to_char(first_time, 'YYYY-MM-DD HH24:MI') time,
    sequence#,
    round(blocks*block_size/1024/1024) size_mb
FROM v$log_history 
ORDER BY first_time DESC;
步骤5:I/O性能诊断
-- 文件级I/O延迟
SELECT 
    file_name,
    phyrds,
    phywrts,
    ROUND((readtim*1000)/DECODE(phyrds,0,1,phyrds)) avg_read_ms,
    ROUND((writetim*1000)/DECODE(phywrts,0,1,phywrts)) avg_write_ms
FROM v$filestat
JOIN dba_data_files USING (file_id)
WHERE file_name LIKE '%redo%';

-- 操作系统I/O统计 (需OS访问)
$ iostat -dx 2 5  # 查看await和%util
步骤6:高负载事务分析
-- 高提交率会话
SELECT 
    sid,
    username,
    status,
    logon_time,
    last_call_et
FROM v$session
WHERE status = 'ACTIVE'
AND EXISTS (
    SELECT 1 FROM v$sesstat 
    WHERE statistic# = (SELECT statistic# FROM v$statname WHERE name = 'user commits')
    AND value > 100
    AND sid = v$session.sid
);

-- 重做生成排名
SELECT 
    sql_id,
    sql_text,
    executions,
    ROUND(io_interconnect_bytes/executions/1024) redo_kb_per_exec
FROM v$sql
WHERE io_interconnect_bytes > 0
ORDER BY io_interconnect_bytes DESC
FETCH FIRST 10 ROWS ONLY;
步骤7:高级诊断
-- LGWR进程追踪
ALTER SYSTEM SET events 'immediate trace name processstate level 10' sid = 'LGWR';

-- 闩锁转储
ALTER SESSION SET events 'immediate trace name latch level 10';

-- 检查Bug
SELECT patch_id, description 
FROM dba_registry_sqlpatch 
WHERE patch_id IN (13542050, 21382587, 29936857);

6. 根治方案

紧急处置
-- 临时减少提交频率
-- 推迟非关键批处理作业

-- 手动切换日志释放压力
ALTER SYSTEM SWITCH LOGFILE;

-- 增加日志组大小 (需重建)
ALTER DATABASE ADD LOGFILE GROUP 4 '+FAST_DATA' SIZE 1G;
ALTER SYSTEM SWITCH LOGFILE;  -- 切换到新组
ALTER DATABASE DROP LOGFILE GROUP 1;
I/O系统优化
  • 升级存储设备
    将重做日志迁移至NVMe SSD
  • 分离日志存储
    ALTER DISKGROUP FAST_LOGS ADD DISK '/dev/nvme0n1';
    ALTER DATABASE ADD LOGFILE GROUP 4 '+FAST_LOGS' SIZE 1G;
    
  • 优化RAID配置
    使用RAID 10替代RAID 5
数据库配置优化
-- 优化日志配置
ALTER SYSTEM SET log_buffer=64M SCOPE=SPFILE;  -- 合理大小
ALTER DATABASE ADD LOGFILE GROUP 4 '+DATA' SIZE 1G;
ALTER DATABASE ADD LOGFILE GROUP 5 '+DATA' SIZE 1G;

-- 调整LGWR参数
ALTER SYSTEM SET "_use_adaptive_log_file_sync"=FALSE;  -- 11gR2+ 关闭自适应
ALTER SYSTEM SET "_log_writer_parallelism"=4;          -- 18c+ 增加并行度

-- 优化检查点
ALTER SYSTEM SET "_disable_adaptive_log_file_sync"=TRUE;  -- 禁用自适应
应用层优化
  • 批量提交
    -- 每1000行提交一次
    DECLARE
      CURSOR c_upd IS SELECT ... FOR UPDATE;
    BEGIN
      FOR r IN c_upd LOOP
        UPDATE ... WHERE CURRENT OF c_upd;
        IF MOD(c_upd%ROWCOUNT,1000)=0 THEN
          COMMIT;
        END IF;
      END LOOP;
      COMMIT;
    END;
    
  • NOLOGGING操作
    ALTER TABLE sales NOLOGGING;
    INSERT /*+ APPEND NOLOGGING */ INTO sales ...;
    
  • 最小化日志操作
    CREATE TABLE new_table NOLOGGING 
    AS SELECT * FROM old_table;  -- 使用NOLOGGING
    
补丁与升级
  1. 关键补丁
    • Bug 13542050:应用11.2.0.4.210119+ PSU
    • Bug 21382587:安装12.1.0.2.220719补丁
    • Bug 29936857:19c中应用Jan 2023 RU
  2. 升级建议
    • 19c引入日志写入增强
      ALTER SYSTEM SET "_redo_transport_compress_all"=TRUE;  -- 压缩传输
      
架构级优化
  • RAC日志分离
    -- 节点1日志
    ALTER DATABASE ADD LOGFILE THREAD 1 GROUP 4 '+DATA_RAC1' SIZE 1G;
    
    -- 节点2日志
    ALTER DATABASE ADD LOGFILE THREAD 2 GROUP 5 '+DATA_RAC2' SIZE 1G;
    
  • 使用Standby重定向
    ALTER SYSTEM SET log_archive_dest_2='SERVICE=standby LGWR ASYNC';
    
  • In-Memory日志优化
    ALTER SYSTEM SET inmemory_size=10G;  -- 18c+特性
    

根治原则
解决latch: redo writing = 加速日志写入(I/O优化) + 优化日志配置(大小/组数) + 减少日志生成(批量提交/NOLOGGING)。
核心在于确保LGWR能够高效地将重做日志写入磁盘,避免进程在闩锁上长时间等待。

通过此方案可显著降低redo writing闩锁争用,提升数据库事务吞吐量。

欢迎关注我的公众号《IT小Chen

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值