最近有朋友和我们交流PostgreSQL运维的问题,其中交流提纲里提到了关于Double Buffering的问题。对于以往习惯于使用Oracle数据库的人来说,不会体会到Double Buffering这个词的含义。很多Oracle DBA也认为Oracle天生就不需要考虑Double Buffering的问题的,只有PG/MYSQL这样的开源数据库才需要关心。事实上,Oracle也就是最近这十几年才彻底的解决了Double Buffering问题,采用完全绕过文件缓冲区的方法的,在我早期使用的Oracle版本中,如何利用文件缓冲提升大数据量的访问性能还是Oracle DBA能够用来挣钱的独门绝技,我也曾利用这个技能帮助用户做过一些优化项目。既然今天要讨论Double Buffering,那么我们就先用PG的一个IO分层结构图来理解一下PG的这个问题吧。
我们看到最上面的shared buffer是PG的主BUFFER,PG数据库使用bufferd io和OS的文件系统进行交互,因此PG数据库的读写都需要使用OS CACHE作为缓冲,读取的数据可以通过OS CACHE来进行加速,写入的数据先写入OS CACHE中,然后再通过fsync()来强制刷盘。在PG数据库里,我们要访问一个数据块可能会经过两个CACHE,一个是PG自己的SHARED BUFFERS,一个是OS的CACHE,这就是Double Buffering的含义。
Double Buffering有什么缺点呢?首先是增加了一个数据块访问的路径,数据块要先读入OS CACHE,然后才能到达SHARED BUFFERS,而这个PAGE在Shared Buffers中被多次使用,期间不再需要再次从文件中读取,因此OS CACHE中的缓冲的效率其实并不高,甚至可能会产生负面的作用。对于PAGE的写入也是如此,你不知道PAGE是写入文件了还是仍然存在于OS CACHE中,有时候我们必须通过fsync()来强制同步OS CACHE与文件系统。这种Double Buffering确实增加了PG数据库在cache管理上的复杂性。
实际上,PG数据库是能从OS CACHE上大大受益的,特别是写IO,写入OS CACHE的延时要远远低于直接写入文件系统。而对于一些访问十分频繁的热表,OS CACHE也是能够明显的提升IO性能的。而交给DBA的最为主要的问题是,我们如何管理好这个Double Buffering的环境。这种管理确实比Oracle这样的使用O_DIRECT访问的数据库要复杂的多,在Oracle数据库管理方面,我们只需要设置一个足够大的sga_target甚至Memory_target基本上就万事大吉了。而在PG数据库的缓冲区管理中,我们还必须考虑如何平衡Shared Buffers和OS CACHE。
在PG的官方文档中,建议PG数据库的Shared Buffers设置为物理内存的25%左右而不要设置的过高,这个建议主要还是为了平衡OS CACHE和Shared Buffers,让OS CACHE作为主缓冲,Shared Buffers作为副缓冲。对于一些不是很大的PG数据库,特别是服务器的内存不是很大的数据库系统来说,这是一个较为稳妥的设置方案。可以最大幅度的避免OS 换页带来的更大的性能问题。因此也有很多PG DBA认为shared buffers不宜设置过大,过大的Shared Buffers对PG数据库性能提升没有多大帮助。不过有很多用户用自身的体验驳斥了这种观点。通过加大Shared Buffers,提高Cache Buffer的命中率,获得了较好的数据库性能。有的DBA把超过75%的物理内存使用到Shared Buffers上,也获得了良好的使用效果。这种模式实际上是把Shared Buffers作为主缓冲,OS CACHE作为副缓冲。对于可以把应用中的绝大多数数据放到Shared Buffers里而不会产生OS的换页的运行场景,这种设置是十分有效的。
到时间来说说我们的观点了,对于PG的Double Buffering,网上的很多观点都有些偏颇,可能持这些观点的人面对的都是自己的系统,并没有关注过不同负载的数据库的需求。因此如果从一个较为全面的角度来说,在现阶段,PG内核还要依赖于OS CACHE来提升PG性能的前提下,Double Buffering依然是目前我们无法绕过去的问题。而对于大多数小系统来说,Double Buffering并不会给我们带来太大的烦恼,只要确保OS不换页,Doube Buffering的副作用是有限的,我们甚至可以完全忽视的。而对于大系统来说,设置多大的Sahred Buffers是我们需要去面对的头疼的问题,因为面对不同的应用负载,不同的个性化的系统,并没有一个十分明确的优化建议。不像我们在管理Oracle数据库那样,只需要确保物理内存足够,OS不换页的情况下,尽可能提高DB CACHE的命中率就可以了。在PG数据库中,90%的db cache命中率不一定比80%的db cache命中率有更好的运行性能,因为有可能有我们看到的90%的物理IO实际上是从OS CACHE中读取数据的。
基于Double buffering的问题,DBA需要根据自己维护的数据库系统,通过个性化的优化策略来评估DB CACHE和OS CACHE对系统带来的性能提升,才能更加正确的设置相关参数,让数据库体验的效果更好。对于大型的PG数据库系统,这一点尤为重要。实际上这对于DBA来说是一个福音,问题出现了,特别是不容易解决的问题出现了,那么体现DBA价值的机会就来了。就像老白当年调整OS CACHE/BUFFER为客户提升应用性能一样,这种服务都是客户愿意花钱来获得的。
实际上,解决PG数据库的Double buffering问题也并不是像想象的那么困难。注意好几点,大部分系统的这个问题都可以得以解决。首先,不要相信只能使用25%物理内存作为Shared Buffers这种固化的经验,因为每个系统都是个性化的,提高DB CACHE的命中率在绝大多数场景下都是有价值的。其次,需要针对OS的VM参数做更为精细的调整,包括脏块刷新的策略,这方面我在以前的好几篇文章里都做过阐述,这里就不重复讨论了,有兴趣的朋友可以去读读这些文章。最后,PG数据库实际上有很多解决这方面问题的插件,可以帮助我们提升OS CACHE的效率,比如针对性的进行OS CACHE/SHARED BUFFERS的预热等,在某些比较大型的数据库系统,比较复杂的应用场景下,这种预热十分有效。有兴趣的朋友可以去研究一下pgfincore这个开源插件,应该会有一些收获的。
作者:白鳝