靓科技解读|PostgreSQL的全局死锁检测原理( 二 )


靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
现在 , 让我们看一个更具体的PostgresForeignServerCluster示例 。 在下图中 , 我们有两个外部服务器 , 它们充当了在上一张图中的从节点的角色 。 在主Postgres服务器上 , 我们创建一个分区表 , 在外部服务器A上部署一个分区 , 在外部服务器B上也部署一个分区 。 接着我们插入一些行 , 其中某些行在外部服务器A上 , 而其他行在外部服务器B上 。
分布式系统中的全局死锁检测器
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
接着 , 我们在两个并发会话上运行以下更新查询 , 我们可以看到两个会话都由于死锁而挂起 。 但是每个外部服务器上的本地Postgres死锁检测器却无法检测到它们 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
那么我们应该如何解决这种死锁问题呢?答案就是——在分布式系统中引入全局死锁检测器 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
在本演讲中 , 我们将提出一个关于如何在Postgresfdw集群中实现全局死锁检测器的想法 。 但是这个概念很普遍 , 可以作为对其他Postgres集群实现的参考 。 实际上 , 我们参考了Greenplum全局死锁检测器的实现 。 首先 , 将全局死锁检测器实现为Postgres的BackgroundWorker , 使其更兼容Postgres , 高可用等需求都可以通过Postgres的BackgroundWorker来实现 。 其次 , 我们提出使用集中式检测算法 , 这意味着我们只需要在主节点上启动一个工作进程来收集事务等待关系并定期检测死锁 。 请注意 , 在Postgres的本地死锁检测器中 , Postgres后端进程以自己为起点检测死锁 。 由于我们使用全局检测器 , 因此必须执行完整的等待图搜索以检测死锁 。 这需要一种更好的算法来检测死锁 , 因为Postgres的基于每个顶点的查找环算法并不高效 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
全局死锁检测器模块
1.等待图
全局死锁检测器仍会使用等待图来为锁等待关系进行建模 。 但与Postgres本地死锁检测有所不同的是 , 首先 , 等待图是基于整个集群 , 因此我们需要将每个外部服务器上的本地等待图进行合并 , 生成全局图 。 此外 , 该等待图中的节点并不再是单个Postgres进程ID , 而是一个进程组 , 我们使用分布式事务ID来表示一个等待图中节点 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
等待图中的节点具有四个主要属性:
分布式事务ID 。
出度边列表
入度边列表
锁等待者或持有者的pid和sessionid信息 。
从节点出发的是等待锁的 , 指向节点的是持锁者 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
2.等待图边
等待图中的边表示任何节点上的锁等待关系 。 边同样具有四个主要属性:
出度节点 , 持有锁 。
入度节点 , 等待锁 。
边类型:并非所有锁在事务结束时都被释放 , 例如 , xidlock可以提前释放 , 而无需等待分布式事务提交 。 我们将这种提前结束的等待关系使用虚边表示 。 与之对应的是实边 , 事务结束使才释放的锁等待关系 。 稍后 , 我们将展示全局死锁检测算法中对这两种边的不同处理 。
锁等待关系中的锁模式和锁类型 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片