Oracle这几年发展太快了。从12C开始就很少参与运维工作了。我对此了解不多。做Oracle20多年,从5.1到11.2,到Oracle10G出来的时候,我说这应该是我学习的最后一个Oracle版本了。没想到,没有拥抱,11G又搞了10年。12C之后,因为没有一线运维,所以没怎么关注。前几天群里有小伙伴在讨论PGWAL写的性能问题。群里有朋友问,难道PG傻到不支持多个WALWRITER并发写入?当时想都没想就说,Oracle也不支持。早期Oracle支持LGWRSLAVER,但是因为bug太多,所以没有人用。12C之后好像就没有SLAVER这个东西了。当时那个朋友就纳闷了,Oracle怎么会不支持多个LGWR并发写入呢?后来问同事,他们说你好像记错了。12C之后,所有OracleSLAVER统一改为WORKER。LGWRworker在12C中自动启用。昨天刚好有点空闲,就找了一些关于12CLGWRworker的资料。在公司的测试环境中,我也找了一个19.15的环境,查看了一下。我发现,正如我同事所说,Oracle从12C开始就自动启用了LGWR并发写入。在12C中,增加了LGnn进程来真正写入REDO数据。LGWR根本不关心写入RedoLog文件,只负责发布一些关于将REDO放到磁盘上的消息。目前我没有看到太多关于LGWRworker的信息。从一些资料和我对LGWR的理解来看,LGWRworker应该和OracleRedoStrand有关。Oracle的LGWRworker都被分配到GROUPs。如果GROUP的个数与Redopublicstrand相关,那么每个group都不需要使用锁机制来同步写工作。LGWR不需要在多个worker之间进行协调,只需要分组相关的消息发布即可。这种机制应该是最有效的。如果在多个worker之间写REDO文件需要一个latch进行序列化,那效率肯定不会好。从Oracle11开始就使用RedoStrand来加速REDO性能,Strand的目的是提高并发写入RedoLogbuffer和RedoLog文件的性能,减少序列化latch等待带来的REDO性能问题。Oracle会根据CPU_COUNT的值自动调整Redosrands的数量。Oracle会根据CPU_COUNT/16设置strand的个数,根据strand的个数将LOGBUFFER分成N个子池。写入REDO数据时,可以并发写入不同的strand,可以降低高并发LOGBUFFER的写入性能。为了保证这个机制起作用,在RedoLog文件中,RedoLog文件也是按照Strand方式进行分配的。该模式允许高速并发写入RedoLog文件。RedoStrand为12C的LGWRworker调用默认启用的一个特性打下了良好的基础。我环境的CPU_COUNT是16,每个实例的RedoStrand最小值是2,所以实例启动的时候也启动了2个LGWRworker,也就是说数据库实例有两个LGWRworkergroup。当系统空闲,没有什么REDO数据需要写入时,LGnn在等待idle等待事件LGWRworkergroupidle,lgwr进程在等待rdbmsipc消息。通过strace看lgwr只是在做一些信号量操作。有空再看看LGnn吧。也睡在同一个信号量上。可以看到LGWR的等待事件发生了变化,LGnn的等待事件也和之前的LGWR非常相似。从等待事件的角度来看,当一个worker完成工作后,它会在Ordering中等待,等待获取另一个写入任务。具体实现算法上,并没有我想象的那样需要调度。让我们再次跟踪LGWR。可以看出,LGWR仍然非常频繁地操作信号量,这可能是因为LGWR正在积极参与日志写入的调度和协调。从工人的行为中,我们也可以看出与LGWR的互动。这说明Oracle的并发日志写入还是需要多进程之间同步,并不是完全自治和非阻塞的。因此,在某些场景下,当WORKER数量过多时,Logfileparallelwrite的等待时间可能过长,可能会导致LOGFILESYNC增加,影响数据库的性能。当Oracle的REDOSTRAND默认开启时,也会出现类似的问题,因为STRANDS的个数与CPU_COUNT有关。十多年前在Oracle11g上,有人发现当CPU数量很大时,logfilesync会莫名其妙的变坏。当时的建议是通过_log_parallelism_max参数来减少Strands的数量,解决Strands过多带来的性能问题。对于LGWRworker机制,Oracle也提供了一个类似的参数来控制,这个参数就是“_max_log_write_parallelism”。在Oracle12C或之后的版本中,经常会出现LGWRworker导致的性能问题。Oracle可以通过“_use_single_log_writer”参数进行调整。默认情况下,该参数的值为ADAPTIVE,即Oracle会根据工作负载来选择工作模式。如果遇到这方面的性能问题,可以将这个参数设置为TRUE,强制使用单个LGWR,即恢复之前的工作模式。如果你发现你的数据库从11G升级到12C后,日志文件同步变坏,导致一些性能问题,可以考虑调整这个参数。数据库的应用场景非常复杂。当我们在某些应用场景中受益于一项新技术时,必然会带来一些新的问题。有些场景可能不能很好地适应新技术。另外,在一些新技术刚刚开始使用的时候,针对一些特殊场景的算法优化不够,也会造成一些问题。我认为随着未来Oracle数据库版本的迭代,LGWRworker的机制会越来越成熟。其实我看到现在国内的一些数据库都在考虑使用多个WALwriter来提高高并发WAL写入的性能,从而充分利用SSD等现代硬件。但是WAL写对延时很敏感,如果算法写的不好,很容易造成比较严重的latch串行问题。Oracle的RedoStrand和LGWRworker的结合应该是目前最值得使用的方法。如果不对WALBUFFER进行Strand分区,多个WALWRITER的并发控制成本会更高。
