内容


SOA 探索,第 3 部分

可靠的数据层如何加速 SOA 实现

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: SOA 探索,第 3 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:SOA 探索,第 3 部分

敬请期待该系列的后续内容。

概述

引入面向服务的体系架构 (SOA) 的概念是为了使工作更简单——松散耦合的接口、更紧密的管理和操作控制、封装的异构性等等。但是许多 SOA 实现正在变得比它们要取代的体系架构更加复杂。

存在许多导致 SOA 复杂性的因素,出现在脑海中的第一个因素就是“您如何处理数据?”关系数据库是面向数据的,不是面向服务的。相反,轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)存储库是面向服务的,仅提供了特定的查找 API。各种类型的文件又怎么样呢:XML、分隔文本、二进制等等?让所有这些分散和异构的数据源支持 SOA 不是一件小事情。除了创建服务来封装现有的企业信息系统(Enterprise Information System,EIS)或本地数据库这个任务以外,还存在大量的挑战。

要利用 SOA 中实现最大的效益,创建一种公共数据管理方法是至关重要的,以便全面处理在企业中集成通过不同自主服务来公开的信息的工作。使用这样的方法,使积极推动简单性和 SOA 项目加速变成可能的。

为了处理这些问题,本系列的这一部分将讨论数据服务层 (DSL)。明确地说,您将考虑如何通过创建 DSL 来消除 SOA 的复杂性,并将研究要在规划 DSL 解决方案时处理的最重要设计问题。

引言

采用 SOA 是一项大型工程,要求组织在沿用多年的不同数据集成解决方案的设计和实现方式方面做出重大改变。我曾经有幸和许多组织在转换到 Web 服务和 SOA 时进行密切合作,他们的经验突出了预先规划高效和可靠的数据访问策略的重要性。

通常,IT 部门基于以下三个选项创建数据集成需求框架,如下面的图 1 所示:

  1. 应用程序通过存储过程直接访问后端数据源。
  2. 应用程序直接访问后端应用程序(通常基于 CICS®/COBOL 技术),后者又管理对不同 EIS 或数据源的访问。
  3. 应用程序连接到一个集成组件,后者处理对其控制下的特定 EIS 或数据源的数据请求。
图 1. 典型数据集成选项
典型数据集成选项
典型数据集成选项

由于在转向 SOA 时,通常不会将数据访问的重建视为一个基本要求,因此往往继续使用现有的框架来进行数据集成——明确地说就是上面图 1 中的选项二和选项三——具体方法是为它们提供一个 Web 服务接口作为前端,如下面的图 2 所示。

图 2. 使用 Web 服务包装现有的前端
使用 Web 服务包装现有的前端
使用 Web 服务包装现有的前端

这样的方法为应用程序隐藏了相关详细信息,例如数据驻留在何处、数据源支持的数据模型和查询机制是什么、数据访问流程(特别是数据完整性)是如何实现的,以及数据源驻留在什么平台上。它还引入了另一种类型的挑战,包括:为有效负载构造简单对象访问协议(Simple Object Access Protocol,SOAP)、从 XML 到特定数据结构(例如,关系)的映射以及反向映射、解决如何使用诸如 Java™ DataBase Connectivity (JDBC) / Open Database Connectivity (ODBC) 等更熟悉的接口来编写代码,以及处理结果集而不是分析和处理 XML 结果,等等。

此外,将数据访问性能的责任留给数据库管理员是很常见的。然而,转向 SOA 通常意味着对数据库环境施加的需求发生实质性增长,例如增加的访问量,以及确保由于通过不同的应用程序来更新数据而威胁到的数据完整性,这些应用程序以前不曾涉及到某个特定的数据库。这样的需求无法仅在数据库环境中进行解决。

简而言之,访问数据源的任务不过就是为了从某个业务服务转到另一个服务,并让后者继续处理所有的数据解释职责时,并不能消除数据访问逻辑仍然消耗很大百分比的开发资源这个事实。这反过来又会对 SOA 活动的成败发挥重要的影响。此外,提供了甚至连前端数据集成解决方案也能够破坏的多个 Web 服务接口,而不管最终解决方案是否满足性能和可伸缩性要求。换句话说,正如我在本讨论的开头所述的,SOA 实现变得比它们将要取代的体系架构更复杂的情况并不鲜见。

因此,在转向 SOA 时,必须对数据访问框架重建的任务进行恰当管理。这就是 DSL 发挥更大作用的地方。

什么是 DSL?

在 SOA 的上下文中,DSL 是一个软件层,此层交付生产环境的运行时,对业务服务以及服务请求应用程序与此类服务使用的多个数据源之间的数据交付和持久性进行管理,而不管是在企业中还是在跨企业的分布式计算环境中。DSL 为业务服务提供所有相关数据源的抽象(和集成)。使用 DSL,业务服务看到的是“数据云”,后者可以使用某种公共数据模型来表示(最好是关系模式),并使用某种标准语言、标准接口或通过标准传输进行查询。要点:DSL 在 SOA 中的主要目的是为所有读写操作提供单点访问,确保始终从受保护的单个来源提取数据,一致地解释数据,并正确地跨所有服务保持完整性。DSL 用作业务服务层与数据持久层之间的公共桥梁(请参见图 3)。如图 3 所示,DSL 不仅旨在用作存在于多个系统中的信息的单一访问点,而且还提供此类系统中嵌入的数据模型的整体视图。后一点对于 SOA 的成功最为重要。

图 3. 在 SOA 中使用 DSL 来集中数据访问
在 SOA 中使用 DSL 来集中数据访问
在 SOA 中使用 DSL 来集中数据访问

显然,并非每种情况下都需要 DSL。在某些情况下,当业务服务的数量非常低(这里的经验规则通常是低于 50),并且最重要的是,当大型数据源的数量也相对较低(假设不大于 10)时,组织可能希望继续直接使用到数据源的单独连接器,或者使用到这些连接器的 Web 服务接口。尽管如此,但是当必须以当今的企业应用程序扩展到超大数量的事务(例如,每秒数百甚至数千个事务)的相同方式扩展到大量的业务服务和数据源时,使用单独有针对性、“烟囱管”式的技术将不再可能。

有些公司尝试通过区分数据上的操作(例如,查看、执行事务和/或更新)和操作的目标(例如,事务服务、信息服务或其他更高级的概念)来消除这些问题。这样的方法需要创建新的数据源,并在其中合并和规范化用于查看与更新的数据,从而又在确保跨多个软件层的数据一致性(数据同步)方面导致附加的困难。

越来越多的公司已开始认识到,处理上述数据访问问题以及追求可靠、全面的 DSL 解决方案方面的局限性,对于为大规模商业分布式计算环境实施经济合算的数据服务来说变得势在必行。

如何通过创建 DSL 来消除 SOA 的复杂性?

日益明显的是,为了消除 SOA 的复杂性,对企业数据源的数据访问应该虚拟化,其中必须将业务服务与在使用 Web 服务作为主要数据集成手段时常见的许多技术方面隔离开来,包括以下方面:

  • 数据源连接性。
  • 数据源安全性。
  • 数据源、服务提供者和基础数据源模型之间的分类学和语义差异的数据映射和解析。
  • 数据库平台差异。
  • 在使用文件和目录作为数据源情况下的非数据库结构差异。
  • 处理向业务服务中的对象提供数据的所有细节,无论是对于单实例、序列请求还是用于执行所有的标准数据访问操作,例如创建、读取、搜索和删除操作。
  • 在跨网络分布业务流程以及故障和可靠性顾虑非常重要(例如,在银行应用程序中)时确保事务完整性。
  • 异常处理和报告。

通过构建 DSL 来封装上述所有功能,您本质上是在集中所有的数据服务代码,从而产生高度可适应和可维护的基于 SOA 的解决方案。这显著简化了 SOA 所涉及到的实现问题,因为对于您需要在服务代码中提供的数据,用于向业务服务提供数据的任何代码全都一次完成,而不管有多少应用程序使用它。

因此,与其让与数据相关的服务调用代码遍布于每个针对 SOA 的应用程序中的每个服务,您可以将数据访问集中到针对所有应用程序的单个统一类型的数据访问中,以便能够减少 Web 服务交互的数量和任何时候打开的数据库连接的数量。所有这些要点可以帮助创建一个促进并发 Web 服务请求高可用性的环境,这样的环境对于基于 SOA 的应用程序非常有用,因为通过 DSL 来增加并发 Web 服务请求,您可以增加并发用户的数量,并允许更多的应用程序使用所需的数据源。

体系架构选项

图 4 描述了 DSL 的概念体系架构。使用这个体系架构,业务服务发起的每个数据访问操作或事务都将调用 DSL。此外,与显式调用专门(或专用)的服务接口不同,业务服务将数据访问处理委托给由多个服务组成的另一个系统进程。促进所有业务服务与 DSL 控制下的任何数据源的集成是该系统进程的职责。

图 4. DSL 的概念体系架构
DSL 的概念体系架构
DSL 的概念体系架构

因此,从概念上讲,DSL 解决方案包括两个逻辑层:数据服务编排层(此层支持所引用的系统进程)和数据集成层。将 DSL 解决方案分解为较小的构件(单独的层)提供了一些有趣的体系架构选项。

让我们简要讨论一下每个层,首先从数据集成层开始。一般情况下,此层可以通过两种方式来实现,如下所示:

选项 1

第一个选项是将数据合并到单个物理存储区中,通常称为操作数据存储区(Operational Data Store,ODS)合并数据创建了实现快速、高度可用和集成的相关信息访问的可能性,从而简化性能、数据一致性和可用性需求。此外,这还可以支持高级数据转换以实现语义规范化。但是,正如我在前面提到过的,由于附加的管理、服务器和存储资源需求,合并的数据存储区非常耗费资源,并且最重要的是,当涉及到真正的实时访问时,数据的副本和源之间的数据同步可能成为真正的挑战。此外,诸如文档、图像或音频等许多非架构化的数据可能不容易在此场景中进行处理。而且,从 SOA 的角度看,应该尽可能避免基于某种形式的数据复制的任何数据集成解决方案,因为这会创建多个数据模型之间的紧密耦合——DSL、ODS 和任何遗留数据源。此类依赖关系也许无法灵活适应将来的需要,并且可能导致在每当升级、重新编写或替换遗留数据源时就需要 DSL 的再工程。

选项 2

第二个选项纯粹涉及到支持联合数据访问功能,使其似乎就像单个资源一样,其中不管各种各样的数据源和平台如何,对数据的分布式访问完全是透明的。联合的分布式数据访问方法无需 ODS 即可提供所需级别的数据同步。然而,此方法也不是没有缺点,尤其是在性能方面——与选项 1 相比,许多请求的性能将会更慢,因此,需要在这里考虑附加的功能来补偿性能下降,特别是:

  • 支持数据缓存以减少访问数量,从而处理大量的数据请求。
  • 在通过网络传输数据时支持数据压缩,包括 XML 有效负载。
  • 使用 XML 的二进制表示形式,特别是所谓的 XML 二进制优化打包(XML-binary Optimized Packaging,XOP),这是一种对 XML 文档进行二进制编码(其中一个示例是 XML 信息集)的新概念和用于发布 XML 文档以供 Web 服务使用的专用格式,并且已在 Axis 2 中实现。基于所使用的编码机制,它可以提供二进制编码(请参阅参考资料)。

下面讨论数据服务编排层:虽然此层和数据集成层都很“智能”,但是由于数据集成层的繁重工作,数据服务编排层提供了必要的功能来专门集中于促进 SOA 实现——尤其是集中于提供公共对象模型及其到关系模式的映射。

DSL 要解决的最重要设计问题是什么?

在规划 DSL 时需要处理若干设计注意事项。显然,在一篇文章中介绍所有的重要注意事项是不可能的,下面让我们了解最重要的注意事项:

首先,对任何 SOA 实现来说都一如既往地重要的是——定义适当的数据服务模型,特别是具有内置可重用性特征的数据服务编目和关联的对象模型。

下面讨论公共对象模型。DSL 实现的这个元素是最关键的设计元素之一。公共对象模型规范化(最重要的是在分类学和语义差异方面)多个领域对象。务必记住的是,就 DSL 而言,该模型中的对象是数据功能(创建、更新、检索等等)而不是物理地存储在数据库中的实际数据的逻辑表示形式。因此,公共对象模型包括以下类型的对象类:

  • 业务对象——这些对象提供企业实体的单一视图和跨多个数据源的所有公共实体的统一视图,例如,“客户”实体、“商品”实体、“仓库”实体等的统一视图。
  • 功能对象——这些对象表示业务对象之间基于业务流程的关系,例如表示对象在特定业务流程上下文中的业务关系的实体,如“订单”实体、“库存”实体、“帐户”实体、“付款”实体等等;那些对象描述业务对象之间存在的静态和动态关系。
  • 数据访问对象——这些对象根据业务和功能对象封装公共数据访问方法,例如公共读写方法集,如 GetCustomerById()GetCustomerByName()GetCustomers()CreateCustomerById() 等等;还包括复杂的导航操作,例如聚合、联接和嵌套。
  • 特性对象——封装复杂处理逻辑的对象,例如对象-关系或 O/R 映射、转换、安全性和缓存;通常,专用于转换的功能对象具有一个封装相关逻辑的私有“获取所有实例”方法。
  • 交叉引用和相关性对象——此类对象表示各个服务“占有”的对某个业务实体的引用;在许多情况下,除了定义“整体”视图外,DSL 还应该能够将一个服务使用的企业实体的实例与另一个服务中的实例相关联。例如,交叉引用对象使用将一个系统中的实例映射到另一个系统中的实例的表达式,将各个服务中的实体实例进行匹配,从而封装了这样的相关性逻辑(通常,此技术称为“匹配谓词”);为了能够对统一的实体执行更新,在 DSL 中显式地处理引用变得非常重要。

其次,正如前面提到过的,为了最大化 DSL 性能,尤其是在使用联合方法来进行数据集成的时候,必须在解决方案的多个层建立缓存。

在数据服务编排层,缓存由专门的数据缓存服务提供支持。其旨在缓存有关将在 Web 服务的许多方法调用中使用和不会频繁更改的的业务或功能对象的基本信息。缓存的信息大部分放在保存在内存中的功能对象中。

XML 查询语言(XML query language,Xquery)对于使用功能对象来实现缓存非常有用。XQuery 是一种新出现的 W3C 标准,用于查询本机 XML 数据。为什么它对缓存任务非常有用呢?主要是因为它允许将数据源建模为过程和/或函数(请参见清单 1 中的示例)。

清单 1. 用于将数据源建模为过程和/或函数的 XQuery 示例
 for $p in strcache:getStoresInfo ()

      where  $p/stores/region eq "A"

       return 

               <asiaRegion>

                   {$p/stores}

                       {

                         for $s in $p/sales/sale

                         let $saletot := $s/Quaterlysales * $s/DollarConversion

                         where $s/YearsOperation gt 1

                         return

                               <store>

                                  <strno>{data($s/@storeno)}</strno>

                                  <type>{data($s/@storetype)}</type>

                                  <sales>{$saletot}</sales>

                              </store>

                       }

               </asiaRegion>

清单 1 中的示例可以看到,XQuery 执行多个任务:它将 getStoresInfo() 方法建模为一个函数,使用 $p/stores 提供变量绑定和筛选,并使用 $s/@storeno 和 $s/@storetype 执行数据转换。此外,XQuery 还允许对关系和非关系数据执行相同功能。

但是 XQuery 主要适合于读取类型的服务。更新的情况如何呢?为了克服 XQuery 在更新方面的缺点,可以使用两个选项:以编程方式使用 Java 或 IBM 和 BEA 引入的非常有趣的新技术——服务数据对象(Service Data Object,SDO)(请参阅参考资料)。SDO 不仅提供了用于执行直接更新的 setattribute() 操作,而且还可以跟踪更改(如果使用 <ChangeSummary> -- </ChangeSummary> 块在其 XML 配置中进行指定的话)。

就实现所需的性能特征而言,为数据服务选择恰当的面向 Web 服务的工具和运行时平台极其重要。例如,自从 5.1 版本以来,IBM WebSphere® Application Server 提供了高度优化的缓存功能,您可以在我前面讨论的应用程序级别的缓存之上使用此功能。此功能称为 WebSphere 动态缓存服务 (WebSphere Dynamic Cache Service)。对于数据服务,许多类型的请求的性能可以通过使用动态缓存来得到极大的增强。

激活该缓存机制的方法是向部署 Web 服务的 Web 项目的 WEB-INF 目录添加一个 cachefile.xml 文件。这里必须指出的是,动态缓存通过分析该对象的配置信息来尝试匹配每个不同的缓存条目元素。不同的可缓存对象具有不同的 <class> 元素。为了缓存 DSL 的对象,您需要使用 <name> 元素来定义缓存策略,以唯一地标识您希望缓存的对象。cachespec.xml 文件还允许添加逻辑来使缓存失效。清单 2 描述了 DSL 类型的对象的常见实现。

清单 2. 用于 DSL 对象缓存的示例 cachefile.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE cache SYSTEM "cachespec.dtd" >

<cache>

<cache-entry>

<class>webservice</class>

<name>/dataservices/MyServiceHTTPServicePort</name>

<cache-id>

<component id="xxxx" type="serviceOperation">

<value>http://nnnnn.nnnnnn.com/CommonQuery:getyyyyyy</value>

<required>true</required>

</component>

<component id="storeSales" type="serviceOperationParameter" />

<timeout>15</timeout>

</cache-id>

</cache-entry>

</cache>

在结束有关 DSL 性能的讨论之前,强调一下设计高度粗粒度的服务是绝对重要的,这样的服务接受用于执行多个相关任务的所有必要参数和信息,从而允许 DSL 代表支持 DSL 的应用程序完成尽可能多的工作。因此,为消息交换实现全面的以文档为中心的策略是必需的。例如,在面向客户的银行应用程序的情况下,最好允许应用程序提供客户 ID、姓名、借贷信息、帐号和主要或电子邮件地址信息——全都在单个请求中提供。该请求本身可以发起多个原子事务(客户身份验证、信用卡授权、提交客户配置文件更改等等)。

结束语

在本文中,我简单讨论了几个要点,这些要点证明了使用共享 DSL 以便简化和改进总体 SOA 体系架构的理由。我还描述了一些用于确保此类实现能够在联合数据集成场景中维持严格级别的请求量的方法。使用为您的特定情境定制的附加增强和技术,很容易对这些方法进行扩展。例如,您可能希望考虑将 ESB 实现为 DSL 的前端。您的每个应用程序都将调用 ESB,后者又调用 DSL 的适当数据服务。这将减少生产 DSL 中的服务交互功能数量,从而改进管理和操作特征。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services, XML
ArticleID=333378
ArticleTitle=SOA 探索,第 3 部分: 可靠的数据层如何加速 SOA 实现
publish-date=08282008