数据库 频道

PG的DOUBLE BUFFERING是更优秀的解决方案吗?

  关于PG在Shared buffers上的DOUBLE BUFFERING设计,一直是争议极多的。有一些搞PG的朋友认为这是PG充分利用OS CACHE的一种特殊设计,是PG数据库设计中比较优秀的地方。还有一些朋友则认为这是一种过时的设计,与当前数据库技术的发展潮流所相违背的。前些天有几个朋友谈到这个问题,希望我写篇位置表达下我的观点。

  以我这些年做数据库优化的经验来看,DOUBLE BUFFERING的设计如果算是一种技术上的进步,在这一点上我一直是不太认同的。众所周知,现在几乎所有的现代数据库产品都是用AIO/DIO等方式来访问底层存储系统,只有PG目前还通过BUFFER/CACHE来读取物理文件。随着现代硬件的发展,BUFFERED IO的劣势越来越显现出来了。如果我们采用直接IO,绕过文件缓冲,那么就可以绕过BUFFER CACHE这一层,让数据从文件到内存更为直接,这会大幅提升OS到数据库缓冲的数据交换的吞吐能力,同时,因为DMA等技术的使用,可以让文件IO消耗的CPU资源更少,让系统更为高效。这对于大型数据库系统来说绝对是十分必要的。PG数据库越来越被用于大型OLTP系统,直接IO替代BUFFERED IO肯定可以有效增加大型系统的并发IO能力。

  另外一个方面,操作系统是无法充分理解数据库的PAGE访问逻辑的,因此操作系统缓冲的效率比较shared buffers而言,要低的多。两个分别由RDBMS和OS管理的分离的缓冲的效率肯定没有一个独立的数据库缓冲高,这个应该也是广大研发人员的共识。不过这句话成立的前提是数据库缓冲区被设计的十分高效,其LRU算法也被设计的十分合理。通过分析Oracle DB CACHE的算法的改进,我们也了解到为什么Oracle的DB CACHE能够保持那么高的DB CACHE命中率了。

  既然使用统一缓冲,消除DOUBLE BUFFERING那么重要,那么为什么PG还在坚持使用DOUBLE BUFFERING呢?这个原因十分复杂,实际上最近这些年里,PG社区也在这方面做着不断的努力。通过利用OS的AIO来替代当前bufmgr.c中的BUFFERD IO操作,不过PG的IO堆栈太长了,在大量的代码中都存在和buffered io相关的内容,再加上PG的文件结构导致的预读、连续块访问的IO合并等问题,要解决这个问题并不容易。在IO路径上,不仅仅需要修改bufmgr.c,在smgr.c,xlog.c,到底层的md.c,fd.c,甚至backend等模块中都有大量IO相关的代码需要修改。这些修改不仅仅是在调用文件IO时的函数调用的修改,还涉及到异步IO模式的修改,以及IO优化、预读等一系列的问题。因此这部分的修改中左虽然已经进行了数年,但是要出现在正是发布的版本中,依然还需要一定的时间。这也成为PG代码中的XID64之外的又一个老大难的问题。

  除此之外,在shared buffers的管理上,也需要做相应的优化,否则哪怕底层IO改为了AIO,buffer contention冲突也会让一个大型的统一的数据库缓冲的性能出现问题。比如在Oracle上遇到的buffer busy waits等待,可能会在PG上放大,从而在高并发访问时引发严重的性能问题。

  举个最简单的场景,那就是当多个backend需要访问相同的一组PAGE的时候,PG目前的管理算法上海经常会出现lwlock等待方面的超时等问题。而Oracle从9i开始已经优化了这方面的算法,当多个并发的会话访问相同的block的时候,首先为这个BLOCK申请db cache的会话会PIN住这个BUFFER HEADER,然后开始加载这个block(当然也包含IO合并以及预读,多块读方面的算法优化),其他并发访问相同数据的会话就会等待“read by another session”,这个等待事件是Oracle 10g才开始引入的,在9i中等待的依然是buffer busy waits,不过reason code(P3)参数是特殊的,从reason code可以缺别处这种特殊的热块冲突类型。当PG在这方面算法没有做优化之前,就无法区分这种情况,也就无法与AIO配合,达到最低成本的开销。

  PG消除DOUBLE BUFFERING,在技术发展上来说,是必须要做的事情,只不过因为历史欠债还是较多,这方面的改造工作量很大,需要一些时间来完成。一旦PG完成这个改造,将可以充分利用AIO的能力,大幅提升PG数据库读写的能力,从而让PG数据库真正向大型关系型数据库迈出一大步。目前我们有很多数据库企业都是基于PG生态在做研发,我也希望我们的数据库厂商能够在这方面多投入一些研发,为PG社区解决这个难题提供一些中国方案。

0
相关文章