分布式事务中间件 Fescar - 全局写排它锁解读

前言

一般,数据库事务的隔离级别会被设置成 读已提交,已满足业务需求,这样对应在Fescar中的分支(本地)事务的隔离级别就是 读已提交,那么Fescar中对于全局事务的隔离级别又是什么呢?如果认真阅读了 分布式事务中间件Txc/Fescar-RM模块源码解读 的同学应该能推断出来:Fescar将全局事务的默认隔离定义成读未提交。对于读未提交隔离级别对业务的影响,想必大家都比较清楚,会读到脏数据,经典的就是银行转账例子,出现数据不一致的问题。而对于Fescar,如果没有采取任何其它技术手段,那会出现很严重的问题,比如:

如上图所示,问最终全局事务A对资源R1应该回滚到哪种状态?很明显,如果再根据UndoLog去做回滚,就会发生严重问题:覆盖了全局事务B对资源R1的变更。那Fescar是如何解决这个问题呢?答案就是 Fescar的全局写排它锁解决方案,在全局事务A执行过程中全局事务B会因为获取不到全局锁而处于等待状态。
对于Fescar的隔离级别,引用官方的一段话来作说明:

全局事务的隔离性是建立在分支事务的本地隔离级别基础之上的。
在数据库本地隔离级别 读已提交 或以上的前提下,Fescar 设计了由事务协调器维护的 全局写排他锁,来保证事务间的 写隔离,将全局事务默认定义在 读未提交 的隔离级别上。
我们对隔离级别的共识是:绝大部分应用在 读已提交 的隔离级别下工作是没有问题的。而实际上,这当中又有绝大多数的应用场景,实际上工作在 读未提交 的隔离级别下同样没有问题。
在极端场景下,应用如果需要达到全局的 读已提交,Fescar 也提供了相应的机制来达到目的。默认,Fescar 是工作在 读未提交 的隔离级别下,保证绝大多数场景的高效性。

下面,本文将深入到源码层面对Fescar全局写排它锁实现方案进行解读。Fescar全局写排它锁实现方案在TC(Transaction Coordinator)模块维护,RM(Resource Manager)模块会在需要锁获取全局锁的地方请求TC模块以保证事务间的写隔离,下面就分成两个部分介绍:TC-全局写排它锁实现方案、RM-全局写排它锁使用

一、TC—全局写排它锁实现方案

首先看一下TC模块与外部交互的入口,下图是TC模块的main函数:

上图中看出RpcServer处理通信协议相关逻辑,而对于TC模块真实处理器是DefaultCoordiantor,里面包含了所有TC对外暴露的功能,比如doGlobalBegin(全局事务创建)、doGlobalCommit(全局事务提交)、doGlobalRollback(全局事务回滚)、doBranchReport(分支事务状态上报)、doBranchRegister(分支事务注册)、doLockCheck(全局写排它锁校验)等,其中doBranchRegister、doLockCheck、doGlobalCommit就是全局写排它锁实现方案的入口。

/**
* 分支事务注册,在注册过程中会获取分支事务的全局锁资源
*/
@Override
protected void doBranchRegister(BranchRegisterRequest request, BranchRegisterResponse response,RpcContext rpcContext) throws TransactionException {response.setTransactionId(request.getTransactionId());response.setBranchId(core.branchRegister(request.getBranchType(), request.getResourceId(), rpcContext.getClientId(),XID.generateXID(request.getTransactionId()), request.getLockKey()));
}
/**
* 校验全局锁能否被获取到
*/
@Override
protected void doLockCheck(GlobalLockQueryRequest request, GlobalLockQueryResponse response, RpcContext rpcContext)throws TransactionException {response.setLockable(core.lockQuery(request.getBranchType(), request.getResourceId(),XID.generateXID(request.getTransactionId()), request.getLockKey()));
}
/**
* 全局事务提交,会将全局事务下的所有分支事务的锁占用记录释放
*/
@Override
protected void doGlobalCommit(GlobalCommitRequest request, GlobalCommitResponse response, RpcContext rpcContext)
throws TransactionException {response.setGlobalStatus(core.commit(XID.generateXID(request.getTransactionId())));
}

上述代码逻辑最后会被代理到DefualtCore去做执行

如上图,不管是获取锁还是校验锁状态逻辑,最终都会被LockManger所接管,而LockManager的逻辑由DefaultLockManagerImpl实现,所有与全局写排它锁的设计都在DefaultLockManagerImpl中维护。
首先,就先来看一下全局写排它锁的结构:

private static final ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>>> LOCK_MAP = new ConcurrentHashMap<~>();

整体上,锁结构采用Map进行设计,前半段采用ConcurrentHashMap,后半段采用HashMap,最终其实就是做一个锁占用标记:在某个ResourceId(数据库源ID)上某个Tabel中的某个主键对应的行记录的全局写排它锁被哪个全局事务占用。下面,我们来看一下具体获取锁的源码:

如上图注释,整个acquireLock逻辑还是很清晰的,对于分支事务需要的锁资源,要么是一次性全部成功获取,要么全部失败,不存在部分成功部分失败的情况。通过上面的解释,可能会有两个疑问:

  1. 为什么锁结构前半部分采用ConcurrentHashMap,后半部分采用HashMap?

前半部分采用ConcurrentHashMap好理解:为了支持更好的并发处理;疑问的是后半部分为什么不直接采用ConcurrentHashMap,而采用HashMap呢?可能原因是因为后半部分需要去判断当前全局事务有没有占用PK对应的锁资源,是一个复合操作,即使采用ConcurrentHashMap还是避免不了要使用Synchronized加锁进行判断,还不如直接使用更轻量级的HashMap。

  1. 为什么BranchSession要存储持有的锁资源

这个比较简单,在整个锁的结构中未体现分支事务占用了哪些锁记录,这样如果全局事务提交时,分支事务怎么去释放所占用的锁资源呢?所以在BranchSession保存了分支事务占用的锁资源。

下图展示校验全局锁资源能否被获取逻辑:

下图展示分支事务释放全局锁资源逻辑

以上就是TC模块中全局写排它锁的实现原理:在分支事务注册时,RM会将当前分支事务所需要的锁资源一并传递过来,TC获取负责全局锁资源的获取(要么一次性全部成功,要么全部失败,不存在部分成功部分失败);在全局事务提交时,TC模块自动将全局事务下的所有分支事务持有的锁资源进行释放;同时,为减少全局写排它锁获取失败概率,TC模块对外暴露了校验锁资源能否被获取接口,RM模块可以在在适当位置加以校验,以减少分支事务注册时失败概率。

二、RM-全局写排它锁使用

在RM模块中,主要使用了TC模块全局锁的两个功能,一个是校验全局锁能否被获取,一个是分支事务注册去占用全局锁,全局锁释放跟RM无关,由TC模块在全局事务提交时自动释放。分支事务注册前,都会去做全局锁状态校验逻辑,以保证分支注册不会发生锁冲突。
在执行Update、Insert、Delete语句时,都会在sql执行前后生成数据快照以组织成UndoLog,而生成快照的方式基本上都是采用Select...For Update形式,RM尝试校验全局锁能否被获取的逻辑就在执行该语句的执行器中:SelectForUpdateExecutor,具体如下图:
 

基本逻辑如下:

  1. 执行Select ... For update语句,这样本地事务就占用了数据库对应行锁,其它本地事务由于无法抢占本地数据库行锁,进而也不会去抢占全局锁。
  2. 循环掌握校验全局锁能否被获取,由于全局锁可能会被先于当前的全局事务获取,因此需要等之前的全局事务释放全局锁资源;如果这里校验能获取到全局锁,那么由于步骤1的原因,在当前本地事务结束前,其它本地事务是不会去获取全局锁的,进而保证了在当前本地事务提交前的分支事务注册不会因为全局锁冲突而失败。

注:细心的同学可能会发现,对于Update、Delete语句对应的UpdateExecutor、DeleteExecutor中会因获取beforeImage而执行Select..For Update语句,进而会去校验全局锁资源状态,而对于Insert语句对应的InsertExecutor却没有相关全局锁校验逻辑,原因可能是:因为是Insert,那么对应插入行PK是新增的,全局锁资源必定未被占用,进而在本地事务提交前的分支事务注册时对应的全局锁资源肯定是能够获取得到的。

接下来我们再来看看分支事务如何提交,对于分支事务中需要占用的全局锁资源如何生成和保存的。首先,在执行SQL完业务SQL后,会根据beforeImage和afterImage生成UndoLog,与此同时,当前本地事务所需要占用的全局锁资源标识也会一同生成,保存在ContentoionProxy的ConnectionContext中,如下图所示。

在ContentoionProxy.commit中,分支事务注册时会将ConnectionProxy中的context内保存的需要占用的全局锁标识一同传递给TC进行全局锁的获取。

以上,就是RM模块中对全局写排它锁的使用逻辑,因在真正执行获取全局锁资源前会去循环校验全局锁资源状态,保证在实际获取锁资源时不会因为锁冲突而失败,但这样其实坏处也很明显:在锁冲突比较严重时,会增加本地事务数据库锁占用时长,进而给业务接口带来一定的性能损耗。

三、总结

本文详细介绍了Fescar为在 读未提交 隔离级别下做到 写隔离 而实现的全局写排它锁,包括TC模块内的全局写排它锁的实现原理以及RM模块内如何对全局写排它锁的使用逻辑。在了解源码过程中,笔者也遗留了两个问题:

  1. 全局写排它锁数据结构保存在内存中,如果服务器重启/宕机了怎么办,即TC模块的高可用方案是什么呢?
  2. 一个Fescar管理的全局事务和一个非Fescar管理的本地事务之间发生锁冲突怎么办?具体问题如下图,问题是:全局事务A如何回滚?

对于问题1有待继续研究;对于问题2目前已有答案,但Fescar目前暂未实现,具体就是全局事务A回滚时会报错,全局事务A内的分支事务A1回滚时会校验afterImage与当前表中对应行数据是否一致,如果一致才允许回滚,不一致则回滚失败并报警通知对应业务方,由业务方自行处理。

 

#阿里云开年Hi购季#幸运抽好礼!
点此抽奖:https://www.aliyun.com/acts/product-section-2019/yq-lottery?utm_content=g_1000042901

原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/519699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云+X案例展 | 民生类:京东云突破数据中心光互联瓶颈

本案例由京东云投递并参与评选&#xff0c;CSDN云计算独家全网首发&#xff1b;更多关于【云X 案例征集】的相关信息&#xff0c;点击了解详情丨挖掘展现更多优秀案例&#xff0c;为不同行业领域带来启迪&#xff0c;进而推动整个“云行业”的健康发展。随着数字化的进程&#…

UI2Code智能生成Flutter代码--整体设计篇

背景: 随着移动互联网时代的到来&#xff0c;人类的科学技术突飞猛进。然而软件工程师们依旧需要花费大量精力在重复的还原UI视觉稿的工作。 UI视觉研发拥有明显的特征&#xff1a;组件&#xff0c;位置和布局&#xff0c;符合机器学习处理范畴。能否通过机器视觉和深度学习等手…

如何成为优秀的技术主管?你要做到这三点

阿里妹导读&#xff1a;技术主管&#xff0c;又叫「技术经理」&#xff0c;英文一般是 Tech Leader &#xff0c;简称 TL。随着工作经验的不断积累&#xff0c;能力的不断提升&#xff0c;每个人都有机会成为Team Leader。然而在机会到来前&#xff0c;我们必须提前做好准备&am…

达摩院2020十大科技趋势发布:云成IT技术创新中心

2020年第一个工作日&#xff0c;“达摩院2020十大科技趋势”发布。这是继2019年之后&#xff0c;阿里巴巴达摩院第二次预测年度科技趋势。 回望2019年的科技领域&#xff0c;静水流深之下仍有暗潮涌动。AI芯片崛起、智能城市诞生、5G催生全新应用场景……达摩院去年预测的科技…

SpringBoot Mybatisplus 多数据源使用

文章目录一、mybatisplus3.x1. 依赖2. 启动类添加注解3. 添加多数据源注解4. yml5. 测试类6. 源码地址为了适配新的需求&#xff0c;需要同时支持mysql和oracle数据库操作多数据源&#xff0c;因此项目中集成dynamic-datasource-spring-boot-starter,支持很多场景。 例如&#…

数据流被污染?数据质量不高?蚂蚁金服数据资产管理平台了解一下

今年年初&#xff0c;蚂蚁金服ATEC城市峰会在上海举办。金融智能专场分论坛上&#xff0c;蚂蚁金服数据平台部高级数据技术专家李俊华做了主题为《蚂蚁金服数据治理之数据质量治理实践》的精彩分享。 演讲中&#xff0c;李俊华介绍了蚂蚁金服数据架构体系的免疫系统——数据质…

努力≠上进!那些“熬夜”持续精进的人有多可怕!

经常听到一些同学说&#xff1a;某个公司薪资上调30-50%&#xff0c;我可以跳槽入吗&#xff1f;最近收到几个比较好的offer&#xff01;该去哪家&#xff1f;纠结&#xff01;目前岗位和环境对自己成长非常慢&#xff01;更看不到公司的前景特别迷茫&#xff01;想成为人工智能…

详解CPU几个重点基础知识

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 骏马金龙责编 | 阿秃关于CPU和程序的执行1、程序的运行过程&#xff0c;实际上是程序涉及到的、未涉及到的一大堆的指令的执行过程。当程序要执行的部分被装载到内存后&#xff0c;CPU要从内存中取出指令&#xff0c;然后指令…

非web项目并且项目文件多java项目 使用tomcat发布的方式

文章目录1. 创建配置文件2. 新建一个web项目2. 新项目结构调整4. 项目结构整理5. 添加jdk和jar6. 等待编译1. 创建配置文件 在tomcat的cof下面创建一下目录 conf\Catalina\localhost这个xml文件的名称建议和项目名一样&#xff0c;作用是&#xff0c;浏览器访问的时候项目名称…

为拯救爸妈朋友圈,达摩院造了“谣言粉碎机”

生命不可能从谎言中开出灿烂的鲜花。 前几天&#xff0c;母上大人给我发了条消息&#xff0c;再三叮嘱帮忙扩散&#xff0c;随手解救癌症患者。 “速转&#xff01;科学家发现&#xff1a;一味中药48小时可杀死60%癌细胞!” 回复框里&#xff0c;我打了一段长长的反驳文字。…

亲历!不要痴迷蓝牙耳机了,出门选这个准没错,99W+人的选择

01有一种耳机啊它是真的不适合在长途火车上使用那就蓝牙耳机除非你带充电宝还有一种耳机啊它是真的不适合丢那就是带有充电仓的耳机因为充电仓丢了这个耳机基本上就废了02这不&#xff0c;我就经历了&#xff0c;活生生的例子出差的路上在火车上把耳机充电仓给弄丢了只剩孤零零…

调整eclipse、SpringToolSuite4编辑器的内存大小以及显示

我们的Eclipse、SpringToolSuite4编辑器总是会因为内存太小发生卡顿或者卡死现象&#xff0c;我给大家提供一个方法来解决&#xff0c;希望能在这里帮到大家&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 设置内存大小 修改Eclipse的配置文件&#xff1a; 打开Eclip…

一元享移动怎么样_中国移动放大招!月租9元享200GB流量,网友:这套路谁敢用?...

中国移动放大招&#xff01;月租9元享200GB流量&#xff0c;网友&#xff1a;这套路谁敢用&#xff1f;众所周知&#xff0c;自从携号转网政策实施以来&#xff0c;移动就面临巨大的压力&#xff0c;因为口碑相对最差&#xff0c;移动转出的用户是最多的&#xff0c;2个月时间就…

云+X案例展 | 传播类:富通云腾加速联通云数字化转型步伐

本案例由富通云腾投递并参与评选&#xff0c;CSDN云计算独家全网首发&#xff1b;更多关于【云X 案例征集】的相关信息&#xff0c;点击了解详情丨挖掘展现更多优秀案例&#xff0c;为不同行业领域带来启迪&#xff0c;进而推动整个“云行业”的健康发展。在云时代背景下&#…

UI2Code智能生成Flutter代码——版面分析篇

开篇: 在《UI2CODE--整体设计》篇中&#xff0c;我们提到UI2CODE工程的第一步是版面分析&#xff0c;如果是白色的简单背景&#xff0c;我们可以像切西瓜一样&#xff0c;将图片信息切割为GUI元素。但是在实际生产过程中&#xff0c;UI的复杂度会高很多。本篇我们将围绕版面分析…

qq互动视频页面加载失败_互动案例技术分析(2)

这是该系列文章的第2篇&#xff0c;我们仍然会选择三个互动营销案例&#xff0c;从技术角度加以分析。这个系列并非为程序员而写&#xff0c;因为这些内容就是我们的日常工作。我们的目标是让更多的朋友能够了解技术可以实现的效果&#xff0c;以及更重要的——不能实现的效果。…

安排!活动素材的亿级用户精准投放

1.背景 随着闲鱼用户快速增长&#xff0c;运营活动越来越趋于精细和个性化&#xff0c;运营会根据用户偏好为其投放合适的活动&#xff0c;如下图所示在闲鱼首页商品展示时&#xff0c;会在商品的列表中插入活动Banner&#xff0c;通过这些活动banner引导用户进入到相应活动会场…

mysql计算年增长率

数据库格式如下&#xff1a; SELECTt1.YEAR,t1.quantity / t2.quantity increase_rate FROMyear_sales t1INNER JOIN year_sales t2 ON t1.YEAR - 1 t2.YEAR结果如下

云+X案例展 | 传播类:九州云 SD-WAN 携手上海电信,助力政企客户网络重构 换新颜

本案例由九州云腾投递并参与评选&#xff0c;CSDN云计算独家全网首发&#xff1b;更多关于【云X 案例征集】的相关信息&#xff0c;点击了解详情丨挖掘展现更多优秀案例&#xff0c;为不同行业领域带来启迪&#xff0c;进而推动整个“云行业”的健康发展。随着网络技术快速发展…