求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
规划和处理面向服务环境中的超时
 

发布于2012-6-13

 

本文强调了所有面向服务的体系架构(SOA)的一个往往被忽视而又十分重要的方面:超时。通过本文了解某些特殊的非功能性需求只能通过谨慎设计在整个解决方案中使用的超时值来满足。

简介

管理异常情况是所有软件解决方案的一个重要方面。系统不可用的原因可能包括硬件或网络问题、供应商软件包含 bug、应用程序应用户错误而出错。设计和开发工作必须谨慎,确保解决方案能够完美地处理类似这样的情况。在开发面向服务解决方案时也是如此 —— 而 SOA 解决方案旨在比其他软件解决方案实现更松散的耦合,这又增加了合理进行非功能性设计、开发和测试的要求。

在非功能性解决方案设计中,一个往往被忽视的方面就是超时。在解决方案设计中有多个应配置超时的点。超时可在不同的级别上进行 配置,通过代码动态设置、从管理角度上更改、由您所在域意外的客户进行设置。必须协同观察和处理所有这些不同的超时定义方式,以实现所需的端到端行为。本 文重点关注超时,全面的探讨了这些元素,此外还观察了如何通过 IBM? WebSphere? 产品组合中的某些产品管理超时。

什么是超时?

对于超时,也许存在着多种正式和非正式的定义,但出于本文讨论的目的,让我们将其定义为软件逻辑在等待特定事件发生时继续处理的最长时间。 这里的软件逻辑可以使用较为高级的编程语言编写,可作为汇编程序逻辑在计算机芯片上执行。但无论是怎样的情况,超时都会导致此逻辑等待某些事件发生,如果 这样的事件在预定义的时间段内未发生,则将停止 “成功” 执行流,将这种事件未出现的情况作为某种类型的异常。如果事件在指定时间过期之前发生,则继续进行正常执行。

为了合理限制上述类型的超时的范围,本文后续内容将关注适用于使用基于 Java? 的应用服务器和 IBM WebSphere 产品的面向服务环境的超时。这些超时的指定方式和位置有多方面的差异:

  • 程序性的,通常是连接协议或在线程管理中。
  • 管理性的,通过应用服务器管理控制台或事务处理和用户会话通用的脚本完成。
  • 由客户端发出请求

程序性的示例:使用 Java Messaging Service(JMS),为在 javax.jms.MessageConsumer 类的 receive() 方法接收到一条消息时定义的超时值。另外一个示例:使用 Java Enterprise Edition (Java EE) 应用服务器(如 IBM WebSphere Application Server),您可以使用 “工作管理” 支持,在新线程上启动所谓的异步 bean,随后等待此线程完成,定义当前线程等待此线程完成的最大时间值。

管理性类型的超时不是以程序方式设定的,而是可配置的,例如,在应用服务器中配置。WebSphere Application Server 使用的一种典型的超时就是默认事务处理超时,它定义了在自动回滚之前一次事务处理最长可运行多长时间。在为客户端编程时,另外一个可配置的超时就是默认 HTTP 超时,用于指明出站 HTTP 请求在等待结果消息返回时的最长时间,超出此时间客户端将发出错误信号。

另外一种同样可配置的超时是在跨多个服务器和客户端运行的应用程序上下文中使用。此类超时可定义为指明不活动的用户(例如,使用浏览器访问受保护的 Web 站点)被视为已登录的最长时间,超出此时间将强制要求重新进行身份验证。这种会话超时也定义了服务器替用户缓存会话状态的最长时间(WebSphere Application Server 默认将此设为 30 分钟)。应用服务器 EJB 容器中的客户端不活动超时可用于定义一次事务在一个客户端的请求间保持打开状态的时间,超出此时间将回滚(顺便说明一下,默认值是 30 秒)。

除了使用标准 Java EE 应用服务器之外,许多企业都利用 IBM WebSphere Process Server 或 IBM WebSphere ES 等更高级别的产品。这就带来了更多将超时定义为其更高级别的功能的一部分的方法。例如,WebSphere Process Server 支持的 BPEL 语言允许指定接收活动的超时;也就是说,在处理等待外部消息抵达时。在 WebSphere ESB 中,可以在调出基元(callout primitive)上定义异步超时,定义仲裁将等待一个异步接收的响应多长时间。

上述的部分超时仅影响当前执行的线程,而其他超时(例如,默认事务处理超时)则应用于应用服务器上运行的任何线程,另外一些仅影响特定应用程序。因而,您可以定义三组不同的超时:

  • 线程级
  • 应用程序级
  • 服务器级

所有者三组中的超时均可以程序性或配置的方式设置,但程序性的访问通常是线程级的。

第四组超时是由请求的客户端设置的。例如,一个 Web 浏览器仅将一个服务器活动的 HTTP 连接保持预定义的特定时间。默认值通常是 300 秒,即 5 分钟。大多数或所有浏览器都提供了更改此默认值的方法。在服务器上,除了在处理请求时以某种方式传输(哑元)数据以避免浏览器重置连接之外,几乎无法影响 此行为。

上述示例仅仅是触及了超时的表层,展示了所有解决方案中普遍存在的超时。大多数可配置的超时都有默认值,设置为涵盖最常见的用力,因而您总是无需更改它们。但如您所见,大多数都是彼此交互的,因而值得付出时间去评估默认值是否适合您的需求,之后再将解决方案投入生产。

为使您能够合理设计超时值,每项服务都必须存档其所需的超时行为;换句话说,在正常条件下服务完成一个请求的预期时间。通常,此类信息是为服务水平协议(SLA)准备的。每一份 SLA 都必须考虑所调用的下游服务和组件所支持的服务水平。

中间媒介的影响

至此为止,本文所讨论的超时都是应用于两方之间的交互:消费者从队列接收一条消息、客户端用户在 Web 服务器中有一个会话、一个服务消费者调用服务提供程序并等待响应。然而,根据面向服务的准则构建的系统(如松散耦合和关注分离)总是会产生中间媒介。换句 话说,消息要流经多个跃点,最终才能抵达最终目标。两个独立跃点之间的每次交互都有自己的超时集,所有这些结合在一起,定义了服务定义的整体行为。

图 1. 带有中间媒介的示例场景

假设用户希望通过 Web 下订单。制造商提供面向服务订购系统的在线界面。此架构包括:

  • 一个 ESB 网关,处理安全性策略
  • 一个 ESB,用于消息协议转换
  • 一个实用服务,用于审计和记录传入的订单
  • 一个 Order 业务服务
  • 一个遗留的后端系统,运行在大型机上,是实际的订单管理和存储位置。

在这些组件之间,都有出现超时的可能性。此外,在各组件内发生的处理也可能会超时。与此同时,对用户来说最重要的就是他或她的订单得到即时的处理,如果无法即时处理,那么就会出现负面影响,比如说,订单的费用无法如期收取。

后一点尤为重要:避免负面影响。换句话说,如果没有真正的分布式事务处理(在 SOA 中,跨服务调用使用分布式事务处理并不常见),您要如何建立事务处理行为。在事务处理中,一组步骤要么全部发生,要么全部不发生。

设想一份新订单(假设它将转换为 Order 服务的同步请求-响应调用)将在后端执行,但在向消费者返回确认之前,与 Web 服务器的会话超时。消费者接收到错误消息是否可以接受?即便订单实际上已经在后端系统中执行了?答案取决于实际场景和相关的需求,有些普遍适用的超时指导 原则。

最重要的是,超时值应减少 “下游”。这也就是说,在被调用组件超时之前,调用的每个客户端都不应超时。这条经验规则的目标是为下游组件提供在调用堆栈的上游组件超时之前超时的机 会。将此规则应用到前述示例场景,即可得到如图 2 所示的远程调用超时设置。(图中所示的值仅用于示例。各超时值之间的时机差距将根据网络中的预计延迟和其他因素的不同而有所不同)。

图 2. 为示例场景应用超时值

可以将此方法转换为多跳环境中的简单超时值公式:

tn = tn+1 + Δn

其中 Δn 等于组件内花费的预期时间加上两个中间媒介之间招致的开销(例如,网络延迟、串行化等)。在上面,请注意,超时每步增加 1 秒,这并不是十分现实。如示例所示,这意味着链中最后一个组件提供的超时(本例中是遗留后端系统)确定必须为之前的所有组件配置的超时。

此外,您必须区分各组件之间的同步和异步通信。至此,我们假设是同步交互,调用的每个客户端都期待响应消息,并将等待之响应抵达或超时。如果 您向下游发送了一条 “单路” 消息,情况将大有不同,此时每个客户端仅等待消息的处理完成,或者说 “发送并遗忘”(fire and forget)消息。在此类情况下,超时不是重要考虑事项,因为上游组件对于处理请求下游的时限并无依赖。

例如,图 2 中 Utility 服务的调用可能是异步发生的,也就是说,与业务服务的调用并行发生。在这种情况下,可以设置业务服务调用的超时,而无须考虑 Utility 服务的行为。调用是同步发生的还是异步发生的,取决于 Utility 服务的特征。

在应用程序级别上,当存在给定请求的预期响应,但此响应是异步接收的时候,超时又重新成为重要问题。换句话说,客户端的执行线程可能会在请求 发送后被立即阻塞。并在稍后(或在并行线程中)显式轮询响应,如果响应在指定时间段中未出现,这种预期响应的接收仍然会导致整体交互超时。在这种情况下, 响应流中使用的超时值必须在与请求发送的时间关联的前提下设置。

动态超时处理

上文中的讨论假定静态、固定的环境。换句话说,图 2 假设各组件之间的超时总是固定的 —— 无论调用的是哪些服务,无论每条消息的内容是什么。

然而,在现实环境中,这并不恰当。例如,假设一个 ESB 与多个后端服务提供程序通信(当然,事实总是这样),不同的提供程序有不同的超时。如上文所述,所配置的超时值时由链中最后一个组件决定的。这就意味着, 若添加具有不同超时特征的新组建,之前的组件中使用的超时必须更改。在为示例添加新服务时,这一点尤为明显(请参见图 3)。

图 3. 添加多个服务提供程序

在这里,服务提供程序的添加需要 30 秒的超时值,强制要求 Web 服务器、ESB 网关等相应地增加超时值。

在添加需要更大的超时值的新组件时,不必静态增加超时,环境应能够动态适应这些新需求。超时值应根据所调用的服务调整,也就是说中间媒介会在运行时动态应用超时值。

图 4. 动态超时值

图 4 假设流经系统的所有消息都必须服从一组不同的超时,具体取决于哪个服务位于末尾处。

图 4 展示的是理想化的解决方案,因为某些组件可能不支持动态设置超时。此类示例之一就是浏览器和 Web 服务器之间的 TCP/IP 连接超时,这总是静态的(通常设置为 5 分钟)。

在某些情况下,为特定服务调整超时值还不够,在其他一些情况下,超时取决于一条消息的内容。此类示例包括服务提供程序访问多个带有不同超时需 求的后端系统,但仅在运行时才确定调用哪个后端系统。在实践中,这样的需求极难实现,让我们再回到示例场景,评估这项需求(请参见图 5)。

图 5. 添加多个后端

例如,假设,消费者向服务提供程序发送一条消息。服务提供程序解析请求消息,确定必须调用需要 5 秒超时的后端函数。之前的组件,如 ESB,不会知道要调用哪个函数,因而在讲消息传递给业务服务提供程序时,也无法回溯地动态调整所用超时。要解决这个窘境,惟一的方法就是使用超过可能调 用的任何下游组件所需最大超时的超时值。考虑到这一点,您可以对前文中介绍的公式略加修改:

tn = t(n +1)(max) + Δn

继续考虑上例,业务服务提供程序依然应动态调整用于下游调用的超时值,根据所用的协议和 API,有时您可能会面临挑战。

理想情况下,特定服务(甚至特定消息)要使用的超时值应该是在外部定义的,因而可以在无需重新部署的前提下进行更改。例如,可以使用 IBM WebSphere Service Registry and Repository 来存储此信息,在运行时检索这些信息,随后可使用前文所述的程序性技术设置超时值。

超时与异常处理

在处理服务请求或相应消息的过程中出现超时的时候,超时将被视为异常,必须采取某些措施来处理异常。最常见的响应就是向消费者回发一条错误消 息,指出发生了超时。如果调用是一个(分布式)事务处理的一部分,可使用 XA 协议或 Web 服务的 WS-AtomicTransaction 标准,事务处理即可回滚,处理过程中作出的所有更改都将自动恢复。但大多数 SOA 系统是松散耦合的,不会启动分布式事务处理。这也就是说,只要调用的客户端出现超时,服务器端将成功完成部分或全部基本逻辑,可能会给系统创建更改,您必 须进行补偿,因为客户端已经认为一切都是错误的。

尝试通过上文所述的减少下游超时值避免这些情况时,无法消除可能发生的超时,某些功能仍将完成,虽然比预期速度要慢。根据所调用服务的功能, 服务的消费者可能必须显式调用 “恢复” 功能,确保所有可能的更改和调用的永久负面效果得到补偿。WS-BusinessActivity 标准为此类补偿提供了一个正式的协议。某些补偿也可能在某个中间媒介上发生,例如,在 ESB 中。

另外一种处理超时的方法是尝试再次调用服务。某些协议和产品支持内置重试,而且是可配置的。这可以方便地涵盖短暂的临时中断的情况,重试将始 终成功。但这会影响所用的超时值。举例来说,如果 ESB 和业务服务提供程序之间的超时设置为 10 秒,配置了重试次数 3,每次重试延迟 1 秒,那么次连接的最大总超时必须计为 32 秒。您可以使用下面这个公式来计算新超时:

tmax = (t +d) * n

其中 d 是配置的延迟,n 是重试的次数。图 6 给出了一个示例,展示了如何为 WebSphere ESB 中的调出节点配置此功能。

图 6. 为 WebSphere ESB 中的调出节点配置重试

在 WebSphere ESB 中,此项的默认设置为 0,表示不重试。

在某些情况下,必须将超时视为普遍的,在正常情况下会出现。举例来说,假设您有一个在特定时间段内响应的业务服务,但对于某些请求来说,一般 情况下会按照预期响应,但在很少的情况下需要更长的时间。您的解决方案设计必须考虑这些预期超时,并作出相应的反应,可以进行补偿,也可以与消费者沟通, 说明请求已经回报为超时,但实际上已经成功完成了。

这些考虑事项仅仅是整体异常处理和错误战略的一部分,此类战略必须详述如何处理所有类型的异常情况,而不仅仅是超时。

结束语

这篇文章将超时值列为规划和设计面向服务解决方案的一个重要方面。此类解决方案具有松散耦合的特征,因而协调适用于解决方案的所有部分的超时值至关重要,从而避免不必要的错误和重复的清理工作。

此外,面向服务解决方案固有的灵活性带来了高度的动态性,这也影响了超时的处理方式。应尽可能地在整个解决方案中动态设置超时,有时甚至要以单独的消息内容为依据。


相关文章

企业架构、TOGAF与ArchiMate概览
架构师之路-如何做好业务建模?
大型网站电商网站架构案例和技术架构的示例
完整的Archimate视点指南(包括示例)
相关文档

数据中台技术架构方法论与实践
适用ArchiMate、EA 和 iSpace进行企业架构建模
Zachman企业架构框架简介
企业架构让SOA落地
相关课程

云平台与微服务架构设计
中台战略、中台建设与数字商业
亿级用户高并发、高可用系统架构
高可用分布式架构设计与实践

 
分享到
 
 
     


基于SOA的工作流(WF)整合
SOA 100问 - 问与答
SOAP 应用模式:处理与性能
ESB架构之企业实施案例
基于SOA架构的企业集成系统
基于SOA的体系架构设计
更多...   


面向应用的架构设计实践
单元测试+重构+设计模式
软件架构师—高级实践
软件架构设计方法、案例与实践
嵌入式软件架构设计—高级实践
SOA体系结构实践


某第三方电子支付企业 SOA架构设计
某电子企业 SOA应用
中国移动 SOA培训
北京大学 SOA架构设计实践
友邦保险 SOA架构设计
上海 SOA架构实践
山东移动通信 SOA体系结构实践
更多...