仅仅是个人对redo运行机制的理解,不对的地方,希望筒子们指出,共同学习。如果你想让你对redo的理解更加清晰,那么可以选择继续看下去。
redo存在的根本意义:
大家都知道数据库修改数据是在buffer cache中进行修改的,然而在commit之后,并不会马上写入数据文件(no-force-at-commit策略),因为这样零散的写出非常消耗资源,而且IO从来都是最有可能是性能瓶颈的地方,但是为了保证提交后的数据能够在故障后可以被恢复,这就产生了redo机制,通过将数据库的修改操作记录到redo log buffer中,写出到redo文件中,来推迟数据的写出,达到批量处理的效果,提高了效率。所以redo 对于数据库是极其重要的。
redo机制的组成:
redo机制,包含三大组件:redo log buffer,LGWR后台进程,redo log file日志文件(如果归档模式下还有arch后台进程以及归档
日志文件);
如果每产生一次redo就要写入到redo log file中,这同样也会产生IO的问题,同时在高并发的环境下还会引发redo log file的争用,所以就产生了 redo log buffer(oracle分配的一块内存区域,存在于SGA中,循环使用),但是该内存区域是循环使用的这就需要一个后台进程来不断的将log buffer 中的内容写出到redo log file中,这也就是LGWR的作用,同时 redo log file同redo log buffer一样也是循环使用的,那怎么来保证数据的安全性呢? 所以每次log switch的时候都会出发一次检查点,促使DBWR进程将写满的redo log file保护的脏数据写出到数据文件中,这样在检查点完成之后,redo log file 就变成了 inactive 状态,就可以被清空重用了。
redo 机制详解:
redo log buffer:
redo entries(redo 条目):包含了重构,重做数据库的变更信息,这些信息包括update,insert,delete,drop,alert,create 等;
一个redo 条目,是在用户全局区(PGA)中产生的,然后由oracle服务进程拷贝到redo log buffer中去,再一定条件下由LGWr后台进程写入到redo log file中。由于redo log buffer是共享的内存区域,在高并发的系统中,可能会出现redo log buffer争用的情况,这就产生了latch机制,log buffer由redo_allocation_latch保护,服务进程必须先获取到redo_allocation_latch才能分配相应log buffer;
redo条目写入到redo log buffer的过程如下:
1>redo并行机制:
高并发的环境下,必然会redo_allocation_latch的争用(redo log buffer 只有一个redo_allocation_latch),为了减少redo_allocation_latch的等待,在oracle9.2中,引入了log buffer的并行机制。
2>Share strand:
将log buffer划分成多个小的buffer,这些小的buffer称作strand,也叫shared strand,每个strand有一个redo_alloction_latch的保护,以前顺序的redo buffer的分配变成了现在的多个strand出现以后的并行的过程,大大提高了效率。
3>Priate strand:
为了进一步提高降低redo buffer的争用,oracle10g引入了一个新的机制---priate strand,priate strand不是在PGA中产生的,而是在share pool中分配的一块共享内存区域,每个priate starand由一个redo_allocation_latch保护,而每个priate strand只会服务于一个活动的事务,获取到priate strand的事务,不会再PGA中产生redo,而是在priate strand中产生,当flash priate strand或者commit的时候,priate strand将被批量写入到redo log file中;如果事务获取不到priate strand,那么将会继续遵循旧的log buffer机制,即shared strand,所以当告警日志出现Private strand flush not complete 可以选择忽略不管。
上面提到,priate strand会在flush/commit的时候直接写入到redo log file,而不经过redo log buffer,这就减少了对share strand的redo_allocation_latch的申请,提高了效率;
priate strand的过程如下:
注意:在没有获取priate strand的redo_allocation_latch成功的事务结束前,即使有其他的事物结束释放latch,该事物也不会再去申请priate strand的redo_allocation_latch;
LGWR后台进程:
Redo log buffer 是一块共享的循环使用的内存区域,LGWr就负责适时的将其脏的日志快释放掉,提供新的日志快供下次使用。其是顺序写入日志文件中,而不像DBWr那样随机写入,所以速度快的多;
LGWr的触发条件:
- commit/rollback语句操作的时候
- 当整个日志信息的数量达到日志缓冲区的1/3时,或者日志信息数量达到1M的时候会触发LGWr,这两个触发条件都是因为一个隐藏
- 参数_log_io_size来定的,所以如果LGWr触发频繁的情况,可以选择将该参数设置成3M,这样1/3和1M便成了一个触发条件了。
- 每个3秒触发一次
- 当DBWr被触发,写出数据之前,会判断该部分数据信息有没有记录到日志文件,如果没有,便会将需要写入日志的block放入一个
- 队列中,触发LGWr去写出,完成后DBWr才会继续写出数据到数据文件。
redo log file:
相关的视图:
SELECT * FROM v$log;
SELECT * FROM v$logfile;
SELECT * FROM v$archived_log;
SELECT * FROM v$recover_file;
SELECT * FROM v$log_history;
SELECT * FROM V$loghist;
重做日志文件状态:
- UNUSED :表示该联机重做日志文件组对应的文件还从未被写入过数据,通常刚刚创建的联机重做日志文件组会显示成这一状态。当日志切换到这一组时,就会改变状态
- CURRENT :表示当前正在使用的日志文件组。该联机重做日志组是活动的。当前Oracle数据库正在使用的联机重做日志文件组。
- ACTIVE : 表示该组是活动的但不是当前组,实例恢复时需要这组日志。如果处于这一状态,表示当前日志组正在归档,如果当日志切换的时候全备都是active状态,就会在告警日志中产生 checkpoint not complete信息,并且伴随着cannot allocate new log的错误信息, 反应到等待事件就是log file sync;
- INACTIVE:表示实例恢复已不再需要这组联机重做日志组了。表示对应的联机重做日志文件中的内容已被妥善处理,该组联机重做日志当前处于空闲状态
- CLEARING:表示该组重做日志文件正被重建(重建后该状态会变成UNUSED)。
- CLEARING_CURRENT:表示该组重做日志重建时出现错误。