故障处理与预防 — 第 1 部分

作者:Guido Schmutz 和 Ronald van Luttikhuizen

面向服务的环境中故障处理简介

2012 年 11 月

简介

设计和编写“正常进行”的自动化业务流程和服务是一回事。处理流程和服务中不希望出现的意外情况是另一回事。本文是由四部分组成的系列文章中的第一部分,将深入介绍基于面向服务的架构 (SOA) 和业务流程管理 (BPM) 原则建立的环境中的故障处理和预防。您将了解可能发生的不同类型的故障,以及 SOA 环境中的故障处理与传统系统中的故障处理有何不同。我们将基于一个“订单到现金”业务流程案例研究来调查此类环境中可能出错的地方。通过这些问题,您将了解 Oracle Service Bus 和 Oracle SOA Suite 中的一些现成功能,可用来防止故障发生以及在故障发生时进行处理。

什么是故障处理?

故障可以定义为发生某些不同寻常的事情,超出正常、预期的运营活动或“正常的流程”之外。IT 系统中的故障可分为以下几种类型:

  • 技术错误 — 由支持应用程序运行的底层基础架构或中间件组件中的错误导致的故障。例如,网络错误、服务器故障、磁盘损坏、表空间已满等。
  • 软件错误 — 由定制应用程序中的编程错误、所用第三方软件库中的故障、打包应用程序中的软件故障和错误导致的故障等。比如说,除以零、无限循环、内存泄漏、空指针异常等。
  • 用户操作故障 — 使用 IT 系统时人为错误导致的故障。此类故障的例子包括输入错误的信用卡号、订机票无意调换了往返日期、在网店订错了电子书等。
  • 异常的业务行为 — 违反某条业务规则导致的故障。例如,信用评级不良的客户、想购买某物但 CRM 系统不能识别的新客户、发票金额不对。
与“正常业务”相比,处理故障的代价较高且非常耗时,因为故障处理往往涉及人员工作和专业知识:CRM 部门可能需要致电客户、IT 运营人员可能需要增大表空间、财务部门可能需要对比工作说明书和发票,等等。因此,故障处理首先应将重点放在预防上:
  • 通过以强健、(可能的)冗余的方式安装和配置基础架构和中间件可预防技术错误。强化和主动监视有助于保持基础架构的质量。
  • 通过应用软件开发方法和最佳实践(如结对编程、同事评审和测试驱动开发)可预防软件错误。
  • 通过应用好的用户体验 (UX) 技术和方法,使 IT 系统设计完善、易于使用、且应用程序提供用户所需信息,这样可预防用户操作故障。
  • 通过向利益相关方明确指明所适用的条件可预防业务故障。利益相关方可以是客户、供应商、员工等。

然而,无论我们多么努力,也不可能防止所有故障发生。发生故障时,重要的是检测到故障,准备有效的故障处理措施进行应对,然后从故障中恢复。不要忽视故障,寄希望于什么坏事都不会发生。下面这些来自 Geek and Poke 的漫画显示了这些方法之间的差异

本文其余部分重点介绍在 SOA 环境中如何预防和处理技术故障和业务故障。

业务故障与技术故障

业务故障和技术故障有许多不同。下表展示了这两种故障类型之间的差异。

业务故障…… 技术故障……
指的是未满足特定业务要求 指的是硬件或软件组件的运行时故障
通常是可预见的且可在服务接口中定义 通常是不可预见的且未在服务接口中定义
有业务价值 无业务价值
是服务客户端可以恢复的故障 是服务客户端不能(轻易)恢复的故障,需要依赖他人纠正根本问题

下面两节分别提供一个具体故障示例。

业务故障

考虑一个客户头一次在一家新网店上订购一些产品。网店应用程序依赖 CRM 系统检索客户的详细信息和喜好。在这种情况下,CRM 系统不认识该客户,针对网店应用程序抛出一个业务故障,指出该客户为未知客户。这是一个可以预见的业务故障,可以通过将这个新客户重定向到一个网页完成注册来恢复。注册之后,业务可以照常继续。

以下代码片段显示 CRM 系统的 Web 服务返回的业务故障。该故障指示在后端系统中找不到特定客户。


<soap:Envelope>
  <soap:Header/>
  <soap:Body>
    <soap:Fault>
      <faultcode>CST-1234</faultcode>
      <faultstring>Customer not found</faultstring>
      <detail>
        <CustomerNotFoundFault>
          <CustomerName>John Doe</CustomerName>
        </CustomerNotFoundFault>
      </detail>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

Web 服务接口中指定了这个特定故障 CustomerNotFoundFault,以便服务的客户端可以预知它。以下代码片段显示了上述消息的部分 WSDL。

<wsdl:definitions name="CustomerServicequot; targetNamespace="..." ...>
  ...
    <wsdl:message name="FindCustomerRequestMsg">
      <wsdl:part name="FindCustomerRequest" element="tns:
	  FindCustomerRequest"/>
    </wsdl:message>
    <wsdl:message name="FindCustomerResponseMsg">
      <wsdl:part name="FindCustomerResponse" 
	  element="tns:FindCustomerResponse"/>
  </wsdl:message>
  <wsdl:message name="CustomerNotFoundFaultMsg">
    <wsdl:part name="Error" 
	element="tns:CustomerNotFoundFault"/>
  </wsdl:message>
  <wsdl:portType name="CustomerServicePortType">
    <wsdl:operation name="FindCustomer">
      <wsdl:input name="FindCustomerRequest" 
	  message="tns:FindCustomerRequestMsg"/>
      <wsdl:output name="FindCustomerResponse" 
	  message="tns:FindCustomerResponseMsg"/>
      <wsdl:fault name="CustomerNotFoundFault" 
	  message="tns:CustomerNotFoundFaultMsg"/>
    </wsdl:operation>
  </wsdl:portType>
  ...
</wsdl:definitions>

故障只是服务操作返回的另外一种消息,只要报告发生业务故障,就应使用此消息。这比向“正常”响应消息添加错误代码或标志好得多,因为它迫使使用者检测故障情况并进行处理。

技术故障

让我们来重温相同的场景,只不过这次由于计划外停机导致无法访问 CRM 系统。这种错误无法轻易恢复,需要等待 IT 操作或托管服务提供商将系统还原至正常运行状态。在这种情况下,一种并不是很好的故障处理方案是让客户在几小时后重试订单。

以下代码片段显示了当外部系统上的服务无法访问时,服务基础架构返回的一个技术故障。该故障指示服务器上发生了一个技术错误。

<soap:Envelope>
  <soap:Header/>
  <soap:Body>
    <soap:Fault>
      <faultcode>S:Server</faultcode>
      <faultstring>Could not connect to 127.0.0.1:443</faultstring>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

故障作为常规 SOAP 故障返回,并未在 Web 服务接口中明确指定。

向服务客户端返回技术故障时,切勿公开实现细节;不要只返回底层系统的技术故障。此类故障可能包括敏感信息,具体包括连接详细信息、驱动程序版本、所用的凭证以及黑客可能利用的操作系统详细信息。这种最佳实践称为异常屏蔽

SOA 中的故障处理与传统系统中的故障处理

每个开发人员的目标都应是打造坚不可摧的系统。这一目标能在多大程度上实现则依赖于能否成功处理和管理预期和非预期的异常情况。面向对象的语言(如 C++ 和 Java)提供了一种使用 trycatchfinally 等构造处理异常的高效方式。在 SOA 环境中,语言层级提供的大部分功能对于创建基本服务仍然有效和可用。

然而,SOA 在编排服务和创建组合应用程序时提出了其他一些挑战。图 1 展示了一个典型的 SOA 和 BPM 环境。该环境包括:

  • 服务提供者。组织使用的服务由内部系统和应用程序提供,如打包应用程序、现成的商用 (COTS) 软件、定制应用程序、客户端/服务器应用程序以及其他软件组件。外部组织也可以充当服务提供者;比如说,提供开票服务的贸易伙伴。
  • 公开的服务。服务提供者的功能以小构建块的形式公开,提供明确描述的、易于访问的功能(即服务)。服务可通过中介(如 Enterprise Service Bus)公开;尽管不一定要如此。
  • 服务使用者。公开的服务由各种使用者使用。可以向供应商和客户(外部)等贸易伙伴提供服务。可以将服务与手动活动一起编排成组织实现的业务流程。这可以使用 BPM 或 Case Management 平台实现。最后,门户和移动设备等用户界面使用服务允许最终用户执行作业。用户界面通常还与 BPM 和 Case Management 平台交互,从而直观显示所需执行的手动任务以及最终用户完成这些任务所需的信息。
图 1:典型的 SOA 和 BPM 环境
图 1:典型的 SOA 和 BPM 环境

这种环境的以下几个方面将影响故障预防和处理的实现方式:

  • 服务可以是异步或触发即忘式的;而进程可能长期运行。这意味着,工作不是在可以回滚的单个事务中执行的。需要其他机制来撤销更改。
  • 服务和进程包含定时事件,这些事件可能发生也可能不发生。您需要保证此类事件在特定的时间段内发生,或者保证不会丢失消息而让进程实例永远等待。
  • 服务是拥有自己功能的自治构建块,不应依赖其他服务。只要可能,应在发生故障的服务中处理故障。
  • 服务用于更大的工作单元,如组合应用程序和流程。故障恢复也应在类似的范围内解决,超出了单个服务的范围。
  • 有多个服务使用者,还经常位于自己的组织之外。不能实现只针对一个服务使用者的故障处理逻辑。逻辑应适用于所有(未来的)服务使用者。
  • 通常,SOA 环境包括异构和外部组件,这更凸显了故障处理标准的重要性。

在本文其余部分(以及本系列文章的后续文章中),您将了解在 SOA 环境中可以使用哪些模式和即需即用的特性实现有效的故障预防和处理。

情景

在本系列文章的第二部分和第三部分,我们将深入介绍 Oracle SOA Suite 中最重要的 SOA 构建块的故障预防和故障处理功能:SCA 基础架构(及其服务组件,如 BPEL 和调解器)和 Oracle Service Bus。我们将使用一个情景来介绍这些功能,其复杂程度足以显示一些实际的错误情况。

图 2 显示了此情景,即在 Oracle SOA Suite 11g 上实现的一个订单流程。我们将使用 Trivadis 集成蓝图表示法,如《Service Oriented Architecture:An Integration Blueprint》中所示 [参见参考资源]。

左侧显示流程步骤,从收到订单请求到订单处理完毕。右侧显示流程应用程序为了完成订单而需要交互的所有外部系统。此类系统包括:客户用于订购产品的应用程序、两个不同的可向客户收费的信用卡服务提供商、产品数据库、订单处理应用程序以及一个用于存储完成的流程实例的历史记录服务。中间部分显示使用 Oracle Service Bus 11g 公开的、流程调用的服务将流程与后端系统集成。

订单处理系统是一个原有的应用程序,只能通过队列与我们的系统集成。

图 2:Oracle SOA Suite 11g 上实现的订单流程
图 2:Oracle SOA Suite 11g 上实现的订单流程

此情景包括以下步骤:

  1. 应用程序通过一个同步 SOAP 调用调用订单流程。
  2. BPEL 流程调用 OSB 上的 ProductService 以获取产品详细信息。
  3. OSB 服务使用数据库适配器访问产品数据库中的数据。
  4. BPEL 流程调用 OSB 上的 CreditCardService 对客户信用卡收费。
  5. OSB 服务根据信用卡类型确定应向哪个 CreditCardService 提供者发送请求。
  6. 向应用程序返回成功或故障响应。
  7. 如果流程到此一直成功,将通过调用 OSB 上的其他服务以异步方式继续执行。
  8. OSB 服务通过将订单放入请求队列中向订单处理系统发送订单。
  9. 订单处理系统不停地从队列提取订单并进行处理。
  10. 根据处理结果,将在响应队列中放入成功或故障消息。
  11. OSB 上的服务从响应队列中提取消息并调用 BPEL 订单流程。
  12. 等待回调的 BPEL 订单流程继续。
  13. BPEL 订单流程调用 OSB 上的 HistoryService 以存档与订单流程相关的数据。
  14. OSB 服务调用订单历史记录系统提供的 Web 服务。

现在看看本情景中可能遇到的一些故障情况。根据墨菲定律,可能会发生许多问题,有些是预期的,有些则是非预期的。下图显示该情景,但这次加上了一些潜在的问题。

图 3:可能的故障情况
图 3:可能的故障情况

可能发生下列情况,必须避免或进行处理:

  1. 产品数据库是一个老系统,扩展能力有限。如果向它发送过多请求,将影响其性能,甚至可能会完全崩溃。
  2. 外部服务提供者与我们之间的网络不稳定,因此必须处理非常短暂的网络中断(通常不到一秒)。
  3. 如果所提供的信用卡无效,将引发业务故障。两个信用卡提供商都在服务合同中定义了自己的故障。
  4. 对于单服务实例,第二个信用卡提供商不能保证 7x24 可用性。因此他会提供另一个服务实例与第一个服务实例并行运行。
  5. 订单处理系统上的响应有时会丢失。记住,这是一个旧系统,没人想碰它,没人想研究这个问题。
  6. 如果产品不再可用,订单处理系统将返回故障。
  7. 订单历史记录系统并不总是可用。

本系列接下来的两篇文章将讨论如何使用 Oracle Service Bus 和 Oracle SOA Suite 的功能预防和/或处理这些故障。

故障预防和恢复策略

可应用各种模式防止故障发生或在不能防止时进行处理。下表列出了一些改进软件故障预防和处理功能的模式。应从服务提供者的角度看这些模式。换句话说,为了使服务能够提供附加值和良好的服务质量,服务提供者负责实现故障处理模式。因此,在该任务中解放了服务使用者。

有关这些模式的更多信息,请阅读《Patterns for Fault Tolerant Software》[参见参考资源]。


操作 预防或处理 说明
无操作 处理 只需忽略请求
阻碍 处理 承认失败
保护性暂停 处理 暂停执行,直到满足正确执行的条件
临时操作 预防 假作执行请求,但在保证成功之前并不提交
替代操作 预防 执行可接受的替代操作,例如,服务提供者自动进行故障切换
回滚 处理 尝试继续,但若失败,则撤销失败操作的影响
重试 预防 从失败的尝试恢复后重复尝试失败的操作。如果重试成功,服务使用者将对故障毫无察觉。如果重试失败,将向使用者传回故障
提交上级处理 处理 请人裁断并为软件提供可接受的解决方案
放弃 处理 尽量减小损失,写入日志信息,然后发出明确、安全的故障通知
补偿 处理 通过以相反的顺序执行相反的操作来撤销活动
异常屏蔽 处理 出于安全原因在返回的故障消息中隐藏实现细节
分流负载 预防 一个系统有多个实例,这样一个实例不可用时可由其他实例处理
心跳检测 预防 定期检查系统可用性以便及早检测到故障
限制 预防 使用队列机制管理发送到系统的消息数量

在本系列文章的第 2 部分,您将了解如何使用 Oracle Service Bus 11g 即需即用的特性防止故障发生并向服务使用者公开可靠、强健的服务。

参考资源

  1. 《Service Oriented Architecture:An Integration Blueprint》
    Packt Publishing
    Guido Schmutz、Peter Welkenbach、Daniel Liebhart
    ISBN-10:184968104X | ISBN-13: 9781849681049
  2. 《Patterns for Fault Tolerant Software》
    Wiley Software Patterns Series
    Robert Hanmer
    ISBN-10:0470319798 | ISBN-13: 978-0470319796

关于作者

Guido SchmutzTrivadis 的 SOA 及新趋势的技术经理,还是 Oracle ACE 总监。Oracle ACE 总监

Ronald van LuttikhuizenVennster 的执行合伙人和架构师,还是 Oracle ACE 总监。Oracle ACE 总监