您的位置:首页 > 数据库

分布式事务-基于DTC的分布式事务管理模型(结合高级数据库系统书(分布式数据库的))

2016-06-22 12:19 821 查看
讨论Windows事务处理模型,首先来看看在这个模型中各个事务参与者各自扮演怎样的角色。

对于所有的事务参与者,按照各自在整个事务生命周期各个阶段所承担的职能,大致扮演着如下三种角色:

应用(Application)、服务(Service)或者组件(Component):代表用户程序,或者是承载着某功能的服务(Service)或者组件(Component);
资源管理器(RM:Resource Manager):代表用于管理具体事务型资源的软件程序,比如数据库或者队列(MSMQ)等;
事务管理器(TM: Transaction Manager):代表管理整个事务的中间件程序,为应用和资源管理器提供基本的事务控制服务。


一、应用(Application)、服务(Service)和组件(Component)

事务最终为用户程序、服务和组件服务的,后者利用了事务这种特殊的机制将一组相关的操作作为一个不可分割的整体来执行,从而确保了数据的一致性。在整个模型中,应用(服务或者应用,为了叙述简练,后续部分关于应用、服务和组件都简称为应用)主要负责如下一些事务相关的任务:

开始事务:事务开始的驱动者总是应用,但是并不是所有的应用都会开始一个新的事务,只有最初的应用才才是事务的开启者;
事务的奉送(Marshaling)和传播(Propagation):将应用的本地事务封送、传播给另一个应用或者资源管理器;
提交事务:事务的开启者同时也是事务最终的提交者,当事务相关的操作顺利完成后,最初开启事务的应用会提交该事务。


二、资源管理器(RM:Resource Manager)

在事务控制模型中,不论是应用还是资源管理器都不是直接地访问具体的事务型资源,而是通过一个中介间接地对目标资源进行操作,这个中介就是资源管理器。按照目标资源是否可被持久化,可以将相应的资源管理器分为如下两类:

持久化资源管理器(Durable Resource Manager):用于管理持久化资源,比如数据库和MSMQ,当事务回滚得时候,具有可恢复性(Recovery);
易失资源管理器(Volatile Resource Manager):用于管理像内存数据这样的不会被持久化的易失资源,易失资源不具有可以恢复性。

在后面介绍的实现分布式事务的两阶段提交(2PC: Two-Phase Commit)协议中,对于这两种不同的资源管理器,采用不同的登记(Enlist)方式。总的来说,资源管理器在整个事务模型中主要承担如下几种职能:

帮助应用实现对目标资源的操作;
注册到相应的事务管理器,以便事务回滚得时候可以从事务管理器中接收到恢复请求,实现对数据的恢复;
向相应的事务管理器报告本地事务的结果;


三、事务管理器(Transaction Manager)

事务管理器是整个事务控制模型的核心和枢纽,是它控制着事务的所有参与者,协调整个事务从开始到完成的所有相关处理流程。事务管理器为应用和资源管理器提供一系列核心的事务性的服务,实现事务的开始、提交和回滚。Windows提供了三种不同的事务管理器,我们现在对它们进行逐个介绍。


1、轻量级事务管理器(LTM: Lightweight Transaction Manager)

正如其名称隐含的意思,轻量级事务管理器(以下简称LTM)具有最小的负载,是性能最高的事务管理器。LTM的作用范围仅限于开启事务的应用程序域(AppDomain)中,并且登记到事务中的持久化资源(Durable Resource)数量不能超过一个。

一般地,被开启的事务就由LTM管理,如果事务涉及到跨应用程序域的操作,当前的事务回被奉送、传播到另一个执行上下文中,此时事务将脱离LTM的管辖。此外,基于LTM的事务中可以同时登记(Enlist)多个易失型资源(Volatile),但是仅仅允许登记唯一一个持久化资源。当第二个持久化资源被登记到当前事务中,该事务也将脱离LTM的管辖。

并不是所有的持久化资源都可以登记到LTM,实际上到目前为止,能够登记到LTM这么一个高性能的事务管理器的事务型资源仅仅限于SQL Server 2005和SQL Server 2008,即使是同属于Windows平台下SQL Server 2000和MSMQ均不支持LTM,更不用说Oracle和DB2。我们希望微软能够和其他的厂商进行合作,让第三方开发的事务型资源也能利用LTM性能的优势。


2、内核事务管理器(KTM:Kernel transaction Manager)

内核事务管理器(以下简称KTM)在Windows Vista中被引入,并被用于后续的Windows Server 2008和Windows 7。引入KTM的主要的目的在于实现将文件管理和注册表管理纳入事务的范畴。借助于KTM,我们可以以事务的方式操作NTFS文件系统下的文件资源,以及注册表资源。我们将支持事务的文件系统和注册表成为事务型的文件系统(TxF)和事务型注册表(TxR)。

之所以被称为内核事务管理器,使因为基于KTM的事务控制引擎运行在内核模式(Kernel Mode),而不是用户模式(User Mode)下。和LTM一样,KTM对易失型事务资源没有限制,却至于单一的持久化事务资源被涉及。

从上面的介绍我们不难看出,无论是LTM还是KTM,其管辖范围仅限于本地事务,对于分布式事务却无能为力。分布式事务依赖于一个更为强大的事务管理器,就是我们接下来着重介绍的分布式事务协调器。


3、分布式事务协调器(DTC:Distributed Transaction Coordinator)

对于分布式事务协调器,我们大都简称为DTC,或者MS DTC,以下我们直接简称DTC。DTC用于管理跨边界(跨应用程序域、进程、机器以至跨网络)执行的分布式事务,它采用相应的事务管理协议,比如Ole-Tx和WS-Atomic Transaction(WS-AT),协调一个分布式事务中的所有参与者。

每一台机器上具有一个唯一的DTC,事务涉及的承载于某台机器的所有事务型资源均由当前机器的DTC管理。当事务跨越多台机器时,它们各自的DTC需要按照相应的协议相互协作,实现对整个事务的一致性管理。


4、事务提升(Transaction Promotion)

以上我们介绍了三种不同的事务管理器类型,从功能上讲,DTC能够协调、管理一个分布式事务涉及的所有事务型资源,而不管具体的资源分布于何处。但是,由于其事务控制的复杂性(一般采用两阶段提交协议)并需要进行跨进程、跨机器甚至跨网络通信,在性能上无疑是最差的。所以,我们不可能在任何事务场景中都采用DTC,所谓“牛刀虽好、不便杀鸡”,我们应该根据事务控制的需要选择性能最高的事务管理器。

但是,事务是一个动态执行的操作序列,系统不可能预知完整执行整个事务所有操作后的资源登记情况,所以不可以预先为其指定一个为相应事务多身定制的事务管理器。相反地,只能在事务具体的执行过程中,动态地选择最适合当前事务执行情况的事务管理器。Windows采用事务提升的机制进行事务管理器的选择。

一般情况下,事务开始的时候,LTM默认被作为当前的事务管理器。随着事务操作的逐步执行,如何该事务涉及到对某个内核事务资源的访问,那么自动提升到基于KTM的事务。无论是基于LTM还是KTM的事务,在当出现如下两种情况的时候,会向基于DTC事务提升:

事务操作涉及到对多个LTM资源的访问或者访问的资源不被LTM支持:比如说,当事务应用开启两个基于SQL Server 2008(LTM事务型资源)的连接进行数据存取;或者,访问开启一个基于Oracle(非LTM事务型资源)的连接进行数据存取;
当前事务被跨应用程序域封送(Marshaling):比如说,放一个服务调用另一个服务的时候,将当前事务进行序列化以实现向被调用服务方传播。

由于WCF的事务体系解决的是事务在服务之间的流转,以及对服务操作直接或者间接访问的所有事务型资源的协作,这样的事务时通过基于DTC的分布式事务实现的。

当基于LTM或者KTM的事务提升到基于DTC的分布式事务后,DTC成为了本机所有事务型资源管理器的管理者;此外,当一个事务型操作超出了本机的范围,出现了跨机器的调用后,本机的DTC需要于被调用者所在机器的DTC进行协助。上级对下级(包括本机DTC对本机所有资源管理器,以及上下级DTC)的管理得前提是下级在上级那里登记,即事务登记(Transaction Enlist)。所有事务参与者,包括所有资源管理器和事务管理器(即DTC)在进行了事务等级完成之后形成了一个树形的层级结构,该结构的形成是后续的事务提供成为可能,因此我们将其称之为事务提交树(Transaction
Commit Tree)。

四、事务登记(Transaction Enlisting)和事务提交树(Transaction Commit Tree)

事务登记的目的在于建立起事务参与者(只要指资源管理器和事务管理器DTC)之间的关系,促进相互之间的协作。我们先来看看整个事务登记是如何进行的,整个事务登记流程大致如图1所示。





图1 事务登记的流程

图1所示的事务涉及到部署与两台机器(Machine A和Machine B)上两个服务之间的交互,事务由Service初始化,在调用Service2的时候被传播到Machine B,从而将分布于两台机器的资源管理器纳入到同一个事务之中。接下来,我们对整个流程进行详细介绍。

首先,Service A开始一个新的事务,并将其最为当前执行上下文的环境事务(Ambient Transaction)。当Service A调用本机的资源管理器的时候,会将该资源管理器纳入到本事务之中(对于我们后续要介绍的System.Transactions事务,像SQL Server、Oracle以及MSMQ等资源管理器都能够自动感知到当前的环境事务)。此时,资源管理器(RM)向本机的DTC进行事务登记,从此DTC和资源管理器之间建立起了上下级关系。

当Service A在调用Service B的时候,会将当前事务的一些信息,比如分布式事务的ID以及关于本机DTC相关信息,封装在消息中(一般是SOAP报头)向对方传递。当Service B接受到服务调用请求消息,会将事务相关的信息提取出来在本地重建事务,并将其作为当前的环境事务,该事务和原事务具有相同的ID。同时,根据得到的关于Machine A的DTC相关信息,让本机的DTC对Machine A的DTC进行事务登记,进而使两台机器的DTC确立了上下级关系。

和Service A访问本机的资源管理器一样,Machine B的资源管理器被Service B调用并被纳入当前事务的时候,会向本机DTC进行事务登记。

当上面所述的事务登记流程结束后,参与整个分布式事务的DTC和资源管理器形成了如图2所示的树形层次结构,由于该结构的构建主要是为了后面对整个事务的提交服务的,所以我们一般将其称为事务提交树(Transaction Commit Tree)。事务提交树的根为事务初始化服务所在机器的DTC,在整个事务提交过程中,它是总的协调者,又被称为全局提交协调器(GCC:Global Commit Coordinator )。资源管理器充当事务提交树的叶子节点,它们的父节点为本机的DTC。分布于不同机器的DTC按照事务传播的路径形成上下级关系。





图2 事务提交树

事务提交树的构建使得对分布式事务的提交成为可能,分布式事务的提交采用两阶段协议实现,接下来我们详细介绍基于两阶段提交协议的事务提交机制。


五、基于两阶段提交(2PC:Two-Phase Commit)协议的事务提交机制

不同于基于单一资源管理器的本地事务,在一个分布式环境中时实现一个涉及到多个资源管理器的分布式事务,实现事务的ACID四大属性,要麻烦得多。当事务初始化服务(应用或者组件,为了更佳贴近WCF,我们都称服务)完成所有相关的操作,决定提交该事务。对于分布式事务的提交,最终的结果有两个:如果所有的操作能够顺利完成,需要持久化的数据被相应的资源管理器写入到目标资源;如果任何一个环节失败,所有持久化资源管理器将数据恢复到原来的状态。分布式事务的整个提交过程,采用两阶段提交(2PC:Two-Phase)Commit协议完成。顾名思义,“两阶段提交”意味整个整个事务提交阶段分两个阶段,我们现在就来详细介绍分别在这两个阶段中,都在做些什么。

注:在事务初始化服务决定提交事务之前,任何一个参与者均可以中止(Abort)该事务,任何一个参与者对事务的中止都将导致整个分布式事务的回滚。


1、第一阶段(Phase I):准备(Prepare)阶段

在第一个阶段,作为根节点的DTC沿着事务提交树的路径,向所有事务的参与者发起请求,要求它们对本地事务的结果进行投票。被请求的参与者将本地事务结果返回给自己的上级,对于资源管理器,自己的上级就是本机的DTC;如果自己本身就是DTC,那么自己得上级就是位于事务提交树父节点的DTC。根据具体事务操作执行的情况,参与者投票的类型包括如下三种:

就绪(Prepared):参与者同意对事务的提交,并承诺在接收到真正的提交请求后完成本地的提交任务;
只读(Read-only):参与者同意对事务的提交,但是不希望接收真正的事务提交请求;
中止(Aborted):参与者要求中止事务。

对于一个非根节点DTC来说,当它从父节点接收到标准的“准备”请求后,会立即将该请求沿着事务提交树发送给自己的下级(本机的资源管理器和下级DTC),然后根据从下级接收的所有投票结果,计算出自己投票的结果。具体的算法是:如果所有的投票结果都是“就绪”和“只读”,对应的结果是“提交”,反之,如果任何一个投票结果是“中止”,则最终的结果就是“中止”,换句话说,任何一个事务参与者具有一票否决权最后。最后,DTC将计算出来的投票结果反馈给自己的上级。

当根节点DTC接收到隶属于自己的所有资源管理器和下级DTC的投票结果后,采用于上面一样的算法决定整个分布式事务的最终结果。当根节点DTC决定了事务最终的结果后,整个提交过程进入第二阶段。

注:我们可以设置事务的超时时限,如果根节点DTC在该时限内没有介绍到所有参与者的投票请求,会对整个分布式事务做出回滚的决定。


2、第二阶段(Phase II):提交(Commit)或中止(Abort)

作为事务提交树根节点的DTC根据最终的事务结果,对整个事务进行最终的提交或者中止操作。同样是沿着事务提交树的路径,提交或者中止请求被广播出去。相应的资源管理器根据从本机DTC获得的请求,实施最终的提交或者恢复操作。当事务参与者完成了各自就的任务后,类似于第一个阶段的投票,会讲执行的结果沿着事务提交树逆向回馈给作为根节点的DTC。

根节点DTC只有接收到所有事务参与者的基于各自事务处理的回复,才能确保整个事务被成功提交或者回滚。那么如果事务的参与者完成了第一阶段的投票,网络断开,那将如何呢?这就涉及到对未决(In-Doubt)事务的处理。


3、未决(In-Doubt)事务的处理

对于某个分布式事务的参与者(DTC或者资源管理器)来说,在第一阶段向上级(事务提交树的父节点)投票表明提交就绪(Prepared)之后,直到它接收到根节点DTC最终的提交或者回滚的请求,它并不知晓本地事务的结果。在这期间,如果出现当机并重启,本地的事务处于一种“未决(In-Doubt)”状态。未决事务仅仅出现在非根节点DTC所在的机器。分布式事务采用如下的机制处理未决事务。

当重启后,对于本机的所有未决事务,DTC会向上级DTC发送查询请求,获取每一个事务最终的结果(提交还是中止)。如果上级也不能决定事务的结果,那么请求会沿着事务提交树不断向上(沿着根的方向)发送,直到得到一个明确的答复(不管怎样,位于根节点的全局提交协调器总是清楚事务的结果的)。

此外,当下级DTC向自己发送相同的查询请求的时候,该DTC会讲获取到的结果回复给它们。如果未决事务存在的时间太长,系统管理者可以强制提交或者中止该事务。


4、单阶段提交(SPC: Single-Phase Commit)优化

对于事务最终结果(提交或者中止)的决策者来说,如果它具有了不止一个下级,那么采用基于投票机制的两阶段提交协议唯一选择。但是如果仅仅具有一个唯一的下级呢,这种投票机制就没有必要了。在这种情况下,根节点DTC采用一种优化的协议来完成整个事务的提交,我们称之为单阶段提交(SPC:Single-Phase Commit)。

顾名思义,2PC意味着整个事务提交分成两个阶段,SPC则表示将其所短为一个阶段。整个流程很简单,如果根节点DTC仅仅只有一个登记的事务参与者(本机资源管理器或者下级DTC),而不管这个下级自身具有几个下级,它不会像2PC一样先向下级发送“准备”请求,而是直接发送提交请求,我们将这个请求成为单阶段提交(SPC)请求。接收到SPC请求的参与者,如果是资源管理器,则直接提交本地事务,并将最终结果(成功提交或者失败中止)反馈给这个跟节点DTC。

如果SPC请求的接收者是DTC,那么会根据隶属于自己的下级的数量选择相应的提交策略。具体做法和根节点DTC提交策略的选择方式一样:如果自己具有唯一一个下级,则采用SPC,反之采用2PC。

也就是说,不仅仅是根节点DTC可以选择SPC提交事务,任何具有单一下级的DTC均可以采用SPC。但是,非根节点DTC只有在接收到SPC请求的情况下,才能选择通过SPC提交事务。如图3给出了两颗事务提交树(图中忽略掉资源管理器,每个节点代表DTC),对于左边的树,因为根节点A和下级B均只有一个唯一的下级,所以A和B均采用SPC,C具有两个下级,则采用2PC。而对于右边的树,因为根节点本身具有两个下级,决定了所有的节点均采用2PC,即使是对于只有一个下级的B和C。





图3 DTC对SPC和2PC的选择
(这是在开发使用DTC,进行分布式事务提交过程中,因为遇到两台机器DTC不成功,然后自己在网上搜了一下,觉得讲的很好啊,就分享转发一下。其实这于我自己可以记录我的学习历程,同时我想找的时候也很方便;另外一方面,个人觉得这样可以加速只是的传播。但是我们也要尊重别人的成果,最后将引用的地址和作者附上,毕竟版权属于作者所有啊,免责声明一下)(在测试分布式事务方面使用了Dtctest.exe 和DTCPing ,有这方面需求的可以参考一下,不过由于个人旧笔记本太旧,xp和win8使用触发器触发时,始终不行啊,最后改用了链接服务器,使用存储过程。如果你有更好的方法也可以联系我啊,帮我解决问题哦)
http://www.cnblogs.com/artech/archive/2010/01/27/1657875.html 蒋金楠,网名Artech,知名IT博主, 微软多领域MVP(给作者打打广告啊,技术大牛啊)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: