暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

从DBA的角度看PostgreSQL的Buffer Manager

白鳝的洞穴 2021-01-15
1698
今天是PG大会开幕的日子,就聊点和PG相关的吧。PG的Buffer Manager在Hironobu SUZUKI大师的《The Internals of PostgreSQL》一文中有十分详尽的描述,后来不少国内网友也翻译了相关的章节,更有不少人通过PG的代码分析过Buffer Manager的算法。看到这个题目可能有些朋友会觉得老白又来炒冷饭了。是的,写一篇关于PG的Buffer Manager核心算法的文章,确实是炒冷饭,不过老白想从一个DBA的角度来重新炒一下这碗冷饭。
PostgreSQL的数据库缓冲叫shared buffer pool。PG的backend进程通过buffer manager模块来访问PG的数据,而Buffer manager通过shared buffer pool来提高PG数据访问的性能。
backend访问PG数据文件的过程和Oracle数据库十分类似,当backend要访问某个数据块的时候,会把需要访问的数据块的地址发送给buffer manager,如果这个数据块已经在shared buffer pool中存在,那么buffer manager会返回包含这个数据的buffer id返回给backend,如果当前buffer中没有这个数据块,那么backend 通过调用buffer manager去申请一个buffer,然后把数据块的数据读入buffer,返回buffer id给后续处理使用。当然这是最简单的场景,对于分配buffer,还涉及了脏块的处理等过程,这里就不深入分析了,这些过程和Oracle数据库的DB CACHE是十分类似的,ORACLE DBA很容易理解这个过程。
为了实现这个过程,PG的buffer manager分为三层:buffer table层、buffer descriptors层和buffer pool 层。buffer pool层是PG buffer的物理实现,PG的BUFFER和ORACLE一样,是一个固定长的数组,用于存放PG的数据块。buffer descriptors层也是一个数组,是存储BUFFER的元数据的层面,包含描述buffer及其状态的数据结构,此层的buffer描述和buffer pool中的数组是一一对应的。buffer table层是实现数据块寻址的,里面包含实现寻址的相关数据结构。整个体系如下图,这张图来自于著名的interdb.jp网站。

熟悉Oracle BUFFER CACHE的人可能比较容易理解这个过程,在Oracle中也是BUFFER HEAD(具体可参考X$BH)指向具体的BUFFER,而通过HASH CHAINS来实现数据块的寻址。
PG的数据块寻址也是通过HASH CHAINS的,这一点与Oracle类似。了解ORACLE的DBA应该很容易回忆起Oracle是通过一个32位的rdba来实现BUFFER定位的,其中10位是FILEID,22位是BLOCKID(BIGFILE TABLESPACE是32位的BLOCKID)。PG这方面复杂一些,是通过一个叫做buftag的数据结构来唯一定位某个数据块的。

buftag包含三个字段,rnode是一个RelFileNode的数据结构,包含了数据对象的inode信息;ForkNumber 为0表示该块是表或者索引文件的数据文件,1表示是freespace map的数据,也就是对应的_fsm文件,2表示是visibility maps的数据,对应的是_vm文件。BlockNumber是数据块的块号。因为PG的表空间结构和Oracle不同,所以PG的数据与具体文件的对应关系相对复杂一些,因此因为无法像ORACLE一样用一个32位的数值+一个表空间ID就能表示某个数据块的物理位置,这样会浪费一些内存空间,不过对于内存价格已经比较低的现在,内存已经完全不是问题了。

和Oracle的RDBA一样,PG的buftag能够唯一定位某个数据块的位置。通过Hash算法对buftag计算HASH值就可以获得这个buffer descriptor的hash bucket的桶号。

uint32 bucket_slot = calc_bucket(unsigned hash(BufferTag buffer_tag), uint32 bucket_size)

所有的已经装在到BUFFER中的数据块缓冲都被链接在hash桶中,每个BUCKET上都有一个链表,链接了该桶中的所有BUFFER。因为无论HASH BUCKET的数量有多大(比如超过BUFFER 的数量),也无法排除在一个BUCKET中链接多个BUFFER。这一点也是和Oracle的HASH CHAINS类似的。

上图是shared buffer pool刚刚初始化的示意图,hash table上都是空的,所有的buffer descritors都被链接在freelist上。

第一个数据块访问请求提交给buffer manager的时候,首先通过buftag算出hash bucket的位置,在hash bucket上看到是空的,于是从freelist分配一个buffer descriptor。然后从数据文件中读取该数据,放入这个buffer descriptor对应的buffer 中。

此时,BUFFER中就缓冲了这个数据块了,下回再访问这个数据块,就可以通过buftag直接定位到hash bucket,从而找到这个buffer了。

上面的截图都来自于Hironobu SUZUKI的原创,以上的算法描述也基本上基于Hironobu SUZUKI大师的资料。从一个DBA的角度来看PG的Buffer Manager,看到了一个和Oracle类似的buffer cache的算法。因此我们也可以推测,在Postgresql数据库中,肯定也会存在类似于Oracle db cache带来的一些并发争用问题,比如cache buffer chains闩锁等待,buffer busy wait等待等问题。

类似Oracle cbc闩锁的是一种PG的轻量级锁lwlock,这个锁的名字在PG的各个版本中可能有所不同,我们统一称之为buffer_mapping(BufMappingLock),这个轻量级锁用于HASH BUCKET的串行化访问。因为在每个buffer 访问中都需要使用这个锁,因此和Oracle一样,PG采用了分区锁的方式,将整个HASH TABLE分为多个分区(缺省位128个,不同版本缺省值会有不同),每个分区使用一个lwlock。

当有多个backend来访问buffer cache的时候,首先通过计算HASH值,找到HASH TABLE的位置,然后获得相关的BufMappingLock,才能去访问HASH TABLE,找到HASH CHAIN,最终找到对应的BUFFER。当两个BACKEND访问的BUFFER属于不同的分区锁控制的时候,不会产生冲突,反之就会产生冲突。前阵子我们在对瀚高数据库做压测的时候,也观察到了这个轻量级锁的冲突:

在11分钟的压测中,产生了110秒的BufMappingLock等待,占整个等待的0.255%,看上去PG的BufferManager的效率还是很高的,在每秒钟超过476万次的buffer 访问中,这个锁的等待只有110秒,平均每次等待为0.023毫秒,这个效率已经高于Oracle的CBS闩锁的效率了。从这里可以推断,在实际生产环境中,PG因为BufMappingLock导致的热块冲突会比Oracle少很多。

在Buffer Descriptor层,每个buffer_id有两个轻量级锁,content_lock 和 io_in_progress_lock,这里和Oracle是有些区别的,不过从原理上也十分类似。对应于Oracle的等待,等待这两个lwlock的等待类似于buffer busy waits和read by another session这两种等待。实际上在Oracle数据库里,Oracle 10g之前是对buffer busy waits分为集中类别,但是统一使用这个等待事件,Read by another session这个等待是buffer busy waits中的一个特例,就是说某个会话等待访问某个buffer的时候,这个buffer 的buffer descriptor已经产生,buffer pool也已经分配了空间,只是这个bufffer中的数据正由另外一个backend从数据文件中读取到buffer中,这个读取的IO还没有完成。PG的io_in_progress_lock是和Oracle的这个等待完全类似的,也许是PG借鉴了Oracle的思想。
我们再回过头来看上面的那个图中的buffer_content等待和buffer_io等待,对应的就是content_lock 和 io_in_progress_lock这两个lwlock的等待时间,可以看出,buffer_content等待大约是322秒,根据BufMappingLock等待估算一下,大约平均每次等待也只有0.06毫秒左右。在如此的并发下的buffer busy waits等待不到0.1毫秒,这种buffer cache的并发效率已经高于Oracle数据库了。
今天,中国PG大会就要召开了,在这里先表示下祝贺,明天下午,我也会到会场和大家一起分享一个PG数据库自动化运维的话题,广大PG FUNS们,明天广州见。

文章转载自白鳝的洞穴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论