SOA实现服务设计应遵循的原则

[摘要]仔细地进行服务设计可以避免对状态对话的需求,从而简化可靠的可伸缩 SOA 基础结构的实现。有用的计算机系统通常将为有状态的;通常反映了业务对象的生命周期。

(中国软件网讯)在本地调用时,清单3所示的服务接口可能能够正常工作。不过,如果服务是在远程位置向使用者提供的,则该服务在常见使用场景中的性能可能会很差。例如,在使用服务检索数据来填充显示书的目录项的屏幕时,将有必要进行多个独立的远程调用,以检索书名、作者和出版日期。进行这些调用可能会有很大的性能损失。远程服务应提供粗粒度的操作,以在单个调用中检索关于某本书的所有信息。

可远程调用的服务的这个设计原则得到了广泛的认可;我们在此处强调此原则的目的在于说明被封装的服务调用细节可能给我们如何选择设计方法带来很大的影响。我们认为,同步调用和异步调用之间的选择也可能对服务接口设计有类似的影响。

这就引入了一个重要的问题:设计服务时,什么决定了所使用的调用方式?服务设计人员是否可以自由选择本地调用和远程调用、同步调用和异步调用?我们建议 SOA 应对这方面进行说明。我们提出此建议有两个原因。首先,我们希望通过确保一致性提高易用性;编排流程时,服务最好具有可预测的特征。其次,我们希望通过将使用者与提供者分离来提高灵活性。通过鼓励进行远程调用,我们可以进行位置、平台和编程语言分离。通过鼓励进行异步调用,我们可以分离使用者和提供者的可用性特征。

如果SOA要具有描述性,是否应声明所有服务都应设计为允许远程、异步调用?我们建议对此描述性采用更为细粒度的方法。可能的服务类型包括提供业务相关较多的操作,如PlaceOrder,也包括技术性侧重较多的操作,如CheckUserInRole。SOA完全应该对不同的服务类别进行不同的描述。我们预期将更多地调用与业务相关的操作,而技术操作完全可能采用本地调用的方式。

服务具有无状态接口

我们在服务应设计为可重用中提到,应该将服务设计为可伸缩且可部署到高可用性基础结构中。此总体原则的一个推论就是,服务不应为有状态型的。即,它们不应依赖于使用者和提供者间长期存在的关系,操作调用也不应隐式地依赖于前一个调用。为了说明这一点,我们以下面的电话转换为例:

清单4. 有状态转换

Q:What is Dave's account balance?

A: It's £320

Q:What's his credit limit?

A:It's £2,000

此示例演示了转换的两个有状态方面。第二个问题通过使用“his”引用第一个问题。这个示例中的操作依赖于转换上下文。现在让我们考虑一下所提供的应答。请注意,响应中没有上下文信息。应当只有在询问者知道所询问的问题时,这个应答才有意义。在此示例中,要求使用者维护对话状态,以便解释所得到的应答。这两个有状态关系(连续的调用之间和请求与响应之间的关系)都与SOA服务设计有关。

首先,我们考虑一下依赖于前一操作建立的上下文的操作。假如这是一个与呼叫中心的交互。只要与同一个操作人员对话,对话就可以有效地结束。但我们假设呼叫被中断了,如下所示:

清单5. 被中断的有状态转换

Q:What is Dave's account balance?

Operator 1: It's £320

An interruption occurs, and the caller talks to a different operator.

Q:What's his credit limit?

Operator 2: Who?

中断导致上下文丢失,因此第二个问题是没有意义的。就这个电话对话而言,我们可以通过重新建立上下文而抵消中断带来的后果:“我在问Dave的银行帐户的信息,您能告诉我他的信用额度吗?”不过,在可扩展服务调用领域,有状态对话通常更为麻烦,在此领域中,重新建立上下文可能在技术上不可行,或者可能带来很大的性能开销。

通常,构建可伸缩的可靠基础结构与允许有状态交互之间有紧密的关系。创建支持有状态的服务调用的SOA基础结构在技术上可行。可以使用的技术包括:

·使用Http Cookie维护会话上下文

·使用有状态会话EJB;Bean的句柄在SOAP Header中传递

不过,我们必须仔细考虑最终基础结构的可伸缩性和可靠性。是否要求使用关联性?即,相同的使用者发出的连续请求是否必须交付到相同的提供者实例?要求使用关联性是一种有状态性与可伸缩性及可靠性冲突的情况。如果基础结构可以随意将请求提交到多个提供者实例中的一个,就可简化负载平衡,而各个提供者实例的可靠性要求就可缓和。

如果没有关联性需求,且允许基础结构将一个使用者的连续请求交付到不同的提供者实例,则任何会话状态必须对所有提供者实例可用。应用服务器基础结构提供会话复制机制。此类机制可以用于提供会话状态,但使用它们会有性能损失。而且,我们的Web开发经验表明,如果没有可靠的指南,开发人员将可以随意使用会话状态;过度使用HTTP会话通常是导致性能低下的常见原因。请参阅“Performance Analysis for Java Web Sites”(作者:joines、Willenborg和Hygh,第59页—60页,Addison-Wesley ISBN 0201844540)。

我们强烈建议,服务应设计为可避免维护会话上下文的需求。

现在,让我们考虑一下对话的其他有状态方面以及请求和响应间的关系。我们是否要采用上面的电话对话方式进行服务设计,依赖会话上下文来解释响应“What is Dave's credit limit?”——“£320”——然后我们将对SOA基础结构再次进行约束。

基础结构必须适应各种可能性,如某些使用者无法在临时停机的情况下保留其会话状态。

我们可以通过将服务设计为在响应中包含合适的关联信息,从而避免会话状态的需求,例如以下的响应:

清单6. 包含关联信息的对话

Q: What is Dave's credit limit?

A: Dave's credit limit is £2000

该响应既标识人员又提供具体的数据。当包装遗留系统时,通常由适配器负责提供此类关联信息。现有同步API完全有可能不提供关联数据。在响应中包含关联信息之所以是很好的做法,有很多原因。首先,它简化了弹性可伸缩解决方案的构造,还能提供很大的诊断帮助,且在不可能向原始请求程序交付错误响应时非常重要。未交付的消息可能放置在错误队列上,每个此类消息的解释都要求使用上下文信息。

总之,仔细地进行服务设计可以避免对状态对话的需求,从而简化可靠的可伸缩 SOA 基础结构的实现。

服务应使用状态事务建模

前面给出了一个总的建议,以避免依赖对话状态,但我们应当记住,有用的计算机系统通常将为有状态的;通常反映了业务对象的生命周期。




免责声明:

本站系本网编辑转载,会尽可能注明出处,但不排除无法注明来源的情况,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与本网联系, 来信: liujun@soft6.com 我们将在收到邮件后第一时间删除内容!

[声明]本站文章版权归原作者所有,内容为作者个人观点,不代表本网站的观点和对其真实性负责,本站拥有对此声明的最终解释权。