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

5月26日 , 一年一度的PG开发者大会PGCon2020如约而至 。 与往年不同的是 , 受疫情的影响 , 今年的PGCon采取了线上会议的方式 , 虽然没有了面对面的交流 , 但在组织者DanLangille等的精心安排下 , 会议有了更广泛的受众 , 干货满满 。 来自Greenplum原厂的Greenplum内核工程师HubertZhang与AsimPraveen合作发表了演讲《DistributedSnapshotandGlobalDeadlockDetector》 。 在演讲中Hubert通过理论结合实例的方式讲解了Postgres单节点死锁和PostgresForeignServerCluster中实现分布式死锁检测的技术路线 。
现在让我们通过本文来回顾一下精彩的演讲内容吧!
在大数据时代 , 随着数据量的爆发式增长 , 对于分布式数据库的需求亦是水涨船高 。 作为最出色的开源数据库之一 , Postgres也在大力探索和发展分布式解决方案 。 其中 , PostgresForeignServerCluster是目前Postgres开发者邮件列表Pghacker中非常活跃的关于分布式Postgres的话题 , 该方案通过ForeignDataWrapper和分区表的技术 , 支持将逻辑分区表 , 物理的存储在多个不同的Postgres节点上 。 为了保证分布式环境中事务的ACID , Postgres社区正在积极开发基于ForeignServerCluster的分布式事务相关patch(https://commitfest.postgresql... 。
但对于分布式系统来讲 , 除了支持分布式事务 , 还需要考虑全局快照 , 全局死锁检测等问题 。 Greenplum作为分布式Postgres的先驱者和成功代表 , 在Postgres分布式执行的诸多领域都拥有成熟、稳定的解决方案 。 因此 , 本次演讲的作者Hubert借鉴Greenplum中全局死锁检测的原理和实现 , 探讨了在PostgresForeignServerCluster中如何实现一个高效的分布式死锁检测系统 。
单节点死锁原理
首先 , 让我们先来看一看单节点死锁 。 下图是一个单节点死锁的示例 。 假设有两个并发的Postgres会话 , 对应两个Postgres的后端进程 。 最初 , 进程1持有锁A , 进程2持有锁B 。 接着 , 进程1要获取锁B , 而进程2要获取锁A 。 由于锁通常在事务结束时才被释放 , 因此 , 本地发生死锁 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
Postgresql死锁检测器
Postgres使用死锁检测器来处理死锁问题 。 死锁检测器负责检测死锁并打破死锁 。 检测器使用等待图来为不同后端进程之间的等待关系建模 。 图的节点由进程标识符pid标识 。 节点A到节点B的边表示节点A正在等待由节点B持有的锁 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
Postgresql死锁检测器的基本思想如下:
如果获取锁失败 , 进程将进入睡眠模式 。
SIGALARM信号用于在超时后唤醒进程 。
SIGALARM处理程序将检查PROCLOCK共享内存以构建等待图 。 以当前进程为起点 , 检查是否存在环 。 环意味着发生死锁 。 当前进程会主动退出以打破死锁 。 Postgres死锁检测器可以处理本地死锁问题 。
靓科技解读|PostgreSQL的全局死锁检测原理
文章图片
分布式集群中的死锁
那么分布式集群中的死锁又是怎么样的?集群和单节点有什么区别?
【靓科技解读|PostgreSQL的全局死锁检测原理】让我们从一个例子开始进行讲解 。 下图中 , 我们有包含一个主节点和两个从节点的集群 。 假设我们有两个并发的分布式事务 。 首先 , 分布式事务1在节点A上运行 , 然后事务2在节点B上运行 。 接着 , 事务1要在由事务2阻塞的节点B上运行 , 因此分布式事务1将被挂起 。 同时 , 假设事务2也尝试在被本地事务1阻塞的节点A上运行 , 则分布式事务2也将挂起 。 这种情况下就会发生死锁 。
请注意 , 节点A或节点B上都没有死锁 , 但是死锁确实出现了 。 从主节点的角度来看 , 这就是所谓的全局死锁 。