0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

PostgreSQL的全局死锁检测原理

倩倩 来源:IT168 2020-07-25 11:27 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

5月26日,一年一度的PG开发者大会PGCon2020如约而至。与往年不同的是,受疫情的影响,今年的PGCon采取了线上会议的方式,虽然没有了面对面的交流,但在组织者Dan Langille等的精心安排下,会议有了更广泛的受众,干货满满。来自Greenplum原厂的Greenplum内核工程师 Hubert Zhang(张桓)与Asim Praveen合作发表了演讲《Distributed Snapshot and Global Deadlock Detector》。在演讲中Hubert通过理论结合实例的方式讲解了Postgres单节点死锁和Postgres Foreign Server Cluster中实现分布式死锁检测的技术路线。

现在让我们通过本文来回顾一下精彩的演讲内容吧!

在大数据时代,随着数据量的爆发式增长,对于分布式数据库的需求亦是水涨船高。作为最出色的开源数据库之一,Postgres也在大力探索和发展分布式解决方案。其中,Postgres Foreign Server Cluster是目前Postgres开发者邮件列表Pghacker中非常活跃的关于分布式Postgres的话题,该方案通过Foreign Data Wrapper和分区表的技术,支持将逻辑分区表,物理的存储在多个不同的Postgres节点上。为了保证分布式环境中事务的ACID,Postgres社区正在积极开发基于Foreign Server Cluster的分布式事务相关patch(https://commitfest.postgresql.。.。

但对于分布式系统来讲,除了支持分布式事务,还需要考虑全局快照,全局死锁检测等问题。Greenplum作为分布式Postgres的先驱者和成功代表,在Postgres分布式执行的诸多领域都拥有成熟、稳定的解决方案。因此,本次演讲的作者Hubert借鉴Greenplum中全局死锁检测的原理和实现,探讨了在Postgres Foreign Server Cluster中如何实现一个高效的分布式死锁检测系统。

单节点死锁原理

首先,让我们先来看一看单节点死锁。下图是一个单节点死锁的示例。假设有两个并发的Postgres会话,对应两个Postgres的后端进程。最初,进程1持有锁A,进程2持有锁B。接着,进程1要获取锁B,而进程2要获取锁A。由于锁通常在事务结束时才被释放,因此,本地发生死锁。

Postgresql 死锁检测器

Postgres使用死锁检测器来处理死锁问题。死锁检测器负责检测死锁并打破死锁。检测器使用等待图(wait-for graph)来为不同后端进程之间的等待关系建模。图的节点由进程标识符pid标识。节点A到节点B的边表示节点A正在等待由节点B持有的锁。

Postgresql死锁检测器的基本思想如下:

如果获取锁失败,进程将进入睡眠模式。

SIGALARM信号用于在超时后唤醒进程。

SIGALARM处理程序将检查PROCLOCK共享内存以构建等待图。以当前进程为起点,检查是否存在环。环意味着发生死锁。当前进程会主动退出以打破死锁。Postgres死锁检测器可以处理本地死锁问题。

分布式集群中的死锁

那么分布式集群中的死锁又是怎么样的?集群和单节点有什么区别?

让我们从一个例子开始进行讲解。下图中,我们有包含一个主节点和两个从节点的集群。假设我们有两个并发的分布式事务。首先,分布式事务1在节点A上运行,然后事务2在节点B上运行。接着,事务1要在由事务2阻塞的节点B上运行,因此分布式事务1将被挂起。同时,假设事务2也尝试在被本地事务1阻塞的节点A上运行,则分布式事务2也将挂起。这种情况下就会发生死锁。

请注意,节点A或节点B上都没有死锁,但是死锁确实出现了。从主节点的角度来看,这就是所谓的全局死锁。

现在,让我们看一个更具体的 Postgres Foreign Server Cluster示例。在下图中,我们有两个外部服务器,它们充当了在上一张图中的从节点的角色。在主Postgres服务器上,我们创建一个分区表,在外部服务器A上部署一个分区,在外部服务器B上也部署一个分区。接着我们插入一些行,其中某些行在外部服务器A上,而其他行在外部服务器B上。

分布式系统中的全局死锁检测器

接着,我们在两个并发会话上运行以下更新查询,我们可以看到两个会话都由于死锁而挂起。但是每个外部服务器上的本地Postgres死锁检测器却无法检测到它们。

那么我们应该如何解决这种死锁问题呢?答案就是——在分布式系统中引入全局死锁检测器。

在本演讲中,我们将提出一个关于如何在Postgres fdw集群中实现全局死锁检测器的想法。但是这个概念很普遍,可以作为对其他Postgres集群实现的参考。实际上,我们参考了Greenplum全局死锁检测器的实现。首先,将全局死锁检测器实现为Postgres的Background Worker,使其更兼容Postgres,高可用等需求都可以通过Postgres的Background Worker来实现。其次,我们提出使用集中式检测算法,这意味着我们只需要在主节点上启动一个工作进程来收集事务等待关系并定期检测死锁。请注意,在Postgres的本地死锁检测器中,Postgres后端进程以自己为起点检测死锁。由于我们使用全局检测器,因此必须执行完整的等待图搜索以检测死锁。这需要一种更好的算法来检测死锁,因为Postgres的基于每个顶点的查找环算法并不高效。

全局死锁检测器模块

1. 等待图

全局死锁检测器仍会使用等待图(wait for graph)来为锁等待关系进行建模。但与Postgres本地死锁检测有所不同的是,首先,等待图是基于整个集群,因此我们需要将每个外部服务器上的本地等待图进行合并,生成全局图。此外,该等待图中的节点并不再是单个Postgres进程ID,而是一个进程组,我们使用分布式事务ID来表示一个等待图中节点。

等待图中的节点具有四个主要属性:

分布式事务ID。

出度边列表

入度边列表

锁等待者或持有者的pid和sessionid信息。

从节点出发的是等待锁的,指向节点的是持锁者。

2. 等待图边

等待图中的边表示任何节点上的锁等待关系。边同样具有四个主要属性:

出度节点,持有锁。

入度节点,等待锁。

边类型:并非所有锁在事务结束时都被释放,例如,xidlock可以提前释放,而无需等待分布式事务提交。我们将这种提前结束的等待关系使用虚边表示。与之对应的是实边,事务结束使才释放的锁等待关系。稍后,我们将展示全局死锁检测算法中对这两种边的不同处理。

锁等待关系中的锁模式和锁类型。

全局死锁检测器工作原理

下面,通过全局等待图,让我们看看集群是如何处理全局死锁的。

基本思路如下:主节点上的Background Worker进程通过查询集群来定期建立全局等待图。接着,删除与死锁无关的节点和边。重复此过程,直到无法删除任何节点或边。如果仍然存在边,则也存在全局死锁,我们需要选择一个会话来取消。

接下来,让我们详细介绍上述步骤。

要构建等待图,我们需要在每个Segment上收集锁信息。这是一个两阶段过程。

1. 构建全局图

首先,它使用Postgres内部函数GetLockStatusData从PROCLOCK共享内存中获取锁等待关系。我们需要扩展lockInstanceData结构,以涵盖分布式事务ID和holdTillEndXact标志。之后,Background Worker进程需要从每个Foreign Server收集本地锁信息,并形成一个全局锁等待图。

每个本地锁等待图包括以下属性:Segment ID,锁等待者和锁持有者的分布式事务ID,标注其为实边或虚边,以及其他属性,例如pid,sessionid,锁类型和锁模式,涵盖了之前介绍的节点和边的四个主要属性。

2. 消除节点和边

下一步是消除不相关的节点和边。我们使用启发式贪婪算法。

有两种策略。一种是对全局图的贪婪,这意味着删除所有出节点度为零的节点,并删除其相应边。这是一个示例,在全局图上,节点D没有出度,因此将其删除。然后,节点C的出站度也更改为零,因此也删除了节点C。

另一种策略是在局部图上贪婪,这意味着找到每个局部图上的所有虚边。如果虚边指向节点的出度为零,则该虚线边表示的阻塞关系可能在事务结束之前消失,因此我们也可以消除这种虚边。

下图的示例中,节点C在全局图上的出度为1,但是在Server0的局部图上,出度为0,因此我们可以将从节点A到C的虚边删除。

全局死锁检测器的最后一步是打破死锁。集中式检测器不同于Postgres本地死锁检测器,后者只能退出当前进程,前者可以根据策略选择取消任何会话。通用策略包括取消最新的会话或基于CPU、内存等资源占用量的策略等等。

实例分析

至此,我们已经介绍了全局死锁检测器的概述和算法。最后,让我们看看另外两种实例,以便更好地了解全局死锁检测器的工作原理。

首先是数据准备工作,如下图所示。

案例一

第一种例子中,有三个并发会话。会话C首先更新ID=2的元组,这将使server1上持有xid锁。会话A更新val=3的元组,它将在server2上持有xid锁。接着,会话B要更新val=3或id=2的元组,它将分别被server1和server2上的会话A和会话C阻塞。最后,会话A要更新server1上val=2的元组。

请注意,当会话B无法获取server1上的xid锁时,它将持有元组锁,以确保在会话C释放xid锁之后可以拿到锁。会话A将在元组锁上被会话B阻塞。请注意,元组锁在分布式事务结束之前就会被释放,因此这是一个虚边。原始的全局等待图在左上角,可以看到全局等待图存在循环。

现在,让我们看看如何消除不相关的节点。首先,节点C的出度为零,我们可以删除该节点和相应的边。现在在Server1的本地等待图上,指向B点的虚边没有出度,因此也可以删除该虚边。删除虚边后,节点A的出度变为零,可以删除,最后也可以删除节点B。没有边,因此在这种情况下没有全局死锁。

案例二

下图的第二个例子中,包括三个并发会话。会话C首先将更新ID=2的元组,这将在server1上持有xid锁。然后,会话A将更新val=3的元组,它将在server2上持有xid锁。会话B要更新val=2的元组,它将被server1上的会话C阻止。

接着,会话A想要更新server1上val=2的元组。像上图的案例1一样,会话A在元组锁上被会话B阻塞,并形成虚边。最后,会话C要更新ID=3的元组,它将被Server2上持有xid锁的会话A阻止。原始全局等待图在左上角,全局等待图同样包含循环。

回想上一张图,案例1的全局等待图与案例2相同,唯一的不同是局部图。

现在让我们看看如何消除不相关的节点。首先,让我们检查全局图:没有出节点度数为零的节点,因此没有可以删除的节点。接下来,我们检查局部图上的虚边。从节点A到节点B,我们有一条虚边,但是节点B的出度不为零,因此无法删除该虚边。我们无法删除任何节点或边,因此在这种情况下消除失败,全局死锁存在。

从以上情况可以得出结论,即使全局等待图相同,它们的全局死锁检测结果也会有所不同。

总结

以上就是本次PGCon演讲的主要内容。回顾一下,本次演讲首先讨论Postgres本地死锁检测器的实现,并通过实例说明本地死锁检测器无法解决全局死锁问题,并进一步提出了在Postgres Foreign Server Cluster中实现全局死锁检测的思路和需要注意的问题。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 检测器
    +关注

    关注

    1

    文章

    924

    浏览量

    49656
  • 建模
    +关注

    关注

    1

    文章

    320

    浏览量

    62738
  • 进程
    +关注

    关注

    0

    文章

    208

    浏览量

    14478
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    请问C语言开发单片机为什么大多数都采用全局变量的形式?

    C语言代码,大多数都是使用全局变量,也就是用很多函数来操作这些变量,比如函数1把一个全局变量经过一系列复杂的算法计算后改变了这个全局变量的值,然后函数2再拿着函数1处理过的这个全局变量
    发表于 12-04 07:47

    I2C死锁的问题

    在实际使用过程中,I2C比较容易出现的一个问题就是死锁死锁在I2C中主要表现为:I2C死锁时表现为SCL为高,SDA一直为低。 在I2C主设备进行读写操作的过程中,主设备在开始信号后控制SCL
    发表于 12-04 06:00

    求助,关于全局中断使能的问题求解

    各位朋友大家好,我最近在使用蜂鸟的板子进行开发时,遇到了这样的问题:我的程序每次运行到使能全局中断的时候,就像进入了死循环一样,出不去了,如上图,首先先打印“GI_EN begin!”这里是可以
    发表于 11-07 06:37

    请问Modus Toolbox下针对CYW20719B2编程,能否指定全局变量地址?

    请问Modus Toolbox 下针对CYW20719B2编程,能否指定全局变量地址?
    发表于 07-08 07:20

    全局快门图像传感器技术的改进提升了机器视觉效率

    先进视觉系统应运而生,而高速、全画幅全局快门传感器是这些系统的核心。全局快门能够即时捕捉拍摄对象的完整视图,这非常重要。   基于全局快门的系统可以消除许多常见于视觉系统的视觉伪影(例如摆动、倾斜和空间混叠等),有助于
    发表于 05-20 16:18 1868次阅读
    <b class='flag-5'>全局</b>快门图像传感器技术的改进提升了机器视觉效率

    ST具有滚动和全局快门功能的510万像素RGB-NIR影像传感器 车舱监控的全能之选

    ST推出的VB1940和VD1940影像传感器,集成滚动快门和全局快门功能,具备510万像素的RGB-NIR成像能力,专为车舱内监控和大视场(FoV)应用设计。其创新的双模式设计和高动态范围(HDR
    的头像 发表于 04-10 16:38 884次阅读
    ST具有滚动和<b class='flag-5'>全局</b>快门功能的510万像素RGB-NIR影像传感器 车舱监控的全能之选

    展望PostgreSQL 18的新特性

    距离 PostgreSQL 17 正式发布已近半年,按照每年发布一个大版本的惯例,PostgreSQL 18 预计将在 2025 年底发布。距离正式发布还有一段时间,社区的开发工作仍在如火如荼地进行中。
    的头像 发表于 03-03 16:51 1392次阅读
    展望<b class='flag-5'>PostgreSQL</b> 18的新特性

    DMD全局复位是否一定要求加载所有行的数据?

    1.DMD全局复位是否一定要求加载所有行的数据?可否指定某一段的行数据进行变化,然后申请全局复位,没有数据变化的行保持原先数据。 2.指定某一段的行数据变化,DVALID信号应该如何控制。控制
    发表于 02-26 08:04

    利用SSIS源、查找及目标组件集成PostgreSQL数据至ETL流程

    使用SSIS源、查找和目标组件在ETL中集成PostgreSQL数据 Devart SSIS Data Flow Components for PostgreSQL 允许您将 PostgreSQL
    的头像 发表于 02-07 09:24 1658次阅读
    利用SSIS源、查找及目标组件集成<b class='flag-5'>PostgreSQL</b>数据至ETL流程

    DAC7564输出死锁是什么原因引起的?

    我用DAC7564输出,发现DAC7564会不定时的出现某通道输出死锁的现象(就是输出固定在某一值,不能再改变了)。断电重启后又正常了。 是用IO口模拟的SPI,在发送命令前关中断,发送完后再开中断。 请问指点一下,这种情况可能是什么原因引起的?用这个芯片要注意什么方面?
    发表于 02-05 08:44

    dbForge Studio for PostgreSQL:PostgreSQL数据库多功能集成开发环境

    什么是 dbForge Studio for PostgreSQL?是一个集成工具包中包含 PostgreSQL 所需的一切 上下文感知SQL代码补全、智能格式化和语法验证 消除性能瓶颈的查询优化器
    的头像 发表于 01-16 17:26 878次阅读

    ADS8365是否存在类似死锁的保护使得数据显示为0或者65535,而且只有重新上电才能恢复正常?

    我当时判断为ADC应该有一个类似死锁的保护,从而只显示0值。由于各种原因,此事不了了之,我仍然一如既往的使用ADS8365。但2015年另一款实用该ADC的控制器也发生了类似的现象,只不过这次显示
    发表于 01-07 07:41

    思特威推出高性能智能交通应用全局快门图像传感器产品

    近日,技术先进的CMOS图像传感器供应商思特威(SmartSens,股票代码688213),全新推出高性能智能交通(ITS)应用全局快门图像传感器产品——SC935HGS(9MP)及SC635HGS(6MP)。
    的头像 发表于 12-26 10:48 1308次阅读

    onsemi全局快门图像传感器—了解图像传感器的选型要点

    统应运而生,而高速、全画幅全局快门传感器是这些系统的核心。全局快门能够即时捕捉拍摄对象的完整视图,这非常重要。基于全局快门的系统可以消除许多常见于视觉系统的视觉伪
    的头像 发表于 12-20 16:15 1097次阅读
    onsemi<b class='flag-5'>全局</b>快门图像传感器—了解图像传感器的选型要点

    PostgreSQL将不再支持MD5密码

    根据 PostgreSQL 代码仓库的最新动态,近日有维护者提交了“弃用 MD5 密码支持”的 commit。 该维护者指出,MD5 被认为不适合用作加密散列算法已有一段时间。 此外
    的头像 发表于 12-10 16:14 736次阅读