WCF学习--Windows事务系统

最近开始WCF相关知识的学习,虽然实际工作中使用公司自己的一套SOA系统,但微软的一套服务架构还是具有很大的参考意义。除了WCF的一些基础使用,相对比较复杂的内容有分布式的事务和通信的安全等,不过基本都和WS-协议簇相关联。为了引出WCF中的事务处理,今天优先介绍Windows下的事务处理模型,说实话用了很多年的TransactionScope,其实我一直都不知道它到底是如何运作的,回想Java中不管是EJB还是Spring也有和这部分类似的实现。今天通过学习蒋金楠老师的WCF服务框架解析来了解这部分的原理。

首先回忆事务的概念和相关应用机制。事务具有ACID(原子性,一致性,隔离性,持久性)特性,主要的应用场景比如银行转账,大部分的数据库都支持事务操作(SQL Server,Oracle,DB2,MySQL-InnoDB)。事务的实现最常见的有在SQL语句中使用事务BEGIN TRANSACTION, COMMIT TRANSACTION, ROLLBACK TRANSACTION,还可以通过ADO.NET的DbTransaction对象来控制事务,但这些只能支持单个链接的本地事务,而不能支持分布式事务。但实际的项目中,事务的参与者往往不会分布在同一个网络节点,有时是不同类型的事务资源(不仅仅是数据库,也可以是文件系统,注册表等)。分布式事务的典型业务场景有以下三类:将多个资源的访问纳入同一事务;将多个服务纳入同一事务(涉及事务在服务间的流转);将多个资源和服务纳入同一事务(如下图所示)。

接下来进入核心内容Windows下的事务处理模型,事务处理模型一般包括三种角色:

应用(也包括服务、组件等),资源管理器RM(管理具体事务型资源的软件程序),事务管理器TM(管理整个事务的中间件程序)。事务是为了将一组相关操作作为一个不可分割的整体来执行,保证数据的一致性,实际上就是为应用服务的。应用主要负责开始事务&事务的封送(Marshaling)和传播(Propagation)、提交事务。

事务型资源的存取需要通过资源管理器,按照目标资源是否可以被持久化,相应的资源管理器分为:持久化(Durable)资源管理器,例如数据库管理器和小心队列,当事务回滚时具有可恢复性;易失(Volatile)资源管理器用于管理类似内存的资源,不具可恢复性。其主要职责是帮助应用实现对目标资源的操作、注册到相应的事务管理器便于回滚时接受恢复请求、向事务管理器报告本地事务的结果。事务管理器

事务管理器是整个模型的枢纽,协调所有的事务参与者,提供事务的开始、提交和回滚服务。Windows提供了三种不同的事务管理器,包括轻量级事务管理器LTM、内核事务管理器KTM和分布式事务协调器DTC。不过从这儿也可以看出事务服务并不具有跨平台特性,因而这部分内容主要作为参考学习,重在理解原理。轻量级事务管理器和内核事务管理器分别负责SQLSERVER和Windows文件&注册表,高效但不支持分布式。分布式事务协调器用于管理跨边界的分布式事务,支持Ole-Tx和WS-AT协议,每一台Windows计算机都具有唯一的DTC用于管理本地所有的资源管理器,支持分布式但效率较低。需要注意的是,事务开始默认LTM作为事务管理器,在其进行的过程中,根据实际的情形会进行事务提升(Transaction Promotion)。例如,涉及到注册表的读写就会升级到KTM,涉及到跨域的封送就会提升到DTC。

那么我们不经要问,分布式事务到底是如何实现的呢?其最关键的两个概念分别是事务登记&事务提交树(Transaction Commit Tree)和两阶段提交协议,接下来分别介绍这两个概念。

事务登记(Transaction Enlist)的目的在建立事务参与者之间的关系,促进相互间的协作,整个流程如下图所示:

以上的事务涉及两台机器,事务由ServiceA开启,并将其作为当前执行上下文的环境事务(Ambient Transaction)。当ServiceA调用本机资源管理器(如SQLSERVER)时,会将该RM纳入到本事务中。资源管理器RM向本机的DTC进行事务登记,从而DTC于RM建立起上下级关系。当ServiceA在调用ServiceB时,会将当前事务信息(分布式事务ID和本机DTC信息)封送,Service接到后取出信息重建事务,并将其设置为环境事务具有与原事务相同的ID。同时,ServiceB根据得到的MachineA的DTC消息,让本机DTC对MachineA的DTC进行事务登记,使得两台机器DTC建立上下级关系,之后将RM也纳入该DTC管理。在登记流程结束后就形成了如下事务提交树:

在分布式环境下,事务提交需要保证在操作成功时,所有需要持久化的数据被相应资源管理器RM写入目标资源,而失败时所有RM中数据要恢复到原始状态。为了实现这一目标,分布式事务提交需要采用"两阶段提交"协议,接下来详细介绍这两个阶段:

第一阶段--准备阶段,根节点的DTC向所有事务参与者发起请求,要求他们对本地事务的结果进行投票,如上图所示递归的进行消息传播,相应节点反馈就绪、只读、终止等投票类型。若所有投票结果为就绪和只读就代表提交,如果有任何一个为终止则代表终止提交。同时可以设置超时时限,若超过此时限整个事务进行回滚。

第二阶段—提交或者回滚,根节点DTC根据投票结果对整个事务发起提交或者终止操作,使用和第一阶段相同的消息传播方式完成操作。当遇到事务参与者在完成第一阶段投票后网络断开等异常情况时,该子事务处于"未决态"。再重启此事务后,该DTC会向上级询问最终结果,如果上级不能确认则继续向根节点传播,直到得到答复,若时间太长系统管理者可以强制提交或终止事务。

此外,为了提高提交性能,协议会根据节点所具有的下级节点数决定是否选用单阶段提交协议,就是在节点只有一个唯一下级时直接发起提交。

在完成了原理的剖析后,进入实际的应用,这也是与工作息息相关的部分。WCF基于DTC的Windows事务架构为基础,提供一个完善的分布式事务解决方案。提供了System.Transactions.Transaction的命令式编程模型和System.Transactions.TransactionScope的声明式编程方式。

Transaction类时可以序列化封送的,通过EnlistDurable和EnlistVolatile等方法将资源管理器登记到当前事务,构建事务提交树。Currrent属性表示当前的环境事务(Ambient),其存储在当前线程的TLS中。TransactionInformation属性表示事务的基本信息,包括创建时间、状态、本地标识和分布式标识。并通过IsolationLevel表示隔离级别,使用Clone和Rollback方法克隆事务和回滚事务,需要注意的是事务的开始和结束需要同一个事务来完成,我们把这种事务称为可提交事务(Commitable Transaction),而其他的相关事务被称为依赖事务(DependentTransaction)。可提交事务通过TransactionOptions结构体设置超时时间和隔离级别,也可以通过如下配置设定。


<system.transactions>

<defaultSettings timeout="00:01:00"/>

<machineSettings maxTimeout="00:10:00"/>

</system.transactions>

可提交事务通过Commit方法和异步Begin/EndCommit方法提交事务,例子如下所示:


private static void Transfer(string accountFrom, string accountTo, double amount) {

Transaction originalTransaction = Transaction.Current;

CommittableTransaction ct = new CommittableTransaction();

try

{

Transaction.Current = ct;

Withdraw(accountFrom, amount);

Deposit(accountTo, amount);

ct.Commit();

}

catch

{

ct.Rollback();

throw;

}

finally {

Transaction.Current = originalTransaction;

ct.Dispose();

}

}

在Transaction类中存在一个DepedentClone的方法,该方法用于基于当前事务创建其所对应的依赖事务,也就是其所辖的子事务,将当前线程的环境事务传递到新的事务中。接下来的代码演示了通过依赖事务采用异步方式进行银行转账。需要注意的是,由于在调用DependentClone时指定的Options参数为BlockCommitUntilComplete,所以主线程在提交事务时,如果依赖事务未结束会一直等待到超时。还有一个关于事务型方法的实现也很有意思,大家有兴趣可以去看蒋老师的原著。


private static void Transfer(string accountFrom, string accountTo, double amount)

{

Transaction originalTransaction = Transaction.Current;

CommittableTransaction ct = new CommittableTransaction();

try

{

Transaction.Current = ct;

ThreadPool.QueueUserWorkItem(state => {

Transaction.Current = state as DependentTransaction;

try

{

Withdraw(accountFrom, amount);

Deposit(accountTo, amount);

(state as DependentTransaction).Complete();

}

catch (Exception ex) { Transaction.Current.Rollback(ex); }

finally {

(state as DependentTransaction).Dispose();

Transaction.Current = null;

}

}, Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete));

ct.Commit();

}

catch

{

ct.Rollback();

throw;

}

finally

{

Transaction.Current = originalTransaction;

ct.Dispose();

}

}

最后介绍实际工作中最常见的TransactionScope类,如之前提到的事务型方法就有如下简易实现。


static void InvokeInTransaction(Action action)

{

using (TransactionScope ts = new TransactionScope())

{

action();

ts.Complete();

}

}

需要注意的是TransactionScopeOption的设置,有如下三种类型:Required,表示如果存在环境事务则使用,否则进入范围前创建新的事务;RequiresNew,表示总是在该范围创建新事物;Suppress,表示屏蔽环境事务,即所有操作均在无环境事务的情况下执行。这个J2EE Spring中的REQUIRED 、REQUIRES_NEW   、 NOT_SUPPORTED很相似,不过对于J2EE与DTC相类似的机制个人还未涉猎,之后有机会再和大家分享了。

注:本文主要供自己学习,不妥之处望见谅。

参考资料:

[1]蒋金楠. WCF全面解析[M]. 上海:电子工业出版社, 2012.

时间: 2024-10-12 04:25:02

WCF学习--Windows事务系统的相关文章

WCF学习日记

图书馆借阅了<WCF高级编程>,从6.11开始学习wcf,希望尽快熟悉原理和编程模型以及常用编程方法. WCF是一个平台,也是一个框架,从Net.3.0 就在Net framework(无需安装) .WCF将服务以SOA架构对外使用.SOA的宗旨就是让应用程序成为一个接口可以供其余程序使用.比如图书订单管理系统,订单履约系统,ship系统,会计系统,以及其它系统,每个都是一个独立的系统,但是彼此系统应该作为接口供别人使用,这样即使扩展了服务或者改善了服务也不会影响原先的体系架构和业务规则. W

WCF学习笔记(一)

WCF是什么? 官方解释: Windows Communication Foundation (WCF) 是用于构建面向服务的应用程序的框架.借助 WCF,可以将数据作为异步消息从一个服务终结点发送至另一个服务终结点. 服务终结点可以是由 IIS 承载的持续可用的服务的一部分,也可以是应用程序中承载的服务.终结点可以是从服务终结点请求数据的服务客户端.简单消息可以是作为 XML 发送的单个字符或单个单词,复杂消息可以是二进制数据流. 网络收集: Windows通信基础(Windows Commu

wcf 学习笔记1

1. wcf 中的所有消息均为SOAP消息,注意WCF的消息与传输协议无关,与WEB服务不同,因此WCF服务可以在不同的协议之间传输,而不仅限于HTTP 2. wcf的每一个服务都有一个唯一的地址,地址包含两个元素:服务位置和传输协议:服务位置包括机器名,站点,通讯端口,管道或队列,以及一个可选的特定路径或URI统一资源标识 3. wcf 通讯协议有:http ,tcp , peer network , ipc , msmq ,使用命名管道的服务只能接收来自同一台机器的调用,每台机器只能打开一个

WCF学习之旅—WCF概述(四)

一.WCF概述 1) 什么是WCF? Windows Communication Foundation (WCF) 是用于构建面向服务的应用程序的框架.借助 WCF,可以将数据作为异步消息从一个服务终结点发送至另一个服务终结点.服务终结点可以是由 IIS 承载的持续可用的服务的一部分,也可以是应用程序中承载的服务.终结点可以是从服务终结点请求数据的服务客户端.简单消息可以是作为 XML 发送的单个字符或单个单词,复杂消息可以是二进制数据流.一些示例方案包括: 处理企业事务的安全服务. 将当前数据

Windows 2012 系统搭建高可用故障转移集群

Windows 2012 系统搭建高可用故障转移集群 一.故障转移集群介绍 2 1.1 系统介绍 2 1.2 工作原理 2 二.实验目的 2 2.1 验证故障转移功能 2 2.2 验证高可用集群的可用性,以及支持的服务类型 2 三.实验原理 3 3.1 实验拓扑 3 3.2 实验环境设备 3 四.配置步骤 4 4.1 配置域服务器 4 4.2  iSCSI 虚拟存储配置 18 4.3 配置故障转移集群服务 45 4.4  验证集群 63 五.实验结果验证 68 5.1  验证故障转移 68 5.

WCF学习笔记(1)-一个完整的例子

一.开发环境 IDE:VS2013 OS:Win10 IIS:IIS 10 二.开发流程 1.项目结构 2.添加一个WCF程序 3.删除系统自动生成的两个文件IService1.cs和Service1.svc 4.添加自定义的WCF服务文件 5.在IUser.cs文件中,定义方法名 注: [ServiceContract]来说明是一个WCF接口,不加的话,不能被外部调用 [OperationContract]来说明该方法是一个WCF接口的方法,不加不能被外部调用 namespace WCFSer

有一定基础的 C++ 学习者该怎样学习 Windows 编程?

人的心理有个奇异的特性:一项知识一旦学会之后,学习过程中面临的困惑和不解非常快就会忘得干干净净,似乎一切都是自然而然,本来就该这种.因此,关于「怎样入门」这类问题,找顶尖高手来回答,未必能比一个刚入门不久的人来回答要好.就譬如最高票的那个回答,是一个非常精通 Windows 编程的高人回答的,但这种答案能给刚開始学习的人带来多少帮助,我这里想先打一个问号. 前段时间刚辅导了一个学生学会了 Win32 GUI 编程,刚好看到这个问题,顺手就邀请他回答了.并不是是给他布置总结作业,不过希望能从他这里

有一定基础的 C++ 学习者该如何学习 Windows 编程?

人的心理有个奇妙的特性:一项知识一旦学会之后,学习过程中面临的困惑和不解很快就会忘得干干净净,似乎一切都是自然而然,本来就该这样的.因此,关于「如何入门」这类问题,找顶尖高手来回答,未必能比一个刚入门不久的人来回答要好.就譬如最高票的那个回答,是一个非常精通 Windows 编程的高人回答的,但这样的答案能给初学者带来多少帮助,我这里想先打一个问号. 前段时间刚辅导了一个学生学会了 Win32 GUI 编程,刚好看到这个问题,顺手就邀请他回答了.并非是给他布置总结作业,仅仅是希望能从他这里得到第

学习windows内核书籍推荐 ----------转自http://tieshow.iteye.com/blog/1565926

虽然,多年java,正在java,看样子还得继续java.(IT小城,还是整java随意点)应用程序 运行于操作系统之上,  晓操作系统,方更晓应用程序.主看windows,因为可玩性高,闭源才有意思.(莫忘2008年,微软盗版黑屏事件)书籍推荐(全中文 ),按顺序======  windows应用程序  =============C&C++, 略 (懒~,就那几本,程序员都知道)<windows程序设计> (第5版.珍藏版), 非珍藏版的翻译垃圾,莫看<WINDOWS.核心编程