Redo Log Buffer 与 LGWR 写入策略

Redo Log Buffer 与 LGWR 写入策略

适用版本:Oracle Database 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

Redo Log Buffer 是 SGA 中的循环缓冲区,缓存 Redo 记录,由 LGWR 进程异步写入 Redo Log 文件[1]。

作用

  • 减少 Redo 写入磁盘的频率
  • 批量写入提升 I/O 性能
  • 保证事务持久性(commit 时强制写)

2. Redo Log Buffer 结构

2.1 循环缓冲区

Redo Log Buffer (循环使用)

+----------------------------------------+
|  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓        ▓▓▓▓▓▓      |
|  ↑ 已写入                ↑            |
|  |                       |            |
| LGWR 写位置           进程分配位置    |
+----------------------------------------+

                        新 Redo 写入此处

2.2 大小配置

SHOW PARAMETER log_buffer;
-- 默认 14MB(19c)
-- 最小 64KB
-- 最大 与 OS 相关(通常 4GB)

大小建议

  • OLTP:64MB - 256MB
  • 高写入 OLTP:512MB
  • 不宜过大:影响实例恢复

3. Redo 记录结构

每条 Redo 记录包含:

字段说明
RBARedo Block Address(位置标识)
SCNSystem Change Number
Change Vector数据变更内容
Transaction ID事务标识
Undo 信息对应的 Undo 记录位置
Redo 记录示例:
RBA=(0x245, 0x400, 0x10), SCN=1234567890
Change #1: UPDATE block 4, offset 1024, old=1000, new=5000
Transaction ID: 0x0001.012.00001234
Undo: UBAn=0x0002.045.000005678

4. LGWR 写入触发条件

LGWR 进程在以下情况触发写入[1][2]:

触发条件说明
每 3 秒LGWR 定时唤醒
COMMIT用户提交时同步写
Buffer 1/3 满或 1MB 数据时
DBWn 写脏块前保证 Redo 先于数据落盘
日志切换强制写完所有 Redo

4.1 COMMIT 时的写入

用户 COMMIT:
1. 生成 commit 标记写入 Redo Log Buffer
2. LGWR 立即将 Redo Log Buffer 内容写入 Redo Log 文件
3. LGWR 等待 I/O 完成确认
4. 通知用户 COMMIT 成功
5. 释放事务锁

→ COMMIT 延迟 = Redo 落盘时间

4.2 DBWn 写脏块前

重要原则WAL(Write-Ahead Logging)

DBWn 在写脏块到数据文件前,必须确保对应的 Redo 已落盘:

DBWn 写脏块 B(修改自 Redo 记录 R):
1. 检查 R 是否已写入 Redo Log
2. 若否,触发 LGWR 写入
3. 等待 LGWR 完成
4. DBWn 写 B 到数据文件

5. Redo Log 文件结构

5.1 日志组与日志成员

Redo Log Group 1: [member 1.1, member 1.2]   ← 多路复用
Redo Log Group 2: [member 2.1, member 2.2]
Redo Log Group 3: [member 3.1, member 3.2]

循环使用:1 → 2 → 3 → 1 → 2 → 3 ...

5.2 状态切换

状态:
- CURRENT    : 当前正在写入
- ACTIVE     : 实例恢复需要,但未归档
- INACTIVE   : 已归档,可被覆盖
- CLEARING   : 正在清空
- UNUSED     : 从未使用
SELECT group#, sequence#, members, bytes/1024/1024 AS mb, 
       status, archived
FROM v$log;

6. 日志切换(Log Switch)

6.1 触发

  • 当前 Redo Log 写满
  • 手动执行 ALTER SYSTEM SWITCH LOGFILE
  • 设置 ARCHIVE_LAG_TARGET 强制切换

6.2 切换流程

1. LGWR 停止写入当前组
2. 切换到下一组
3. 触发检查点(CKPT 通知 DBWn 写脏块)
4. ARCn 复制当前组到归档目录
5. 当前组状态变为 INACTIVE

6.3 强制日志切换

-- 手动切换
ALTER SYSTEM SWITCH LOGFILE;

-- 设置归档延迟(强制 30 分钟切换一次)
ALTER SYSTEM SET archive_lag_target=1800 SCOPE=BOTH;

7. 相关视图

-- Redo Log 组信息
SELECT group#, thread#, sequence#, bytes/1024/1024 AS mb, 
       members, status, archived, first_change#, first_time
FROM v$log;

-- Redo Log 文件成员
SELECT group#, member, status 
FROM v$logfile;

-- Redo Log Buffer 统计
SELECT name, value 
FROM v$sysstat 
WHERE name IN (
  'redo entries',
  'redo size',
  'redo synch time',
  'redo synch writes',
  'redo buffer allocation retries',
  'redo log space requests',
  'redo log space wait time'
);

-- LGWR 等待事件
SELECT event, total_waits, time_waited
FROM v$system_event
WHERE event LIKE 'log file%';

8. 常见坑与排错

8.1 log file sync 等待严重

现象log file sync 等待事件占据 TOP 1。

原因

  • Redo Log 写入慢(磁盘 I/O 瓶颈)
  • LGWR 进程性能问题
  • 远程 Data Guard 同步延迟

修复

-- 1. 检查 Redo Log 磁盘性能
-- Linux:
-- dd if=/dev/zero of=/u02/test.dbf bs=8k count=10000 oflag=dsync

-- 2. 使用更快的存储(SSD/NVMe)

-- 3. 调整 Data Guard 同步模式
-- 改为 ASYNC 模式
ALTER SYSTEM SET log_archive_dest_2='SERVICE=stdby ASYNC' SCOPE=BOTH;

-- 4. 考虑 commit 写优化
-- 仅在低数据丢失容忍时使用
ALTER SYSTEM SET commit_write='NOWAIT,BATCH' SCOPE=BOTH;

8.2 Redo Log 切换过频

现象:每小时切换 > 10 次。

修复

-- 增大 Redo Log 文件大小
ALTER DATABASE ADD LOGFILE GROUP 4 ('/u01/redo04.log') SIZE 1G;
ALTER DATABASE ADD LOGFILE GROUP 5 ('/u01/redo05.log') SIZE 1G;

-- 删除旧的小日志组(先确保不是 CURRENT)
ALTER DATABASE DROP LOGFILE GROUP 1;

-- 推荐大小:每小时切换 3-5 次

8.3 checkpoint not complete

现象:日志切换时报 Checkpoint not complete

原因:检查点未完成时 LGWR 需要覆盖未归档/未写完的 Redo。

修复

-- 1. 增加日志组数(至少 4-6 组)
ALTER DATABASE ADD LOGFILE GROUP 6 ('/u01/redo06.log') SIZE 1G;

-- 2. 增大 Redo Log 大小
-- 3. 优化 DBWn 性能
ALTER SYSTEM SET db_writer_processes=4 SCOPE=SPFILE;

8.4 Redo Buffer 分配重试

现象redo buffer allocation retries 高。

原因:LGWR 写入速度跟不上 Redo 生成速度。

修复

-- 1. 增大 Redo Log Buffer
ALTER SYSTEM SET log_buffer=256M SCOPE=SPFILE;

-- 2. 优化 Redo Log 磁盘
-- 3. 减少 Redo 生成(如批量 NOLOGGING)

9. 最佳实践

  1. Redo Log 多路复用:每组 2-3 个 member,分布不同磁盘
  2. 合理大小:每小时切换 3-5 次
  3. 至少 4-6 个日志组:避免 checkpoint not complete
  4. 快速存储:SSD/NVMe 提升写性能
  5. 监控 log file sync:等待时间应 < 10ms
  6. 批量提交:减少 commit 次数
  7. Data Guard 用 ASYNC:避免同步影响主库
  8. 专用 Redo 磁盘组(ASM):独立 I/O

10. 参考资料

[1] Oracle Database Concepts 19c, “Redo Log Buffer” https://docs.oracle.com/en/database/oracle/oracle-database/19/cncpt/memory-architecture.html

[2] Oracle Database Administrator’s Guide 19c, “Managing the Redo Log” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/managing-redo-log-files.html

[3] AskTOM, “LGWR and Redo Log Internals” https://asktom.oracle.com/pls/apex/f?p=100:1:0