GaussDB(DWS)中的分布式死锁问题实践

这篇具有很好参考价值的文章主要介绍了GaussDB(DWS)中的分布式死锁问题实践。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文分享自华为云社区《GaussDB(DWS)中的分布式死锁问题实践》,作者: 他强由他强 。

1、什么是分布式死锁

分布式死锁是相对于单机死锁而言,一个事务块中的语句,可能会分散在集群里多个节点(CN/DN)执行,在不同节点上可能都会持有锁,当并发事务进行时可能会导致分布式(全局)死锁,如下图所示,会话SESSION1持有了DN1上的lock1资源后再去请求DN2上的lock2,会话SESSION2持有了DN2上的lock2资源后再去请求DN1上的lock1,两个会话形成互相等待。出现分布式死锁现象后,如果没有外部干预,通常是一方等待锁超时报错后,事务回滚清理持有锁资源,另一方可继续执行。

2、常见的分布式死锁场景

一般来说,分布式死锁的产生与在不同节点上的并发时序或持锁顺序有关,所以现网实际发生概率较低,分布式死锁通常都是RegularLock类型,下面是几种常见的分布式死锁场景,举例说明两个并发事务产生的分布式死锁:

1)锁升级

# 集群两个CN,两个DN
create table mytable(a int, b int);
insert into mytable values(1,1),(2,2);

其中sessionA与sessionB由不同CN发起(sessionA:CN1,session2:CN2),执行时序如下:

session A(CN1)

session B(CN2)

begin;

begin;

select * from mytable;

// CN1上拿1级表锁

 
 

select * from mytable;

// CN2上拿1级表锁

truncate table mytable;

// CN1上拿8级表锁

// CN2上拿8级表锁,waiting

 
 

truncate table mytable;

// CN1上拿8级表锁,waiting

可以看到sessionA里select会持有本地1级锁,truncate会持有8级锁,出现锁升级现象,导致sessionA在CN2上等锁,sessionB在CN1上等锁,形成相互等待。

2)行更新冲突

# 集群两个CN,两个DN
create table mytable(a int, b int);
insert into mytable values(1,1),(2,2); 

行存表发生行更新冲突是比较常见的分布式死锁场景。因为表是round robin分布,所以行a = 1 与 a = 2数据可以保证分别分布在DN1和DN2节点。

一个事务在更新数据时需要在对应DN节点持有本xid事务锁的Exclusive锁,当发生行更新冲突时(写写冲突),一个事务需要阻塞等待另一个事务提交(等待获取对方事务锁ShareLock),形成相互等待时造成分布式死锁。

其中sessionA与sessionB可由相同或者不同CN发起,执行时序如下:

session A(xid1)

session B(xid2)

begin;

begin;

update mytable set b = 1 where a = 1;

// DN1上拿xid1的事务锁

 
 

update mytable set b = 2 where a = 2;

// DN2上拿xid2的事务锁

update mytable set b = 1 where a = 2;

// DN2上拿xid2的事务锁,waiting

 
 

update mytable set b = 2 where a = 1;

// DN1上拿xid1的事务锁,waiting

3)CU更新冲突

# 集群两个CN,两个DN
create table mytable(a int, b int) with (orientation = column);
insert into mytable values(1,1),(2,2),(3,3),(4,4);

其中sessionA与sessionB可由相同或者不同CN发起,执行时序如下:

session A(xid1)

session B(xid2)

begin;

begin;

update mytable set b = 1 where a = 1;

// DN1上拿xid1的事务锁

 
 

update mytable set b = 2 where a = 2;

// DN2上拿xid2的事务锁

update mytable set b = 1 where a = 3;

// DN2上拿xid2的事务锁,waiting

 
 

update mytable set b = 2 where a = 4;

// DN1上拿xid1的事务锁,waiting

当出现更新冲突时,对于行存表来说是对一行数据加锁(如场景2所述),但对于列存表来说是对一个CU加锁。所以一个事务里的更新语句如果涉及到不同的CU,也会拿事务锁,可能就会产生分布式死锁。

我们可以通过如下语句观察ctid信息判断数据是否分布在同一个CU上,如下图:可以看到a = 1 与 a = 3分布在DN1上,且在同一个CU;a = 2 与 a = 4分布在DN2上,且在同一个CU。所以这也能解释为什么看上去列存表更新不同的“行数据”也会产生锁阻塞和分布式死锁现象。

4)单语句出现分布式死锁

前面几种场景都是事务块里涉及到多条SQL语句,可能会到不同节点上去交错拿锁导致的分布式死锁,但有时候某些单语句场景可能也会出现分布式死锁,如下:

session A(xid1)

session B(xid2)

update/delete mytable set b = 1 where a = 1;

// waiting

update/delete mytable set b = 2 where a = 2;

// waiting

此类问题与数据分布有关,如下场景都可能会导致这个现象:

1)若表是复制表,每个DN节点上都有数据,更新时会去所有DN并发执行

2)表是普通行存表或列存表,但有行数据(如a=1)同时分布在了多个DN节点上,如round robin分布下插入两条相同a=1的数据

insert into mytable values(1,1);
insert into mytable values(1,2);

此场景需要具体去排查数据分布是否会造成此情况。

3、规避分布式死锁的方法

1)控制锁级别,减少锁升级

按照各类操作的锁级别建议规则使用,开发时不要盲目提高锁级别,造成可能发生的不必要的锁等待

2)控制锁粒度

合理控制锁使用范围,及时释放

3)控制拿锁顺序

尽量控制对资源操作的顺序,比如对各分区表的操作顺序,避免乱序造成的死锁。但全局各节点的拿锁情况或顺序一般无法提前预测,往往为了考虑提高性能,请求会在节点间并发执行,但我们可以在某个节点上控制并发互斥以规避分布式死锁问题,如操作某个表时先去FirstCN上请求持锁,持锁成功后再对其他CN和DN并行拿锁。GaussDB(DWS)内核的很多地方的设计中会有这种思想,如DDL语句,autoanalyze等。

4)主动设置较短的锁超时时间

一般用在非关键的用户路径操作上,如用户语句在runtime analyze子事务的流程里会主动设置锁超时时间为2秒,发生阻塞后可及时放锁,避免出现长时间锁等待,也能规避潜在的分布式死锁场景

4、如何排查系统是否产生了分布式死锁

本质上是发现集群中是否有全局的死锁环等待关系,内核中提供有许多视图可以辅助观察持锁等待情况,但需要注意的是,因为查询到的锁等待关系可能只是暂时的瞬间状态,只有持续存在的锁等待才会造成分布式死锁,需要判断锁是否稍后会主动释放(事务提交前),还是只能等到事务提交后释放。如何判断系统是否产生了分布式死锁,有以下方法:

1)查询pgxc_deadlock视图,会输出全局死锁环信息,如果信息为空,则代表无分布式死锁,但需要注意在某些复杂的场景可能会出现误报,即输出有死锁环信息,但可能并没有形成分布式死锁;

当有分布式死锁时,直到等待锁超时后,某一方事务会出现“Lock wait timeout...”,打印具体的锁信息及锁语句,报错后释放锁,另一方解除阻塞。相关的锁超时参数是lockwait_timeout或update_lockwait_timeout。

2)在GaussDB(DWS)的8.3.0版本及以后,内核已经支持了自动化地分布式死锁检测,当检测到系统中存在分布式死锁等待关系后,会自动报错和挑选事务进行cancel,具体原理下一节中会详细介绍。

如下图所示,若用户出现“cancelled by global deadlock detector”报错,代表检测到分布式死锁并被查杀,此时可以去检测CN上(FirstCN或者CCN)上去找相关日志信息,会输出具体死锁和session查杀信息,需要注意用户语句执行CN和检测CN可能并不是一个,此时检测CN会向执行CN发起事务cancel。

5、分布式死锁检测原理

分布式死锁检测的目标原则是做到不误报,争取不漏报,尽量及时报。

我们使用了中心化的收集检测思想,如流程图所示:首先挑选一个CN作为检测CN(类似master角色),CN上新增后台线程启动GlobalDeadlockDetector模块,周期性向集群所有节点收集锁等待关系,计算等待者和持有者信息,然后构造全局有向图(WFG),依赖定义的规则对图的顶点和边进行消除,判断是否能消除完成。如果无法消除完成,则出现了死锁环,并进行二次DoubleCheck,如果两次的死锁环信息有交集,则报告死锁信息。当发现死锁后,按照事务时间戳挑选最年轻的事务(youngest)进行中断,并会对用户报错。

我们在设计上主要参考了Greenplum的思路,由于与GaussDB(DWS)架构和应用场景上的差异性,也针对做了一些改造和优化,主要包括:

1、检测节点的选择:在FirstCN或CCN上启动后台检测线程,依赖外部OM模块做高可用切换;

2、等待关系图节点的标识:由检测CN构造全局唯一global_session下发,格式为:timestamp.pid.node_name(timestamp为事务开始的时间戳,pid为执行CN上的线程号,node_name为执行CN名称);

3、虚实边关系定义:支持定义线程级别虚实边,过滤掉不必要的死锁误报;
  • 实边:锁等待关系的变化,需要等到持有者事务会话commit或abort
  • 虚边:锁等待关系的变化,不需要等到持有者事务会话commit或abort

4、死锁结果的合法性检查:增加DoubleCheck机制,提高检测结果准确性,结果以连续两次检测到的死锁环交集为准;

5、死锁消除:执行CN与检测CN可能不同,可能存在跨CN发起的事务中断;

6、与单机死锁检测算法互补:当分布式死锁检测算法如果发现检测到单机的死锁环路等待关系后,则忽略,与单机死锁检测算法处理不冲突; 

分布式死锁检测相关参数:

  • enable_global_deadlock_detector:分布式死锁检测功能是否开启,默认off

  • global_deadlock_detector_period:分布式死锁检测周期,默认5秒

 文章来源地址https://www.toymoban.com/news/detail-760900.html

点击关注,第一时间了解华为云新鲜技术~

 

到了这里,关于GaussDB(DWS)中的分布式死锁问题实践的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 阿里云 ACK 云原生 AI 套件中的分布式弹性训练实践

    作者:霍智鑫 众所周知,随着时间的推移,算力成为了 AI 行业演进一个不可或缺的因素。在数据量日益庞大、模型体量不断增加的今天,企业对分布式算力和模型训练效率的需求成为了首要的任务。如何更好的、更高效率的以及更具性价比的利用算力,使用更低的成本来训

    2024年01月25日
    浏览(48)
  • 【项目亮点】大厂中分布式事务的最佳实践 问题产生->难点与权衡(偏爱Saga)->解决方案

    不断有同学问我大厂中实践分布式事务的问题,这里从 分布式事务的产生 ,到 强弱一致性与性能的权衡 ,再到最终 落地的解决方案 ,再到 实际的代码实现 ,再到我工作中实际 使用SAGA模式的应用案例 ,一篇文章讲清楚. 83.7%分布式事务的产生都是因为拆分微服务导致 的: 一句话概

    2024年04月27日
    浏览(47)
  • 【Redis 开发】分布式锁中的常见问题和Lua脚本

    分布式锁中我们设置的过期时间: 如果有一个线程获取锁之后在进行操作时,到达了锁的过期时间,之后就会有别的线程获得锁,如果这时,第一个线程执行完成后释放锁,就会将第二个锁的线程删除 针对这个情况如何改进: 在获取锁时存入线程标示(可以用UUID) 在释放

    2024年04月28日
    浏览(46)
  • GaussDB(DWS)迁移实践丨row_number输出结果不一致

    摘要: 迁移前后结果集row_number字段值前后不一致,前在DWS上运行不一致。 本文分享自华为云社区《GaussDB(DWS)迁移 - oracle兼容 --row_number输出结果不一致》,作者:譡里个檔 。 迁移前后结果集row_number字段值前后不一致,前在DWS上运行不一致。 这种问题大部分都是因为PARTITI

    2024年02月06日
    浏览(70)
  • 【分布式】大模型分布式训练入门与实践 - 04

    【分布式】NCCL部署与测试 - 01 【分布式】入门级NCCL多机并行实践 - 02 【分布式】小白看Ring算法 - 03 【分布式】大模型分布式训练入门与实践 - 04 数据并行(Distributed Data Parallel)是一种用于加快深度学习模型训练速度的技术。在过去,训练大型模型往往受限于单卡训练的瓶颈

    2024年02月08日
    浏览(39)
  • 分布式系统中的分布式链路追踪与分布式调用链路

    本文分享自天翼云开发者社区《分布式系统中的分布式链路追踪与分布式调用链路》,作者:c****w 在分布式系统中,由于服务间的调用关系复杂,需要实现分布式链路追踪来跟踪请求在各个服务中的调用路径和时间消耗。这对问题排查和性能监控都很重要。 常用的分布式链

    2024年01月19日
    浏览(59)
  • 【问题记录】警告:warning.warn(‘Downloading:{}‘.format(url),DownloadWarning) | 区块链 面试题:区块链技术中的分布式账本是如何实现的?

      “当人们做不到一些事情的时候,他们就会对你说你也同样不能。”     🎯作者主页: 追光者♂🔥          🌸个人简介:   💖[1] 计算机专业硕士研究生💖   🌿[2] 2023年城市之星领跑者TOP1(哈尔滨)🌿   🌟[3] 2022年度博客之星人工智能领域TOP4🌟   🏅[4] 阿里云社

    2024年02月07日
    浏览(49)
  • vivo 自研鲁班分布式 ID 服务实践

    作者:vivo IT 平台团队- An Peng 本文介绍了什么是分布式ID,分布式ID的业务场景以及9种分布式ID的实现方式,同时基于vivo内部IT的业务场景,介绍了自研鲁班分布式ID服务的实践。 随着系统的业务场景复杂化、架构方案的优化演进,我们在克服问题的过程中,也总会延伸出新的

    2024年02月11日
    浏览(46)
  • tim实践系列——去中心化分布式架构特点

    前言: tim是去中心化分布式即时通讯引擎。不依赖于任何中心服务器,采用去中心化分布式架构,解决传统中心化通讯方式的问题,去中心化分布式架构的通讯引擎的各个节点之间相互连接,形成一个庞大的分布式网络。可以轻松地扩展服务规模,支持更多的用户和业务需求

    2024年01月20日
    浏览(52)
  • 搭建Jmeter分布式压测与监控,轻松实践

    对于运维工程师来说,需要对自己维护的服务器性能瓶颈了如指掌,比如我当前的架构每秒并发是多少,我服务器最大能接受的并发是多少,是什么导致我的性能有问题;如果当前架构快达到性能瓶颈了,是横向扩容性能提升大,还是纵向扩容性能提升大。 如果需要了解这些

    2024年02月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包