异步工作流体系结构的选择由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“常用的工作流引擎分析”。
异步工作流体系结构的选择简介
在行业应用程序中的许多进程并非都能够即时执行。例如,验证信用卡在某些时候就需要十秒钟的时间。在本地商店排队的时候,十秒钟过得很快;但在电子商务领域,十秒钟却非常漫长。如果Web站点或其他应用程序闲置这么长时间去等待对客户的信用卡进行验证,那么处理大量并发用户的能力将大大降低。
因此,对于运行时间相对较长的进程而言,无论它们需要十秒还是需要十天,都应当断开与应用程序的连接而以异步方式运行。以异步方式运行某个进程意味着,发出该调用的系统并不需要等待该请求执行完毕;请求发出之后,调用就立即返回。这种处理方式有许多优点,但最主要的结果是,它切断系统中不同进程之间的连接,让它们以不同的速度运行。一套断开连接的、或者去耦的系统有助于在分布及伸缩方面取得最大的灵活性。
定单处理系统从 Web 站点或其他公司等外部来源接收定单,它最适合于采用异步处理方式。如果对这样的系统进行了去耦处理,在传入的定单量很大时定单会堆积起来,但进程的其余部分不需要一定按同样的速度进行操作。前端系统可以尽快地接收定单,而此进程的其余部分可以在定单量较少时追赶上来。在系统组件之间采用异步连接方式能够产生均匀效果,将变换不定的输入流转换为一致的请求流程进行处理。
如果不在某种程度上使用异步处理,任何电子商务应用程序都不可能正常发挥作用,因此,对这种体系结构很少有异议,但是们仍有必要讨论其积极方面和消极方面。异步处理的优点
异步体系结构的主要优点包括:
前端进程(通常是Web页)响应更快,客户会认为这是一个运行速度较快的系统
提供了用来提出负载平衡请求的简单方式 提供了容错能力
2.1 支持断续连接的系统
其中的每个优点都是通过异步模式对应用程序中不同部分进行去耦处理的结果。要让某个进程具有异步特点,就必须建立某种形式的队列来保存挂起的请求,该进程中的每一个步骤都只能与这些中间队列进行通信,而不能直接与其上一步或下一步进行通信。
图 1.利用队列实现去耦操作
2.2 更快的响应时间
第一个优点,即更快的响应时间,是由于客户(可能是正在访问Web 站点的某个人,也可能是另一个公司的计算机系统)不需等待任何定单处理过程开始进行的结果。在同步系统中,用户在整个操作(例如提交定单)结束之后才得到响应。
图 2.同步操作的累积滞后时间
在异步系统中,提交定单之后,客户的延迟时间仅仅是将该定单传递给进程中的下一步所花费的时间。在某种程度上,这样的更快响应时间只是一种假象,因为客户收到响应时该进程并未真正完成,但客户不需要再等待了,这是重要的优点。
图 3.在异步模式中滞后时间缩短
2.3 负载平衡
在接收高流量通信的系统中,人们常常希望将负载分布到多台服务器上,并且还希望根据需要调整这种分布以适应计算机数量的变化。有多种不同的方法处理系统的负载平衡问题,但异步处理所要求的基础体系结构能够在不增加额外软件的情况下轻松地提供灵活的负载平衡能力。
如上所述,在异步系统中,需要某种形式的中间存储或队列来存储步骤之间的请求。当一份定单完成了某步骤中的进程工作时,它就被放到队列中等待进行下一步进程。当下一个步骤准备好处理另一份定单时,它就从这种挂起请求列表中抓取一份定单。要完成这样的系统中负载平衡的实施,只需要增加计算机的数量,由它们处理挂起列表中对步骤 B 的请求。
图 4.在处理步骤 B 的节点群集之间实现负载平衡
采用中间队列之后,在负载平衡和可伸缩性方面都获得了很大的灵活性。在该系统的前端或后端都可以放置任意数量的计算机,而且这种灵活性适应于任何一个进程步骤。可以在每一个步骤中使用适当数量的硬件对系统的性能进行微调,也可以在一台计算机上将多个步骤结合在一起进行处理。2.4 容错能力
异步体系结构可以让系统具有容错能力,这样,即使在进程中出现中断,整个系统也不会崩溃。对灵活的负载平衡提供支持的功能同时也就是对容错能力提供支持的功能。如果某个软件或硬件故障删除了某个进程步骤,请求执行该步骤的那些挂起请求就在队列中等候直至该服务被恢复。这对进程中先前的步骤并不产生什么实际的影响,尽管总体进程时间可能由于故障而延长。如果遵循了上一节关于负载平衡所讨论的技术,很可能仅仅减缓某一步骤的进程,但并不会停止。同样的功能也可以通过使用群集方式来提供;群集可以在不进行任何负载平衡工作的情况下提供故障转移能力。
图 5.异步系统能够容忍一个或多个节点出现故障
在负载平衡的系统中,处理同一步骤的其他服务器可以继续从队列中截获请求;如果各服务器都已经以接近峰值的状态运行,整个系统的性能将下降。
注意 尽管采用请求队列可以提供容错能力,但队列本身可能成为关键的故障点。用于确保这些队列可靠性的方法依赖于实施队列时所采用的特定技术,但一般都涉及故障转移群集以及将信息写入某个永久性的存储设备中,例如写入数据库中。
2.5 断续连接的系统
这种使异步系统具有容错能力的行为也同样能够让异步系统在无需始终连接所有工作流组成部分的情况下正常运行。在异步系统中,工作流中的某个阶段可能由业务合作伙伴来进行处理。而系统与合作伙伴的系统之间的连接有可能是间断的,或者仅在需要时才连接。因此,异步功能可以将不可靠通信链接的影响降至最低程度,而且还可以实现更经济的系统操作,因为它将通信资源的占用减至最少。
在断续连接的系统中,某个合作伙伴可以连接工作流过程并将一个或多个请求置入工作流过程中排队,也可以接收某一具体步骤的处理结果并随后在自己的系统中进行处理。异步处理方式让系统之间相互独立;如果系统 A 与系统 B 能够在同一时刻相互连接,那很好;但如果不能在同一时刻连接,它们以后也能够进行通信而不会有任何麻烦,因为信息会被存储起来,直至与接收者接通。
图 6.使用中间队列能够支持断续连接的系统而不需要任何专门编程
断续连接的系统引入它们自己的一套体系结构决策,包括连接的频率、在连接时期之间对请求进行批处理、处理失败的连接尝试,等等。需要这种系统的常见场合是,必须与某个外部合作伙伴打交道以处理付款或处理定单实现;对于需要采用拨号连接而并不采用网络链接的所有情况,也需要这种系统。由于支持了断续连接,在资源总可以获得但连接数量受到限制的情况下,系统可以将对资源的占用减少到最低程度;限制连接数量的原因可能是许可证、配置或系统容量方面的限制——例如数据库、FTP 服务器以及带有服务广告协议(SAP)等其他后端系统的会话。异步系统的问题
在使用异步处理时,有几项功能比同步方案实施起来更困难,这样的功能如下:
利用通知或轮询进行状态跟踪 处理超时
创建和执行补偿逻辑
3.1 对状态进行通知或轮询
在同步系统中,调用进程要等待调用返回之后才继续向下执行;虽然这对性能和系统响应有负面影响,但它也有一些优点。在调用确实完成之后,它可以一同返回某种形式的状态消息,例如进程成功或进程失败。一个简单的例子可以说明此问题:将新定单插入数据库中,同时获得数据库生成的新定单 ID。如果对数据库进行同步调用(或许通过某个组件进行,由该组件处理实际的数据库工作),可以立即发回该定单的 ID,也可以表明该定单是否已经成功地添加到数据库中。但在异步系统中,虽然发出了插入定单的请求,但是实际的插入动作却未同时发生,因此,此时无法返回数据库生成的 ID,系统也不知道是否成功插入。获得已提交请求的状态以及创建 ID 这两个概念是紧密联系的,因为任何异步形式的状态跟踪都需要一个唯一的 ID。
3.2 生成跟踪 ID 在异步系统中工作可以采用多种方法获得跟踪 ID,但在选择这些方法时,必须牢记对系统进行去耦处理这一目标。可以在对请求的提交进行处理时同步生成 ID,由此获得 ID 并在随后以异步方式将该请求传递给进程的其余部分。但这种解决方案有损于采用异步处理所带来的优点,因为它至少会将请求的提交与请求处理的第一步紧密耦合在一起。
另一种方法是,由提交定单的系统生成 ID,这样可以保持系统的异步特点,但却丧失了在一个位置生成唯一 ID 的简单性。为了保证提交方生成的 ID 具有唯一性,通常采用两种方法:
以随机方式或半随机方式生成 ID,通过随机数长度来保证唯一性,或者根据系统中唯一的硬件组件生成某个数码来保证唯一性(GUID 常被用于此目的)
- 或者 -
首先获得在单个提交系统中唯一的 ID,然后将此 ID 与提交方的标识符一同发送,从而生成一个组合的唯一 ID。
倾向于选择第二种方法,因为它与处理采购定单(PO)所采用的(现在仍在使用)一般处理很相似,此类公司采购定单常以批处理方式提交;这样的话,与现有系统协同工作时就很容易转换。提交方,即 PO 情形中的公司,拥有他们自己的系统,可以生成唯一的 PO 编号,然后他们将该编号与其公司的标识符(既可能是客户 ID,也可能是系统 ID)一同提交。在提交方需要确定特定定单的状态时,他们也将这些信息组合起来使用。在接收端,仍然可以在定单处理系统中生成一个唯一的 ID 并在内部使用,但客户的 PO 编号并不删除。
图 7.来自提交系统、含有引用 ID 的传入消息
3.3 状态跟踪
如上所述,必须拥有唯一的 ID 才能在异步系统进行状态跟踪。那么,如果有了该 ID,如何跟踪请求的状态呢?异步系统中的状态跟踪通常采用下面两种形式之一:或者向原始调用者发出通知(定期发送状态消息,或在特定事件发生时发送状态消息),或者使用某种形式的轮询机制让调用者自己负责查询状态。还有第三种可能性,不准备在这里详细讨论了,因为它实际上并不适合企业系统;这种可能性是,发出调用的系统不需要关注其请求发生了什么结果;它仅发出请求而已,并不需要知道最后是成功了还是失败了。两种状态跟踪形式可以简单地描绘为“喂,的定单准备好了吗?”以及“喂,定单已经准备好了”。它实际上就是谁先打招呼的问题。
图 8.利用通知进行状态跟踪
一般将通知视为最有效的进程状态跟踪的方式,因为在这种方式中,只有项目状态发生更改时才发送信息;而在轮询方式中,可能会出现许多不必要的状态请求。
图 9.使用轮询方式进行状态跟踪
但事情并非总是如此;如果检查请求状态并不是一项很频繁的操作,基于查询的状态系统可能更为有效。为了取得最大的灵活性,建议两种方式都实施,既实施能够对状态进行请求的机制,也实施状态通知机制。们以一个允许在线订购产品的 Web 站点为例;发出定单之后,通常会回到 Web 站点上查阅定单的当前状态(只要乐意,随时都可以查询),但该 Web 站点也可以在定单被接受、处理及发货时发出电子邮件消息。两种状态跟踪形式都很有用,两种方式也都对处理系统有相同的隐含要求;每一项请求的状态都需要跟踪。
3.4 超时处理
异步处理的主要好处之一是,不必等待每一步都完成;但仍要考虑整个进程需要多长时间才能结束的问题。为了保证定单或者正在处理的任何形式的请求最终不会等待过长时间才能处理完毕,需要一种方法来指定每个异步请求允许花费的最长时间。实施超时机制是防止定单在系统中耽搁好几天的唯一办法。
3.5 补偿逻辑
与上述状态跟踪问题相似,在出现错误的情况下,补偿逻辑非常重要。实际上,如果假设每项请求都会成功,每项定单都能够成功处理,那么,系统的建立就会很省时间,设计上也会更简单。真正占用大部分设计时间和实施时间的工作是处理出现的问题——也就是处理异常情况。
补偿逻辑与数据库中的事务回滚概念相关——它在进程彻底失败时撤销任何已经完成的操作。在定单处理场合,当客户的信用卡未通过验证并因此取消定单时,补偿逻辑或许就包括撤销预留库存。根据这些事务进程技术的任一种技术,程序员可以明确声明某进程的所有步骤都是某项事务的一部分;如果出现错误,数据库或 MS DTC 提供的服务将撤销错误出现前已完成的所有工作。在异步系统中,不可能采用这些事务进程技术来管理进程中的所有步骤,因为这些步骤被不确定的时间所分割。必须实现自己编写的代码才能撤销进程失败时已经完成的任何工作。采用多种方法可以实现这一任务,但通用方法是在运行时对进程进行跟踪/审计,然后使用跟踪信息回退并逆转每一操作。这听起来很简单,但做起来却很麻烦;开发补偿逻辑是主要的工作。
在本文其余部分,将探讨在系统中实施异步工作流的多种不同方法,并解释每种方法如何处理上述问题。实施策略
为了解释创建异步工作流的多种不同选择,最好使用一个具体例子。对于本文其余部分,就使用一个定单处理系统的例子,如图 10 所示,定单必须经过一个简单的四步工作流。
图 10.由四步构成的简单工作流
并不是每一阶段发生的事情都与实施选择的讨论相关,但是们假定可以获得一系列.NET 组件(以及公开的 COM 接口)来处理每一步。
注意 在任何实际的系统中,可伸缩性和可靠性都是要考虑的关键问题。如果一套系统时常“丢失”定单(或者将同一份定单执行一次以上),任何这样的系统就不适合实际使用,因此,还应当谨慎设计软件系统和硬件系统,以保证可靠性。可伸缩性也是一个需要考虑的问题,尤其是面向公众的系统,其潜在用户量是非常大的。在本文描述的所有三种实施方法中,将讨论在使系统能够根据需要进行扩展的同时保证可靠性的措施。
根据必须由自己动手创建的实施工作量,将实施工作流的选择划分为三个不同的途径:
利用 Microsoft SQL(TM)Server 利用 Microsoft.NET 和 Microsoft 消息队列(MSMQ)利用 Microsoft BizTalk(TM)Server 第一种选择说明在实施解决方案时不需要依赖任何专为工作流设计的预建机制。在本例中,就是使用 SQL Server 来创建自己的队列系统,并自己编写代码处理实际移动和处理通过定义的工作流的定单。第二种选择使用操作系统提供的 MSMQ 功能来实施定单在处理中移动时的队列编排工作,但仍然要自己提供代码来控制定单从一个队列到另一个队列的移动,以及调用每个组件。最后一种选择是购买一套系统,即 BizTalk Server,由它来处理整个工作流过程,自己仅使用该工具定义工作流即可。当然,在以上三种方案中,都需要实施表达工作流中每一步发生的实际处理工作的组件。然而,值得指出的是,如果某步骤主要是转换、存储和检索各个系统中的消息,BizTalk 可以完成大部分此类任务,根本不需要编写代码。将逐一介绍每个选择方案,并解释如何在每一实施方案中处理本定单处理的各种元素。
4.1 利用 SQL Server 构建自己的工作流
4.1.1 解决方案描述
要使用 SQL Server 构建自己的工作流系统实施方案时,有多种选择。可以为工作流中的每一个状态(等待验证、已经发运,等等)创建不同的表,然后通过在表之间进行插入、删除操作将消息(例如,定单)在不同状态之间进行“移动”。这非常类似于队列系统中的工作流进行工作的方式(例如 MSMQ,将在下一实施选择方案中讨论),但让 SQL Server 从事它不擅长的工作并没有什么好处。
另一种可选模式是仅使用一张表来存储消息,并采用一个附加字段来保留当前状态。将一条消息从一个状态转变为另一个状态只涉及对该状态字段的修改,而所有的消息始终保持在原位置不动。如果要将 SQL 用做工作流引擎,建议采用这种模式,它可以创建另一张表来跟踪定单进入处理每一步的日期和时间。4.1.2 实施细节
特别符合异步业务处理概念的操作示例是在数据库表中插入新定单。在通过 Web 站点或另一个系统提交并接收定单之后,SQL Server 实施将由下面几个关键元素组成:保留定单及相关信息的表,完成每一步处理工作的组件,跟踪表的工作流,以及协调定单在此处理中移动的程序(即控制器)。由于本系统可能具有的去耦特性,该控制器不可能仅是一个程序;实际上,它由在各种不同计算机上运行的多个不同的程序组成。无论分布方式如何,控制器的概念体现了与工作流有关的全部代码;消息要在各个步骤之间移动,就需要运行控制器。使用.NET 后,这些控制器可以按照 Microsoft Windows? 服务的方式来编写,它们不间断地运行并处理任何挂起的定单;也可以按照应用程序的方式来编写,将其设置为在特定的时间运行。在基于 SQL Server 的系统中,控制器代码可以遵照下面的基本行为模式:
For a particular step:
Query database for the oldest records at this stage
(SELECT TOP 1 * FROM Order
WHERE Order.CurrentStage = i
ORDER BY Order.Date ASC)
If order exists then Proce record
Add entry to Tracking/Auditing table
Call Component(s)to proce Order
If succeful
Update Tracking table
Move Order to next stage
(UPDATE Order
SET Order.CurrentStage = Order.CurrentStage +
WHERE Order.ID = ID)
If failure
Compensating Logic for all previous steps(i-1
to 1)
Update Tracking table 为了获得最佳的性能和最大的灵活性,可以为每一个阶段创建单独的控制器实例,也可以在每一阶段自身的线程中处理该阶段的工作;在两种方式中,控制代码都可以根据需要在不同计算机之间保持隔离。
将 SQL Server 用于工作流的主要好处是所有的东西都存储在一个数据库中。将所有的定单和它们的状态都存储在 SQL Server 之后,就有可能通过一个简单的查询来检查定单的当前状态,同时也容易通过使用相关表来实现与其他系统(这些系统可能也在使用数据库,甚至或许是相同的 SQL Server)的集成。但使用 SQL Server 也有它的缺点:主要是,它并非一部工作流引擎,而是一套数据存储系统。因此,SQL Server 对工作流系统的许多功能都没有提供支持,必须构建将 SQL Server 用作数据存储系统的自己的工作流引擎。超时就是一个例子,它是工作流环境中必需的功能,但 SQL 不处理它。为了处理超时情形,需要一个程序(或许还要与工作流逻辑的其他部分结合在一起)来定期扫描表,以发现超过规定时间长度的记录并将它们处理为超时消息。4.1.3 多线程开发
当多个处理查找同一阶段的记录时,就会遇到使用 SQL Server 的另一个问题。关于这个问题详细讨论已经超出了本文的目的,但很有必要关注这个问题,因为它极好地说明了异步及多线程应用程序所面临的问题。如果两个或多个处理试图同时处理同一阶段的工作,在使用为控制器处理提供的伪代码时就会出现问题。第一个处理将检索在某特定阶段最旧的记录,并将该记录发送给不同组件进行处理。只有在这些组件返回了更新的记录,才表明它已准备好移动到下一阶段。从检索到最终更新之间,另一个处理或许也在处理相同阶段的工作,而且它也会经历同样的步骤。在第二个处理检索该特定阶段最旧的记录时,如果第一个处理还没有进行更新操作,也没有完成其数据库的事务处理,那么第二个处理就会检索到与第一个处理一模一样的记录。此相同记录随后将再次发送给各组件,从而造成潜在的重复处理问题。有两种方法可避免此问题。第一种方法是在事务处理期间对该 Order 表使用排他表锁,只有这种方法才能阻止第二个处理在第一个处理完成之前对该表执行 SELECT 查询。这种方法能够发挥作用,但其结果是封锁了所有其他处理(甚至包括其他计算机上的处理),使得它们在此处理完成通过当前阶段的第一个定单的操作之前一直都不能访问该表,这实际上是取消了并行处理的可能性。
第二种方法是对处理稍做修改以避开此问题——仍使用排他表锁,但只限制在较短时间内。这种方法不是在对定单进行处理的全部时间内锁定表,而是在启动事务处理、进行 SELECT 操作(包括排他表锁)后即对记录进行更新,将其标记为可以继续进行其他处理。可以使用多种方法对记录进行标记,包括设置布尔值标志或者将其更新为某个特殊的状态代码。在UPDATE 执行完毕后,可以立即提交该事务并解锁。随后即可对该定单进行其他处理,对其他处理的封锁时间也不会大于执行 SELECT 和 UPDATE 所占用的时间。作为一个存储过程,这类似于下面的代码:
CREATE PROCEDURE GetNextOrder
@Step int,@OrderID int output,@OrderDate datetime output,@CustomerID int output,@OrderStatus int output,@SubTotal money output,@Tax money output,@ShippingHandling money output,@ShipToName nvarchar(50)output,@ShipToAddreId int output AS
DECLARE @NextOrder int SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION
SELECT TOP 1
@NextOrder = Orders.OrderId,@CustomerID = Orders.CustomerId,@OrderDate = Orders.OrderDate,@OrderStatus = Orders.OrderStatus,@SubTotal = Orders.SubTotal,@Tax = Orders.Tax,@ShippingHandling = Orders.ShippingHandling,@ShipToName = Orders.ShipToName,@ShipToAddreID = Orders.ShipToAddreId FROM [Orders] WHERE [Orders].OrderStatus = @Step ORDER BY [Orders].OrderDate ASC
UPDATE Orders SET OrderStatus = OrderStatus + 50 WHERE OrderID = @NextOrder
SELECT @OrderID = @NextOrder
COMMIT TRANSACTION SQL Server 能够很快地执行此事务处理的各个步骤,因此表锁的封锁并不会对整个系统的性能造成明显损害。
注意 尽管此例使用了轮询方法来查找新定单,但也可以在 SQL Server 中使用通知模式,只是后者需要更多的“自制”代码。4.1.4 可伸缩性和可靠性
使将 SQL Server 用作工作流引擎的系统具有可靠性和可伸缩性的方式与使将 SQL Server 用于其他目的的系统具有上述特性的方式是一样的。在数据库场合,处理不断增加的负载的主要办法就是“升级”,即在运行数据库的计算机中增加内存和处理器。可以将一个数据库分布到多台计算机上,以利用联盟服务器(federated server)和分区等功能实现分配负载的目的,从而支持极其大量的负载;但如果有 8 路CPU 或更大型的计算机,那么,通常一台计算机就足够用了。为确保可靠性,可以采用由 2-4 台计算机组成的故障转移群集;这样做的目的并不是为了提高性能,而是为了保证正常运行时间,因为它提供了多达三台服务器,它们可以在主运行服务器(live server)发生重大故障时接管系统的运行。
4.2 使用.NET 和 MSMQ 处理工作流
解决方案描述
.NET 框架使能够利用消息队列(MSMQ)以编程方式轻松地发送和接收消息,该解决方案就以此基本功能为基础。实施这种形式的工作流解决方案需要使用许多队列——其中一个用于表达工作流的各个阶段,还需要一套用来存储最终定单的数据库表和一个审计/跟踪表。与上述 SQL Server 实施相似,本系统的关键组件也是一个控制器程序,它编写为 Windows 服务形式,设计为处理与工作流有关的处理。该程序负责从队列中接收消息,针对每条消息调用适当的组件来进行适当的处理,然后将定单发送到下一个队列。4.2.1 实施细节
与上述 SQL Server 示例不同的是,本方式不通过轮询方法检查每一阶段的新定单,而是利用 MSMQ 的功能在控制器等侦听程序中激发事件。此外,还可以为每个队列创建一个线程,而且在不指定超时时间的情况下接收在每个队列上启动的处理。这两种方法之间的性能差异很小,但各自的代码差异却很大。为了获得审计与跟踪的详细信息,还需要某种方法来存储信息,因此,很可能还需要一个数据库表。
采用 MSMQ 有很多好处,因为 MSMQ 本身提供了异步处理所需要的许多功能。在消息等待处理时,它们存储在队列中;最旧的消息自动被最先处理,因为消息队列的规则是“先进先出”(FIFO)。放进消息队列中的消息有很灵活的设置,既可以处理向队列提交消息时的超时问题,也可以处理从队列中接收消息时的超时问题。MSMQ 还内置了一些高级功能,例如将某些消息标记为高优先级或低优先级。每条消息除了其主要内容(本示例中为定单)之外还有多个属性,它们提供了对该消息的进行审计的重要信息(例如 ArrivedTime、SentTime、SourceMachine 等等)。最后,MSMQ 的编程模式在设计上考虑了异步工作流问题,它在新消息达到时能够发出通知(通过事件),从而不再需要任何轮询工作。在 SQL Server 章节中讨论的锁定与并发问题在 MSMQ 中已经不成为问题;无论有多少个处理试图同时从同一个队列中检索一条新消息,MSMQ 都可以保证不会有两个处理收到相同的消息。指定给每一阶段的进程/线程数量是完全灵活的,可以根据系统负载的变化情况进行微调。
虽然 MSMQ 提供了许多与工作流有关的功能,但它与 SQL Server 一样不是一部工作流引擎,仍需要对控制逻辑编写代码,才能将消息从处理中的一个阶段转移到另一个阶段。但 MSMQ 的确为发送和接收消息提供了许多出色的功能,它们是工作流解决方案和组件的关键组件,如果在 SQL Server 基础上进行构建,必须自己对这些组件编写代码。4.2.2 可伸缩性和可靠性
在本实施中使用 MSMQ 时,或者作为 BizTalk 实施中的一个组件使用 MSMQ 时,可以利用 Microsoft 群集服务对 MSMQ 进行群集设置,从而为该服务器上的队列提供故障转移支持。除了为群集提供支持外,MSMQ 还有一项引人注目的可靠性功能,即使 MSMQ 能够处理那些几乎会摧毁任何其他系统的故障。消息发送到队列时——例如从 Web 站点上发送到后端 MSMQ 服务器上 ——这是一项异步操作,即使消息尚未提交,它也会立即返回。如果网络出现故障或者服务器无法使用,就不可能抵达目的地队列,消息将自动存储在发送方计算机上(本示例中,就是 Web 服务器上),直至与目的地接通。这种机制被称为“存储及转发”(store and forward),经常用于允许移动用户脱机使用应用程序,并且还创建了一种容错能力更强的系统。在相似情形中,如果将 SQL Server 或其他数据库用作后端处理,那么必须自己将其构建到系统中才能实现“存储及转发”。5 小结
异步工作流是很强大的体系结构,它不仅能够提高系统的可伸缩性和可靠性,也是处理自动业务处理的好方法。本文介绍了三种不同的方案,通过这些方案可以为系统添加异步处理功能,但必须选择哪种实施方案最适合系统。下一步涉及的是要在自制和外购之间做出选择。就自制而言,还有两种选择。所有事情都自己解决,而不利用 MSMQ 的优势,似乎是效率最低的解决方案,但它将所有的东西都放到 SQL Server 上,这使得文档跟踪以及集成到系统的其余部分变得非常容易。采用 MSMQ 可以让先声夺人,并且还能够带来许多构建解决方案所必需的异步功能,这样,只要根据需求编写控制逻辑以在工作流中移动消息即可。最后,即使采用 BizTalk,仍然必须创建对各个阶段进行处理的组件,这在所有这些解决方案中都不可避免,但 BizTalk 提供了所有其他的工作流元素。
如果需要实施的是运行在一台服务器上一成不变的工作流,那么自己动手构建系统也是很实际的想法。如果希望支持多个工作流,工作流变化相对频繁,或者需要运行大型服务器组,那么需要重复完成大量的 BizTalk 功能,其成本可能会比 BizTalk 本身要高许多。一个主要的决定性因素是对支持的要求,因为自己的解决方案不大可能得到像 BizTalk 这样的外购产品所提供的支持水平。最后,所有这三种解决方案都是在应用程序中实施异步工作流的切实可行的方法,其差别取决于具体需求。