当前位置: 首页 > 科技观察

再说说PG的Buffer相关的锁,你懂吗?

时间:2023-03-16 01:37:07 科技观察

昨天刚下飞机,接到一个电话,说有个长辈去世了。今天一大早就坐高铁回老家去参加葬礼了。于是这篇前两天写的文章,今天在高铁上完成了。有些实验不方便做,只能简化。前两天有朋友说PG热块冲突比Oracle更容易发生,会造成严重的性能问题,尤其是系统中一些大热??表有大量UPDATE操作时。PG的ASTORE机制确实是使用了多个版本的TUPLE来保存一行的历史版本。这种机制使得PG的SHAREDBUFFERS的锁更加复杂。和小伙伴讨论问题后,根据之前学习的一些关于PGBUFFER的知识,画了一张思维导图。PG的BUFFER其实和三种锁有关。一种是SPINLOCK,用来管理BUFFER的空闲链。如果要分配一个空闲缓冲区,需要通过一个SPINLOCK(BufferStrategyLock)来获取。另外两种异构是我们比较容易理解的用于保护PG内存结构的锁LWLOCK。最后,异质性更令人费解。如果我们看一下PG的等待事件,里面有一个独特的分类。这种等待事件称为BufferPin,而在这一类等待事件中只有一种等待事件,BufferPIN。这些锁之间是什么关系?我们可以看看上面的思维导图。比如我们模拟一个BUFFER的生命周期。首先,当我们要访问某个PGPAGE时,需要从FREEBUFFER中找到一个BUFFER。这时候我们就需要一个SPINLOCK(BufferStrategyLock),然后将BUFFER从FREELIST中移除,为BUFFER做准备。使用新的PAGE。这时候我们就需要把这个BUFFERPIN起来,让它不能被BUFFER替换等操作使用。那么需要申请BUFFERCONTENT锁来修改BUFFER,通过加bufferheader锁修改BUFFERheader上的accesspointercounter等信息。然后开始读取页面的IO操作。这时候就需要获取BUFFERIO锁,表明该BUFFER正在进行IO操作,避免多个IO并发在同一个BUFFER上。IO结束后,BUFFER中已经包含了我们需要的页面。这时候我们需要把BUFFER加入到HASHCHAINS中。这时候就需要一个buffer映射锁,方便以后的BUFFER扫描定位。这个锁有点类似于Oracle的CBClatch,也是由多个锁分区来管理的,而PG是通过多个分区来提高并行效率的。我们来看一个例子:此时,我们在另一个会话中检查BUFFERPIN:我们可以看到一个BUFFER被PIN锁定了。如果我们此时执行VACCUM会怎么样呢?可以看出,VACUUM跳过了被pinned的BUFFER,因为PG不能对被pinned的BUFFER的PAGE进行VACUUM等不兼容的操作。这时候如果你做了一个不兼容的vacuumfreeze操作,它就会被锁定,你必须等待BUFFERPIN被移除。BUFFERPIN是一个共享锁,不会阻塞同一页上的并发写操作。但是这个共享锁还是会产生一些并发互斥的操作。例如,它会阻止VACUUM回收和排序这个PAGE,使VACUUM操作跳过ThisPAGE会阻止FREEZE操作,直到BUFFER中的PIN的所有锁被解除。由于PG数据库采用APPENDSTORE模式,一行的UPDATE会产生该行的多份副本,增加了对PG数据行的访问操作的额外开销。这里我们还需要考虑索引访问的开销。.如果这些记录副本都存储在同一个PAGE中,处理成本相对较低。PG使用HOT来降低索引维护和访问成本。如果多个TUPLE分布在多个PAGE中,那么这种开销的增加是不可避免的。如果我们应用系统中某些表的UPDATE非常频繁,那么这个额外的开销会更大。再加上访问数据时PG的各种锁的开销,这个叠加的开销就更大了。以VACUUM为例,如果我们的应用程序有bug,打开一个CURSOR后忘记关闭,或者死掉的session没有释放相关的CURSOR,那么一个或一些BUFFER会被长期pin住,并且VACUUM每次都会跳转这些PAGE,时间长了,就会出现一些莫名其妙的问题。希望今天看完这篇文章后,我们再看看PG等待事件中的BUFFER事件,让我们更准确的理解哪些等待事件代表什么意思,从而更好的定位问题。也正是因为PG的这个特性,我们才不能像使用Oracle那样肆无忌惮的使用PG数据库。如果我们做UPDATE操作,尽可能优化应用逻辑,尽可能减少一条数据的UPDATE次数。另外,对于UPDATE非常频繁的表,或者需要对很多列进行UPDATE的宽表,应该适当减小表的FILLFACTOR参数,尽量使用HOT来优化访问性能。另外,如果一个频繁更新的宽表可以拆分,那么尽量拆分成多个表。我和很多使用PG数据库的人交流过,有人说PG好用,我们用了PG之后系统一直很稳定。有朋友说经常踩坑。其实很多数据库都有各种坑。知道坑的存在,踩坑就不容易了。有坑不可怕,更可怕的是不知道前方有坑。