PG的DOUBLEBUFFERINGonSharedbuffer的设计一直存在争议。有搞PG的朋友认为这是PG充分利用OSCACHE的特殊设计,是PG数据库设计的优秀部分。有朋友认为这是一种过时的设计,有悖于当前数据库技术的发展趋势。前几天有几位朋友谈到了这个问题,希望我写一篇文章表达一下自己的观点。从我这些年做数据库优化的经验来看,如果说DOUBLEBUFFERING的设计也算是一种技术进步的话,我一直不同意这一点。众所周知,几乎所有现代数据库产品都采用AIO/DIO访问底层存储系统,目前只有PG通过BUFFER/CACHE读取物理文件。随着现代硬件的发展,BUFFEREDIO的缺点越来越明显。如果我们使用直接IO来绕过文件缓冲,那么我们就可以绕过BUFFERCACHE层,让数据从文件到内存的传输更加直接,这将大大提高OS到数据库缓冲区的数据交换吞吐量。同时,由于DMA等技术的使用,可以使文件IO消耗更少的CPU资源,使系统效率更高。这对于大型数据库系统来说是绝对必要的。PG数据库在大型OLTP系统中的应用越来越多,directIO代替BUFFEREDIO当然可以有效提高大型系统的并发IO能力。另一方面,操作系统无法完全理解数据库的PAGE访问逻辑,因此操作系统的缓冲效率远低于共享缓冲区。由RDBMS和OS管理的两个独立缓冲区的效率肯定没有一个独立的数据库缓冲区高。这应该也是广大研发人员的共识。不过这句话的前提是数据库buffer设计得非常高效,它的LRU算法也设计得非常合理。通过分析OracleDBCache算法的改进,我们也明白为什么Oracle的DBCache能够保持如此高的DBCache命中率。既然使用统一缓冲和淘汰DOUBLEBUFFERING这么重要,为什么PG还要坚持使用DOUBLEBUFFERING呢?原因很复杂。事实上,近年来,PG社区也在这方面不断努力。目前bufmgr.c中的BUFFERDIO操作换成了OS的AIO,但是PG的IO栈太长,大量代码中有bufferedio相关的内容,pre-PG的文件结构导致的安装连续block访问的读取,IO合并等问题不容易解决,在IO路径上,不仅需要修改bufmgr.c,还有大量的IO相关的代码需要修改在smgr.c、xlog.c,到底层的md.c、fd.c,甚至后端模块。这些修改不仅仅是调用文件IO时函数调用的修改,还涉及到异步IO方式的修改,以及IO优化、预读等一系列问题。因此,虽然这部分修改已经进行了数年,但要在发布版本中出现还是需要一定的时间。这也成为PG代码中除了XID64之外的另一个老大难问题。此外,共享缓冲区的管理也需要进行相应的优化。否则,即使底层IO改为AIO,缓冲区争用冲突也会导致大型统一数据库缓冲区的性能出现问题。比如在Oracle上遇到的bufferbusywaits,在PG上可能会被放大,导致高并发访问时出现严重的性能问题。拿最简单的场景来说,当多个后端需要访问同一套页面时,PG目前的管理算法Shanghai经常会出现lwlock等待超时等问题。Oracle从9i开始优化了这个算法。当多个并发session访问同一个block时,先为这个block申请dbcache的session会PINBUFFERHEADER,然后开始加载block(当然包括IO合并和预读,多block的算法优化读),同时访问相同数据的其他会话将等待“被另一个会话读取”。这个等待事件是在Oracle10g中引入的,在9i中仍然是bufferbusywaits,但是reasoncode(P3)参数比较特殊,reasoncode中可以缺少这种特殊类型的hotblockconflict。PG算法在这方面没有优化之前,无法区分这种情况,无法配合AIO来达到成本开销最低。PG淘汰DOUBLEBUFFERING在技术发展上是必须要做的事情,但由于历史欠账还很多,这方面的改造工作非常繁重,需要一定的时间才能完成。一旦PG完成这个改造,就可以充分利用AIO的能力,大大提高PG数据库的读写能力,让PG数据库真正向大型关系型数据库迈出一大步。目前我们很多数据库公司都在基于PG生态做研发。也希望我们的数据库厂商能在这方面多投入研发,为PG社区提供一些中文方案来解决这个问题。
