分享一个案例,客户12c的数据库日志切换很频繁,把REDO LOG文件扩大2倍也还是一样。分析发现,该库并不繁忙,可是每小时的切换次数基本上在50次左右,但是每个归档文件的大小只有几十M,远低于REDO LOG文件大小。进一步分析后了解到了oracle LOG_BUFFER的一个机制,这里整理下分享给大家。
![Uploading file...]()
Oracle会根据CPU_COUNT/16来设定srand的数量,在LOG BUFFER中会按照SRAND数量划分为N个子池,写入REDO数据的时候,可以并发的写入不同的SRAND,这样可以减少高并发REDO BUFFER写入的性能。为了确保这一机制起作用,在REDO LOG文件中,也是按照srand的方式分配REDO LOG文件,实现某个srand的写入并不会影响其他srand并发写入redo log文件。
当redo log切换的时候,在新文件里会为每个srand都分配好一个分区,用于刷入这个srand的数据。以后某个srand写满后,再申请一个新的分区写入。当某个srand写入时文件满了,那么就会产生日志文件切换,没有写入的srand数据会在新的redo log文件中申请空间,完成写入。
这种机制可以大大提高REDO并发写入的性能,对于REDO量十分高的系统性能提升十分有帮助。不过针对这种情况,如果REDO LOG文件大小和LOG BUFFER设置不合理,就可能会导致一些问题。
我们回过头去看这个案例。这个数据库的log_buffer设置为900M,这是我见过的设置的最大的LOG_BUFFER了,根据Oracle的内存HEAP的定义,实际上这个LOG_BUFFER的大小为1GB,因为这个系统有256个CPU线程,因此SRAND数量为16,那么一个SRAND分区的大小也就是64M不到一点(有12M的附加,不同的版本不同,大概50多M),而REDO LOG文件的大小恰巧和LOG BUFFER一样,都是1G,因此每次日志切换,整个文件就马上被完全划分了。如果这时候系统负载不高,只有1个活跃会话在产生REDO,那么只有第一个SRAND会被使用,其他的SRAND都是空的。而这个SRAND分配的REDO LOG空间写完后,就会申请新的SRAN的继续写,如果写不下,就会立马进行日志切换,而不会管其他SRAND是否是空的。这样情况,一个REDO LOG文件就有15/16的空间被浪费了。这个现象和我们发现的情况完全一致。
要解决这个问题,只需要把Log_buffer调整到合理的大小就可以了。
示例:128个CPU,因此如果分配一个大小为128Mb的log_buffer,其中包含8个大小为16Mb的共享链。 它可能比 128Mb 稍大一点,因为它四舍五入到 SGA 颗粒边界。
日志文件是 100Mb,因此当 RDBMS 切换到新的在线重做日志文件时,每条链保留 100Mb/8 = 25600 个块,并且没有日志残留。如果系统负载较低,则只有一个重做链将处于活动状态/已使用,当该链的25600 个块被填满时,将调度日志切换
官方文档:Doc ID 1356604.1