串⾏到并⾏, Slave进程的引⼊
1 单库并⾏优化: LGWR->LGnn
在单实例的数据库当中主要是通过LGWR的进程的slave进程LGNN来实现的。
1、LGWR的作⽤:将redo buffer里面的内容写入到redo file里面,在单实例的数据库里面只有一个LGWR进程,当一个系统事务非常繁多的时候,如果这个时候只有一个LGWR进程进行写就会处于各种等待当中。因为LGWR进程造成的等待事件,从前台来说就是Log file Sync,从后台来看就是Log file parallel write
2、 LGWR相关的等待: Foreground: Log file Sync Background: Log file parallel write
3、 Log file Sync产⽣的原因:
commit 过于频繁? Log buffer 过⼤? CPU负载⾼?
4、什么时候会产⽣log file sync等待
1)commit操作
2)rollback操作
3)DDL操作(DDL操作实施前都会⾸先进⾏⼀次commit)
4)DDL操作导致的数据字典修改所产⽣的commit
5)某些能递归修改数据字典的操作:⽐如查询SEQ的next值,可能会导致修改数据字典。
Log file Sync 发⽣了什么
可以看到log file sync是从用户执行一个commit的命令开始,然后LGWR进程告诉用户已经执行完毕,这一整个过程就是log file sync的等待过程。
log file parallel write是指LGWR进程接受请求开始写到LGWR写完成。
Log file Sync的原因分析
可以看到实际上log file parallel write等待事件就是实际物理I/O的过程。
1,2阶段的时间,主要是post/wait的时间,典型的这种post/wait一般利用的是操作系统的信号量(IPC)实现,如果系统CPU资源充足,一般不会出现大的延迟。前台进程post lgwr后,就开始等待log file sync。
2,3阶段的时间,主要是lgwr为了获取cpu资源,等待cpu调度的时间,如果系统cpu资源充足,一般不会出现大的延迟。这里我们需要知道,lgwr只是操作系统的一个进程,它需要操作系统的调度获取cpu资源后才可以工作
3,4阶段的时间,主要是真正的物理io时间,lgwr通知os把log buffer的内容写入到磁盘,然后lgwr进入睡眠(等待log file parallel write),这个时间正常情况下的延迟占整个log file sync的大部分时间。还需要指出,lgwr在获取cpu资源后,可能并不能马上通知os写磁盘,只有在确保所有的redo copy latch都已经被释放,才能开始真正的IO操作。
4,5阶段的时间,os调度lgwr 重新获得cpu资源,lgwr post前台进程写完成。lgwr可能会post很多前台进程(group commit的副作用)
5,6阶段的时间,前台进程接受到lgwr的通知,返回cpu运行队列,处理其他事物(log file sync结束)。
C1是一个已经完成的事务,做了一个提交告诉LGWR要写日志了,LGWR要真正写日志之前是有一个等待的过程的,需要LGWR进程先获取CPU资源,在等待的过程当中,在log buffer里面没有为事务进行分区,当c1的事务处于等待的过程当中,c2,g1,c3这三个事务也在进行操作,也在同时使用redo log buffer的空间。这个时候会产生什么情况呢?在c1等待的过程当中,c2,g1完成了自己的事务就等待提交了,但是c3还没有完成。
Group commit的机制是当LGWR在写日志的时候,不是说c1提交的,只去写c1的这部分内容,而是会去寻找redo buffer里面的最高点,这里最高点是c3,这样LGWR就要将c1,c3,g1所有内容全部写进去。
给大家设定这样一个场景。
c1作为一个commit record已经被copy到了log buffer里,接着前台进程通知lgwr去写日志,根据我前面的描述,在前台进程post lgwr去写,到lgwr真正开始写之前,非常可能存在着时间差,就在这个时间差里,c2,g1,c3也已经把相应的日志拷贝到了log buffer里,其中c1,c2,c3是commit的记录,g1仅仅是普通的事务日志,不是commit日志。在lgwr真正开始写之前,它会去检查当前log buffer的最高点,发现在c3位置处,把这个点作为此次刷新日志的目标,把c1,c2,g1,c3的日志都刷新到磁盘。虽然刷新日志这个操作是由c1出发的,但是c2,g1,c3也是受惠者搭了便车,日志也被刷新到了日志文件里,这个功能叫组提交,对于一些不太熟悉ORACLE的人容易把组提交误解为,把提交的事物打包刷新到日志里,其实LGWR是不管你的事务日志有没提交的,它只按照log buffer分配的最高点来刷新,因此我觉得叫组刷新更好点。
图中c1,c2,g1的日志已经拷贝完成,我用filled表示,c3的日志空间已经分配,但是还没完成拷贝,我用allo表示,这个情况下,其实lgwr需要等待c3日志拷贝完成,才能真正的开始刷新操作。
GROPU COMMIT不是我们要去调整的方案,这个是oracle内部的机制,是不能调整的。可以理解为什么要这样做,如果每一个事务都要单独提交,如果这些事务都特别小,同时都在使用redo log buffer,这会导致大量短事务的提交,对系统影响特别大,group commit是为了避免小事务的频繁提交,但是也可能对系统造成负面的影响。
lgwr会post哪些前台进程?
当lgwr刷新完日志后,会post相应的前台进程(wakeup)继续工作,那么lgwr怎么判断应该wakeup哪些前台进程呢?
log file sync等待的p1参数的含义为:P1 = buffer# in log buffer that needs to be flushed
当lgwr刷新完buffer后,会扫描活跃会话列表,查看哪些会话在等待log file sync,而且会话的buffer#小于等于它所刷新的log buffer的最大值,这些会话会被wakeup。
/************************************** 可怜的LGWR***************************************/
如果有大量进程在等待LOG FILE SYCN,一旦LGWR写完成,它将POST这些进程苏醒,使它们重新进入CPU运行队列,而LGWR会被当初post它写日志的进程push off出cpu运行队列。这个情形下,由于LGWR已经工作了一段时间了(刚刚写完日志),而前台进程已经等待了一段时间了(等待LOG FILE SYNC),根据操作系统的默认的调度策略,这种情况下,前台进程将会有更高的优先级获取CPU资源,而LGWR将可能由于CPU资源突发式的紧张而没有获取到CPU资源,导致系统 的事务数有很大的降低:因为LGWR已经不工作了(虽然时间很短)。因此我前面所建议的调高LGWR进程优先级的手段是值得尝试的。
我们剖析了log file sycn的各个阶段后,可以看出,正常情况下,最慢的环节应该在3,4阶段(如上图),典型的io操作,这个环节对应的数据库等待叫做log file parallel write。其他的阶段如调度延迟、IPC时间一般都是极短的。网上、论坛上、包括不少书籍里,很多在log file sync出现问题后,往往都把责任推卸到IO慢的原因上。绝大多数情况下,这样的推断可能都是正确的,但是,事情不总是这样的,就像我们分析的,log file sync的快慢也是很依赖cpu资源是否富足、系统的负载是不是过大。这副图描述了,在CPU资源不足的情况下,各个阶段占取整个log file sycn的比重。
如你所见,由于CPU资源的不足、系统负载过大,导致操作系统调度出现了较大的延迟,3,4阶段的IO部分的延迟已经不是整个log file sync时间的最大的罪魁祸首!
在大部分情况下如果CPU资源充足,调度CPU的资源是相当快的,在大部分情况下影响log file sync的等待事件因素就是物理I/O。
如果CPU资源不足每次调度一次就会处于一次等待,这样会导致物理I/O不是最大的瓶颈,在调度CPU资源的时候远远超过了物理I/O写的时间。
在每一个实例当中都只有一个LGWR进程,如果经常处于等待,那么这是一个非常严重的问题。
真正物理I/O的过程表现的是log file parallel write的等待,如果是I/O存在瓶颈,那么log file parallel write的过程就非常长,通过这个等待事件可以判断是否是物理I/O的问题。
在大部分时候都需要调用CPU资源,如果CPU资源不足就会产生比较大的等待,log file sync=log file parallel write+各个阶段cpu调度时间,可以通过log file sync和log file parallel write时间差可以知道是是否是CPU资源影响的。
提高存储响应,降低单次log file parallel write等待时间,用比较高的存储存放redo file,或者使用闪存卡来存储。
12.1数据库LGWR有了slave进程LGNN,这个进程数量是一个范围