PG的锁咋弄得这么复杂呢

谈到锁,很多朋友和我抱怨过PG的锁的对外展现太过于复杂,很多初学者根本搞不懂,不像其他数据库,行锁、表锁,一目了然。Postgresql数据库是一种十分学院派的数据库,因为从本质上讲,PG是一种对象-关系型数据库,所以PG数据库的底层完全按照对象数据库来设计。为了贯彻对象特性,PG锁的基础是对象锁,所以从DBA的角度来看,就很复杂了。

如果你是一个Oracle DBA,那么你可能习惯于看dba_locks这样的视图,Oracle的锁划分的很细,有上百种锁,不过Oracle的锁机制的底层是统一的,都是Enqueue,所以从监控视图上,Oracle的所有锁都是统一的。Oracle的锁使用类型(TYPE),持有模式(MODE_HELD),申请模式(MOD_REQUESTED),参数1(LOCK_ID1),参数2(LOCK_ID2)等几个有限的字段统一表示所有的锁类型。

从DBA_LOCKS视图的结构上可以看出,Oracle把繁琐的锁用一个十分简单的数据结构来描述了。

相对而言,PG的pg_locks视图就要复杂的多,我们来看pg_locks这个PG用来展现锁情况的视图:

除了locktype和Oracle类似外,其他的字段都让人感到有些复杂。实际上这个和PG数据库的对象数据库的特性是有关系的。如果从对象层面来看,需要进行串行化处理的对象层次十分复杂,正是因为PG锁考虑了对象级的多个层面的东西,把所有的需要串行化的需求都归纳到有限的几类锁中(相对于Oracle锁的种类有上百种),因此要想把PG的锁完全统一起来并不容易。

我以前对PG锁的理解也比较肤浅,因为在绝大多数系统中,我们只需要关注事务锁就可以了。不过PG的事务锁也不那么直观,可能我们在pg_locks中会看到一些让人感到十分困惑的数据。

从我们现在的一个纯粹交易型的测试环境中,我们看到锁的类型有5种。

这些锁到底是什么含义呢?到底哪个才是行锁呢?是tuple吗?直到我认真的阅读了俄罗斯postgrepro公司的PG大师叶格尔-罗格夫关于PG锁的系列文章,才算从根儿上理解了PG的锁。从此再看到乱七八糟的PG锁就变得十分舒服和亲切了。从今天开始,我分几期把从叶格尔大师那里学到的知识给大家分享一下。

PG的对象级锁有很多种,上面是叶格尔文章中的截图,列出了PG中常见的对象级锁。对于锁的类型,不同的PG版本可能锁的种类略有不同。从等待事件中我们可以看到一些种类的锁产生的等待事件:

从广义上讲,PG把实现串行化的互斥机制都称为锁,所以PG锁实际上融合了Oracle数据库的ENQUEUE/LATCH/MUTEX等机制,所以相当复杂。当然大多数串行化共享内存操作的PG锁都使用了类似LATCH的LWLOCK,不过二者之间并不是完全等同的。要观察这些锁的情况,我们都可以通过pg_locks这个视图。因为不同的锁的实现方式都会不同,不同类型的锁的参数也不相同,所以pg_locks中的字段很多。有时候甚至会引起我们对行锁的分析都出现困难。关于行锁的详细分析今天因为篇幅问题,可能没有时间展开了,我会在后续的系列文章中一点点的展开讨论。以前在Percona上看到过一篇文章,里面有一个解析pg_locks的SQL语句。

SELECT pid, virtualtransaction AS vxid, locktype AS lock_type,mode AS lock_mode, granted,

CASE

WHEN virtualxid IS NOT NULL AND transactionid IS NOT NULL THEN virtualxid || ' ' || transactionid

WHEN virtualxid::text IS NOT NULL

THEN virtualxid

ELSE

 transactionid::text                                                                                                                                                                                           END AS xid_lock, relname,

page, tuple, classid, objid, objsubid

FROM pg_locks LEFT OUTER JOIN pg_class ON (pg_locks.relation = pg_class.oid)

WHERE  pid != pg_backend_pid();

用这条语句来解析PG_LOCKS后,我们看这些锁数据就舒服多了。下面来看一个例子:

关于virtualxid和TransactionID的区别我们明天的文章中再来分析,不同的锁的类型其参数是不同的。关系锁关联的是relations,而PG的事务锁都是针对事务的。

如果你以前是Oracle DBA那么理解PG锁的障碍来自于PG锁的类型划分与Oracle在维度上的不同。Oracle是按照功能来划分锁的,比如行锁(TX)、表锁(TM)、表空间锁(TT)、SEQUENCE锁(SQ)。而PG的锁是按照对象的粒度来划分的,把相同级别的不同对象划分为同类。除了行锁(transactionid)之外,其他锁的处理模式都是类似的,因为行锁的并发量巨大,因此针对行锁采用了独特的处理方式,以避免性能问题。

正是因为PG的锁十分复杂,因此今天我们重点来讨论关系型锁这种和运维与应用开发关系最为密切的锁。要了解关系级锁的细节,一定要首先了解锁的模式,PG的关系级锁有着相当复杂的锁模式,下面这个表格可以让我们快速理解复杂的锁模式。

Access Share是最弱级别的锁,这种锁是由select操作产生的,而Access Exclusive是最严格的锁,如果在关系上执行DROP/TRUNCATE等操作,会产生这种锁。我们如何来理解这张表呢?用一个最为简单的CREATE INDEX来做个示范吧。我们看到CREATE INDEX会持有SHARE模式的锁,这个模式兼容Access Share、Row Share和SHARE,因此多个CREATE INDEX可以并发执行,同时SELECT和SELECT FOR UPDATE操作可以不受阻塞执行。而INSERT/DELETE/UPDATE操作需要Row Exclusive模式的锁,会受到阻止。

今天因为时间关系,就先讲到这里吧,看到这里的朋友可能现在还是有点懵圈,不知道老白到底想要讲什么。我想把这个系列全部看完之后,一切都会明了的。明天南瑞要搞两年一度的子衿IT基础架构大会,我一大早要去参会,如果今天下午有时间,我会把第二部分写出来,明早发出。看完第二部分,大家就会明白我今天为什么要写这一篇了。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值