应用程序结构:概念视图-6状态(企业结构)

本页内容
状态简介状态简介
业务处理业务处理
使用其他服务使用其他服务

				联机处理和脱机处理
			联机处理和脱机处理
状态小结状态小结

服务管理状态;这里所指的状态就是服务存在的原因。 服务保护此状态,通过其业务逻辑确保状态保持一致并且正确无误。 此状态是唯一真实的当前信息源。

状态简介

几乎所有服务都管理持久状态;也就是说,存储在某种持久介质(例如,文件系统或数据库)上的状态。服务从另一个服务接收请求,从持久介质中检索某个状态,然后生成响应或更新该状态。利用持久状态,服务可以暂时停止而不会丢失上下文;当服务再次恢复时,持久状态仍然原封不动,服务可以继续进行,就好象什么也没发生过。服务尽力使持久状态保持一致;当然也希望使内存中的应用程序状态保持一致,但如果发生问题,服务只是中止处理,忽略其内存状态,之后使用持久状态重新设置。 服务常常使用 ACID 事务来保持一致的持久状态。 事务是作为单个逻辑工作单元执行的操作的序列。 ACID 事务必须具备四个属性,称为 ACID 属性:

Atomicity(原子性)。 工作单元不可分;要么执行所有数据修改,要么不执行任何数据修改。

Consistency(一致性)。 事务完成后,必须使所有数据处于一致的状态。

Isolation(隔离性)。无法在事务之外看到中间状态的数据。

Durability(持久性)。事务完成之后,其作用将永久地留在系统中。

ACID 事务通常涉及到数据库,因此也会涉及到数据的锁定。 服务不希望对不信任的人锁定其数据,因为如果锁定持续很长一段时间,其他使用者也无法访问。允许服务与其他服务加入原子事务意味着某种程度的信任以及某种程度的耦合。处理服务一般无法依赖于共享原子事务,因为服务可能或者不参与原子事务(许多旧式系统都无法这样做),或者可能处于远程位置(如在防火墙的后面,等等)。

服务应该通过设计实现良好的性能和出色的可维护性。 在设计上应该充分考虑到内部数据结构和数据存储之间的映射。与外界通信的设计有一些额外的要求,如接口的不变性,因此您可能不希望它匹配内部数据结构。这两种映射(数据存储到内部数据结构和内部数据结构到外界)可以不同,可以相互独立地进行设计。

业务处理

服务处理请求,有时必须处理多个请求才能完成一个业务事务。这个过程可以使用业务处理来组织,业务处理也称为处理,它控制执行某个工作的按步骤进行的操作,使系统从一个状态进入另一个状态。在每个步骤,业务处理执行一个业务操作。 例如,业务处理可以接受传入的定单请求,更新定单系统,发送响应,然后更新客户关系管理 (CRM) 系统和生产系统。另一个例子是管理整个订购、交付和支付过程的处理。这个处理会接受报价请求,发送所请求的报价,接受定单,检查是否能满足定单要求,发送定单确认,安排交付,发送发票,等等。每个步骤都使该处理从一个一致状态进入下一个一致状态。

处理涉及三种持久状态:

永久状态。这是由处理更新的状态。 这是我们在谈起服务状态时通常总会想到的状态。 在前面的示例中,此状态就是定单数据库和 CRM 数据库。 此状态在处理完成后仍然存在。

处理状态。业务处理可以保持其状态;这样服务就可以停止处理和重新启动处理。在前面的示例中,如果在一个业务处理的整个持续时间内使该物理处理一直运行在计算机上,显然没有什么意义;因此,业务处理保持其状态并停止在那里。当接收到该处理的消息后,处理重新启动;处理检索其状态,然后处理请求。 打个比方,处理会脱水再水化。我们将处理的保持状态称为处理状态。 处理状态只在处理的持续期间存在,当处理完成后,处理状态即被删除。

消息状态。当消息从一个服务被发送到另一个服务时,是在内存中创建的。 消息在创建后被传输,然后最终在另一端的内存中被具体化。不过,当使用如队列这样的存储转发机制时,消息持留在队列中,然后被传输,接着持留在另一端,在消息源被删除。 在接收端,整个过程的发生很类似。消息被接收,进行某种处理,如果一切顺利,消息从目标端删除,不过也可以保存消息,以便进行审核和跟踪。 消息状态在消息被发送时存在。

正象前面所提到的,消息从一个一致状态进入下一个一致状态;所有这三种状态的组合必须在每个步骤后保持一致。 处理必须在一个 ACID 事务中存储改变的永久状态、处理状态和消息状态。

事务性消息处理

在 ACID 事务期间,不会引起任何更新的消息可以在任意一点自由发送,也可以接收响应。只要发送消息产生实际效果,例如,更改接收者一端的持久状态,就需要确保只有在事务提交时才能发送消息。 例如,您可能需要只有在定单被接受时才更新 CRM 系统;因此您需要只有在定单事务提交时才将更新消息发送到 CRM 系统。

当消息的发送是事务的一部分时,如果事务中止,消息就不会被发送。 这说明,消息只能在事务提交后发送。 这就意味着,不可能在同一个事务中接收响应。

同样,在一个事务中接收消息意味着,只有当事务提交时消息才离开消息处理基础结构。

对于事务性队列系统,这是一种典型的行为。

事务性处理

处理按步骤执行业务活动。 处理可以更新其持久状态,可以发送消息,可以保持自己的状态。每个步骤可以由多个操作组成,每个步骤都使处理从一个一致状态进入下一个一致状态。 每个步骤可以包括在一个 ACID 事务中。如果永久状态、处理状态和消息状态的组合是一致的,就可以认为状态是一致的。例如,您要进行借方记入和贷方记入,如果借方记入完成后处理状态知道仍然需要完成贷方记入,就说明状态是一致的。 在前面的例子中,如果定单被接受后处理知道 CRM 和生产系统需要更新,说明状态是一致的,或者,如果定单被接受后消息已经发送到 CRM 系统和生产系统,也说明状态是一致的。

图 1 说明了处理服务如何逐步执行一系列事务。

bdadotnetarch08_03

图 1. 处理中的事务性步骤

长期运行的事务

处理常常无法将一系列步骤合并到一个 ACID 事务中;之所以会这样,原因是处理必须等待来自另一个服务的结果,或者因为步骤需要的时间太长。处理常常使用长期运行的事务这一概念来确保正确的结果。长期运行的事务包括业务处理的一部分,它定义了在发生异常、不得不取消事务的情况下,对已执行的任何操作进行补偿而需要执行的逻辑。只要活动无法结合到一个原子事务中,长期运行的事物就非常有用。

本文讨论的是补偿操作的效果而不是撤消操作,因为我们常常无法恢复原来的状态;在很多情况下,撤消操作可能甚至并不可取。例如,已经进行了一次总帐记录,不可以只是通过将帐面值改回去、从日记帐和报表删除项目来撤消该操作。而是应该需要进行另一个记录来补偿原来的记录。

如图 2 所示,发票和付款的发送和接收是一个长期运行的事务。 如果订购的货物不能全部交付,可能需要取消发票,或者进行部分退款。这与撤消完成的工作有所不同,因为系统并不返回原来的状态,而是补偿已经执行的工作。

bdadotnetarch08_03

图 2. 事务类型

再举一个例子: 您可以预定一个旅馆房间,后来再取消预定。 系统必须能够保留该预定,但可能会要求您支付管理费,因此它不会返回原来的状态。

如果业务服务或用户希望取消事务,将向业务处理产生一个异常,然后由异常来确保执行补偿事务,补偿事务本身可以由一个或多个长期运行的事务组成。如果没有长期运行的事务,异常的处理就会变得非常复杂。

使用其他服务

服务包含状态,当前状态始终保留在服务内,以防止受到外界的攻击。 服务不仅使用本身管理的数据,在许多情况下,还使用从另一个服务获得的数据。

快照数据

在服务之外释放的任何数据都是快照。一般说来,快照是服务内保留的状态的有限视图,但不一定是当前视图,因为服务内的状态在快照创建后可能已经发生了改变。

引用数据

引用数据由多个快照组成,每个快照包含服务代理请求时和请求后已创建的不同数据集。当服务代理保留此引用数据供以后重用时,我们称之为缓存。 服务代理可以存储从一个或多个服务产生的快照。因为引用数据由不同时间获得的不同快照构成,有些快照会比其他快照更旧,包含当前数据的可能性就更小。

由于这个原因,引用数据应该被稳定,以便随空间和时间的改变一直能够保持价值。 可以通过许多方法来实现该目的,包括:

添加时间戳例如,进行股票价格报价时,当价格产生时开始报价——“(<时间戳>)时的股票值是<值>。”

添加有效期。例如,指定一个此数据一直保持有效的期间——“价目表中的价格在 (<日期>)之前有效。”

确保引用保持有效。例如,使用价目表中的产品编号时,某产品的产品编号不应该在以后重用于另一个商品。如果发生这样的事情,使用过时价目表和错订产品或在两个完全不同的商品项之间比较提价情况的客户就会感到混淆。 产品编号不再存在总比错误地引用产品要好。

当您的引用数据稳定后,就可以在各种位置复制和使用,因为该数据的副本与正本一样有效。不过,数据有意义这一事实并不意味着它是可以信赖的;因为数据可能已经过时。 例如,可能发生这样的情况,您的库存有足够的配件使您在上午 9:00 点处理一个请求,但到下午 3:00 点时配件就不够了。

为了最大限度地减少发生这种事情的可能性,您应该制定出服务和服务代理之间的某种更新策略,以确保按适当的时间间隔重新创建在服务之外保留的引用数据。

服务代理和状态

服务代理在帮助创建将提交到服务的使用者请求时使用引用数据。 它依靠快照数据,快照数据可能反映服务中的当前状态,也可能不反映。

因为请求基于引用数据,而引用数据可能与服务内存储的当前数据不一样,服务必须能够处理过时的请求并解决该问题,最可能采用的方式就是拒绝请求。然后,由服务代理负责处理被拒绝的请求,可能使用的方法包括:更新其引用数据并重新提交请求,或与使用者就下一步采取什么措施进行沟通。

服务代理还可以负责管理每使用者数据。这种数据可能是用户为传递到服务而输入的数据,或者可能是创建新请求时所需的特定于使用者的数据。

您可以在服务之外任何处理数据的地方以及在不锁定的条件下处理数据的任何地方使用服务代理;在上述任何一种情况下,您使用的都是引用数据,也就是可能已经过时的数据。Web 服务、Web 客户端以及几乎任何服务使用者操作从其他服务获得的数据;它们处理引用数据以及每使用者状态。所有这些参与方都面临着使用引用数据的挑战。

联机处理和脱机处理

只要您工作在服务之外,您使用的就是快照数据。 这意味着,实际上,服务之外的所有工作在本质上都是脱机工作;也就是说,您使用的是非当前数据。创建快照的时间离现在越近,数据是当前数据的可能性就越大;不过,在设计应用程序时,您必须始终假设数据可能已经发生更改。

图 3 说明了所有快照数据,无论新旧,都不能被认为是当前数据。

bdadotnetarch08_03

图 3 快照数据不是当前数据。

我们通常所指的联机处理和脱机处理之间的唯一区别由来自服务的更新的频率决定,判定脱机处理的条件是:在重新连接之前不能执行请求,无论是对信息的请求还是对更新的请求。

例如,如果您使用的是脱机电子邮件系统,您的收件箱可能没有处于最新状态;不过,这或许不能算是个问题,因为电子邮件本身在服务器端等待被下载时不会发生更改。可是,当脱机使用一个日程编排系统时,您可能会发现并发问题,因为您和其他人可能为一个约会指定了同一天的同一时间。在这种情况下,系统必须能够检测,并且可能解决冲突。理论上来说,这种事情在联机时也可能发生,唯一的区别是,系统会更早地通知您预约冲突,您可以立即作出反应。

状态小结

服务的存在就是为了保护状态。 您允许其他服务通过许多定义明确的接口访问您的服务中的状态。例如,一个消息被发送到服务,该消息包括访问存储在服务内的状态的请求。 服务在收到请求后会更改该状态的一部分,或将它的一个副本发送回请求服务。

消息可以在一个 ACID 事务中发送或接收;不过,在一个原子事务中长时间地等待响应就显得不切实际,因此,可以使用长期运行的事务将部分业务处理合并到一个事务性单元。在这种情况下,操作没有被撤消,而是在事务中进行了补偿。 使用补偿事务可以使服务之间的错误处理变得更加简单。

虽然状态在服务中受到保护,但其他服务可能需要引用该状态来创建它们的消息。 使用从服务获得的引用数据可以实现此目的。您不能假设此数据是有效数据,因为它在您创建快照后可能已经在服务内部发生更改,因此您应该考虑用于稳定数据和处理包含过时状态的请求的机制。

转到原英文页面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值