作者:Guido Schmutz 和 Ronald van Luttikhuizen
面向服务的环境中故障处理简介
2012 年 11 月
设计和编写“正常进行”的自动化业务流程和服务是一回事。处理流程和服务中不希望出现的意外情况是另一回事。本文是由四部分组成的系列文章中的第一部分,将深入介绍基于面向服务的架构 (SOA) 和业务流程管理 (BPM) 原则建立的环境中的故障处理和预防。您将了解可能发生的不同类型的故障,以及 SOA 环境中的故障处理与传统系统中的故障处理有何不同。我们将基于一个“订单到现金”业务流程案例研究来调查此类环境中可能出错的地方。通过这些问题,您将了解 Oracle Service Bus 和 Oracle SOA Suite 中的一些现成功能,可用来防止故障发生以及在故障发生时进行处理。
故障可以定义为发生某些不同寻常的事情,超出正常、预期的运营活动或“正常的流程”之外。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 服务接口中明确指定。
向服务客户端返回技术故障时,切勿公开实现细节;不要只返回底层系统的技术故障。此类故障可能包括敏感信息,具体包括连接详细信息、驱动程序版本、所用的凭证以及黑客可能利用的操作系统详细信息。这种最佳实践称为异常屏蔽。
每个开发人员的目标都应是打造坚不可摧的系统。这一目标能在多大程度上实现则依赖于能否成功处理和管理预期和非预期的异常情况。面向对象的语言(如 C++ 和 Java)提供了一种使用 try、catch 和 finally 等构造处理异常的高效方式。在 SOA 环境中,语言层级提供的大部分功能对于创建基本服务仍然有效和可用。
然而,SOA 在编排服务和创建组合应用程序时提出了其他一些挑战。图 1 展示了一个典型的 SOA 和 BPM 环境。该环境包括:
这种环境的以下几个方面将影响故障预防和处理的实现方式:
在本文其余部分(以及本系列文章的后续文章中),您将了解在 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 公开的、流程调用的服务将流程与后端系统集成。
订单处理系统是一个原有的应用程序,只能通过队列与我们的系统集成。
此情景包括以下步骤:
现在看看本情景中可能遇到的一些故障情况。根据墨菲定律,可能会发生许多问题,有些是预期的,有些则是非预期的。下图显示该情景,但这次加上了一些潜在的问题。
可能发生下列情况,必须避免或进行处理:
本系列接下来的两篇文章将讨论如何使用 Oracle Service Bus 和 Oracle SOA Suite 的功能预防和/或处理这些故障。
可应用各种模式防止故障发生或在不能防止时进行处理。下表列出了一些改进软件故障预防和处理功能的模式。应从服务提供者的角度看这些模式。换句话说,为了使服务能够提供附加值和良好的服务质量,服务提供者负责实现故障处理模式。因此,在该任务中解放了服务使用者。
有关这些模式的更多信息,请阅读《Patterns for Fault Tolerant Software》[参见参考资源]。
操作 | 预防或处理 | 说明 |
无操作 | 处理 | 只需忽略请求 |
阻碍 | 处理 | 承认失败 |
保护性暂停 | 处理 | 暂停执行,直到满足正确执行的条件 |
临时操作 | 预防 | 假作执行请求,但在保证成功之前并不提交 |
替代操作 | 预防 | 执行可接受的替代操作,例如,服务提供者自动进行故障切换 |
回滚 | 处理 | 尝试继续,但若失败,则撤销失败操作的影响 |
重试 | 预防 | 从失败的尝试恢复后重复尝试失败的操作。如果重试成功,服务使用者将对故障毫无察觉。如果重试失败,将向使用者传回故障 |
提交上级处理 | 处理 | 请人裁断并为软件提供可接受的解决方案 |
放弃 | 处理 | 尽量减小损失,写入日志信息,然后发出明确、安全的故障通知 |
补偿 | 处理 | 通过以相反的顺序执行相反的操作来撤销活动 |
异常屏蔽 | 处理 | 出于安全原因在返回的故障消息中隐藏实现细节 |
分流负载 | 预防 | 一个系统有多个实例,这样一个实例不可用时可由其他实例处理 |
心跳检测 | 预防 | 定期检查系统可用性以便及早检测到故障 |
限制 | 预防 | 使用队列机制管理发送到系统的消息数量 |
在本系列文章的第 2 部分,您将了解如何使用 Oracle Service Bus 11g 即需即用的特性防止故障发生并向服务使用者公开可靠、强健的服务。
Guido Schmutz 是 Trivadis 的 SOA 及新趋势的技术经理,还是 Oracle ACE 总监。