一种针对SOA的消息类型架构

SOA治理组织的一个主要目标就是定义能促进开发可重用服务的流程和策略。由此,一个服务治理组织将参与整个服务的生命周期,包括识别、资助、设计、部署、运营、版本管理和退役。

\

SOA治理的一个关键问题是,它往往对可对SOA治理起补充作用的数据治理视而不见。即便它们俩的目标相差很远,但它们却一起分享了一组常常被称为 “企业数据模型(Enterprise Data Model)”的元数据。EDM是全体信息系统的逻辑数据模型(Logical Data Model),要是你愿意,你也可以把它视为一种本体(Ontology)。它的结构常常是抽象的,并且与记录系统(systems of record)的物理结构之间存在着松耦合。但是,任何已知记录系统中保存的所有数据元素都应该来源于EDM中的一个元素。EDM常常被用来搭建在系统间 同步或复制数据的转换映射。

\

除了EDM,数据治理拥有的流程还会影响服务设计、运营、版本管理和消费:这些流程包括数据质量、元数据管理、引用数据变更、业务规则变更、外部数据需求、数据模型变更等。

\

本文的重点并非是数据治理流程和SOA治理流程之间必需的一致。相反,我们将把焦点集中在使它们之间产生有效协作的前提:企业数据模型的共享使用。

\

自从XML于90年代被发明以来,人们就一直在争论描述XML文档结构的最佳办法,尤其在谈到创建可重用的XML片段时更是如此。后来出现了3个阵营,它们每个的需求各不相同(有时是互相矛盾):Web阵营、文档阵营和数据阵营。当所有人都意识到DTD无法满足需要时,W3C迅速地颁布了XML模式(XML Schema)规范,至今大约有10年历史。可以预计,即将到来的小版本(XML模式1.1)只会有小的变化。尽管有一些批评(复杂、缺陷)以及替代技术(Relax NG)或互补技术(Schematron)的出现,但XML模式已经并且将依旧是用来描述XML消息类型的标准。然而,却没有人真正找到一种只使用XML模式定义建模EDM的有效方法。这导致了两种学科——数据治理和SOA治理——的相互分离。

\

我们在这篇文章中的观点是:消息类型应该由EDM元数据生成。我们还认为:使用传统的模型,如XML、ERD或UML,都无法支持这种类型的EDM消费。我们建议定义两个互补的DSL(领域特定语言),一个用于EDM,另一个用于EDM元素引用的消息类型。这些DSL将被用来产生文本符号,从中可以捕获EDM和消息类型定义。对于图形符号的创建,这些DSL同样适用。

\

一种企业数据模型领域特定语言

\

UML和ERD二者都与具体的M2元模型(分别对应OO和ER(实体关系模型))有很深的渊源。这两个模型事实上都不兼容XML文档的层次特点及其对应的模式语言。无论你使用哪个模式:Salami Slice(意大利腊肠片),Russian Doll(俄罗斯套娃)、Venetian Blind(软百叶窗),还是它们的组合;XML模式都无法有效地实现这个功能。它不是一门建模语言;它是一种让你来验证文档的XML文档结构定义。此外,这些模式所强加的复杂XML模式导入(import)结构还破坏了互操作性,因为并非所有框架都能由这些复杂的XML导入结构产生类。

\

事实上,这3种数据模型都只能通过一种叫做超图数据模型(Hyper-Graph Data Model)的间接数据类型来进行可靠地转换。

\

当然,基于一组定义良好的(而且是非正式的)规则,尤其是那些告诉你如何处理关联的规则,是有可能从UML或ER模型创建XML文档的,反之亦然。然而,这些基于规则的映射根本无法产生出实际的消息类型。原因很好理解:

\

a) 数据天生就是关系型的,在人类于8000年前发明书写、记帐和契约时就是这样。在100年前所有信息系统都是基于纸质文书的时候也是这样;只要人类还继续使用数据,这种情况可能还将持续下去。在企业数据模型中,每个实体几乎都会跟其它任意的实体发生联系。但是,无论是UML还是ERD,它们都无法在组成不同实体的类之间划定一条清晰的边界。

\

b) 消息类型元素往往只包含EDM中对应实体的属性子集。人们一直在试图创建一组粒度可重用的数据元素,但是这一策略已被证明是脆弱的,且会将中一些不必要的复杂性引入EDM。

\

我们建议使用EDM需求相关的语义来创建一个元模型:

\

a) 实体:它定义了一个范围,其中的关联(聚合[aggregation]或包含[composition])很可能最终属于相同的消息类型(如数据库表,或这个元模型的其它应用的报表)。这种关联的一个例子就是“Customer-Address”关系。

\

b) 实体关联:它描述了实体间关系。“Customer-Account”就是这样的一个例子。

\

这个元模型和领域设计开发(Domain Design Development,DDD)中诸如“实体”、“值对象”或“聚合”这样的概念很好地对应了起来。

\

如果我们从医疗保险领域中举一个例子,我们可以看到“Member-Address”关联属于Member范围,而Member和Group(或Coverage)则分别定义了不同范围。

\

一种针对SOA的消息类型架构

\

图 1. 阐述不同关联类型的UML简图

\

图2显示了我们EDM DSL的语法。我们使用Eclipse Modeling Framework和OpenArchitectureWare插件来创建这个文本DSL。Markus Voelter最近对“文本DSL”进行了介绍

\

我们的DSL可以让我们定义实体和数据类型。一个实体可以使用“basic”来限定。由此,它就只能在另一个实体关系的范围内被引用(使用聚合或包含)。这等于DDD中的“值对象”。当然,基本实体(basic entity)也可以被不同实体引用。

\

这个DSL规定了实体之间的“关联”。当你需要说明关联属性时,这些关联可以对实体类型进行扩展。

\

一种针对SOA的消息类型架构

\

图 2. 企业数据模型的DSL(被定义成XText语法)

\

由这个Xtext语法,OpenArchitectureWare创建了两个Eclipse插件,我们可以通过它们来使用这种语法所规定的句法来编辑模型,将之转换成配置和部署制品。

\

有人会提出,这种元模型也可以轻易地用UML Profile来表示,而且它们可能是正确的。但是,UML元模型本身的复杂性使得很难完成一个由UML类图(企业数据模型的图形化表示)到部署制品的转 换。此外,UML profile本身的价值也相当有限,因为它并没有提供一种精确的方法来表示实体定义中类的作用域。为此,你不得不使用特殊的符号。

\

大体来说,不使用图形化表示作为元数据编辑和管理的方法也是一种趋势;幸好,不使用XML表示也同样是一种趋势。正如Markus Voelter在其幻灯片中所强调的,人们不使用文本DSL的主要原因,只是因为没有一种简单的办法来创建分析器和语法感知的编辑器(包含智能感知 [intellisense])。XText可以非常简单的创建出人们想要的语法和富编辑器体验(图3)。

\

一种针对SOA的消息类型架构

\

图 3.一个基于(图2)EDM DSL的简单(图1)EDM

\

消息类型领域特定语言

\

将企业数据模型和消息类型关联起来的思想并不新鲜。例如,在《Applied SOA》一书中,Mike Rosen等人就声称(第3章):

\
信息代表了组织的数据资源。数据以不同的格式存在于不同的存储和应用之中。不同级别的SOA构造单元使用的数据级别也不同。语义 信息模型定义了业务流程和服务的数据。业务流程中传递的信息,其格式文档是以语义信息模型为基础的。这些文档在流程和服务之间提供了语义消息的形式。 SOA定义了数据由其本地的操作格式到业务流程所要求的语义数据的数据转换机制。
\

问题是,我们如何才能有效地建立这种关系(图4)?

\

一种针对SOA的消息类型架构

\

图 4. 我们如何才能将消息类型定义关联到企业数据模型?

\

Michael Rosen等人推荐,着重基于EDM(他们使用的术语是语义信息模型)设计有效的消息类型(参见《Applied SOA》 的第6章,第249页)。作者声称,这样做的核心收益之一是增进了新消费者和现有服务提供者之间的兼容性,因为接口签名有意地根据企业数据模型进行设计, 而非基于后台系统的边界或特殊的项目。但是,作者们并没有提供解决这一问题的模型,更不消说给出执行这项任务的自动化方法了。

\

第一步当然是定义一个EDM的元模型,正如我们在上一段所看到的。

\

图 5详细描述了消息类型的架构。在创建完EDM DSL和消息类型DSL之后,我们将能够产生消息类型的模式和WSDL文件。最终的模式独立存在,并且只由相应的WSDL文件引用。在这里,无需创建复杂的导入结构就能获得任何形式的类型或元素重用,因为重用来自于对消息类型定义中EDM的引用。

\

一种针对SOA的消息类型架构

\

图 5. 消息类型架构

\

消息类型DSL如图6所示,其核心概念是与EDM DSL中实体所定义的范围相结合的“投影(“Projection”)”元素。实体范围被用来定义那些同时在一个消息类型、数据库表或类定义中出现的数据 域。范围元素提供了对“重用”的支持。例如,一个基本实体“address”可能会出现在EDM中不同的实体内。这些范围元素会在消息类型中自动被重用, 除非它们被明确地“排除”在实体投影之外。一个投影定义可以用任何方法将任何属性或基本实体排除在消息类型的定义之外。另一方面,某个消息中也常常希望包 含与基实体(base entity)相关联的实体的某些属性或基本实体。在图1的例子中,groupID常常被包含在表示成员信息的消息中 。在这种情况下,投影也可以“包含”基实体范围外的元素。通过投影的组合,这个模型同样还支持包含那些不一定属于基实体直接关联的实体的元素。

\

这种方法完全消除了在消息类型和XML模式层级管理“1对1关联”或“1对多关联”的必要。来自关联实体的元素和属性只需简单地“投影”到消息类型 中。以图4为例,我们的DSL可被用来产生XML模式,其中Order集合元素是Customer元素的子元素。每个Order也可以包含它自己的 Shipment信息。这是XML模式无法完成的典型示例,因为人们必须用XML模式中复杂的XML模式导入和引用来建模关联。

\

“多对多”关系(如订单和产品)被视为实体区域(EntityArea)定义中的依赖元素。在这种情况下,XML模式产生器必须使用key和 keyref元素,以确保正确地表示出消息元素之间的关联。但是,在这个消息类型DSL中,并没有管理这些元素的必要,因为这些信息将在产生XML模式的 时候从EDM定义中获取。

\

消息类型只能包含投影,即对实体、基本实体、关联和EDM属性的引用。增加不属于EDM的元素是不允许的。这是一个设计决策,因为EDM应该代表企业数据模型,并且保存在记录系统中的所有数据元素都应该对应于EDM的一个元素。

\

一种针对SOA的消息类型架构

\

图 6. 消息类型DSL

\

消息类型本身的组成:

\
  • 动词(GET, NOTIFY, PATCH, CONFIRM, CANCEL, PREPARE, SUBMIT, SHOW或ANY ——参见图6中的统一接口和动词定义)\
  • 名词(基实体)\
  • 这条消息的处理是否是幂等的\
  • 消息负荷可以有3种不同的类型\

前3个元素被用来配置消息的业务信封,如由开放应用小组(Open Applications Group)定义的那个。在产生XML模式时,信封的所有元素将被编织进所有消息类型中。这些元素包括消息标识符、发送者信息、日期等。

\

动词是开放应用小组的动词和HTTP动词的子集。作为一项设计决策,我们选择不使用POST(如果是OAGIS,对应PROCESS)、PUT和DELETE动词,因为它们往往会鼓励定义CRUD接口,而CRUD风格的交互常常会在服务提供者和服务消费者之间造成强耦合。

\

消息的负荷可以是以下3种不同类型中的一种(这同样是遵循开放应用小组的设计指导原则):

\

a)  查询区域(被表示为按例查询[Query-by-Example,QBE],这时对应的动词是GET)

\

b)  事件区域(代表一个源实体的状态事件——使用NOTIFY动词发布事件消息)

\

c)  实体区域(代表所有其他动词的参数)

\

一种针对SOA的消息类型架构

\

图 7. 消息类型定义

\

PATCH动词的使用要结合实体区域,对应一个请求-(变更)-更新([REQUEST-(CHANGE)-UPDATE])模式。这个模式已经 用.NET世界的DataSet和Java世界的SDO(服务数据对象)中实现了。对于要实现目标是更改基实体(及相关元素)内容为目标的某类人类活动的 BPM应用而言,这个模式尤其有用。但是,当调用一个动作(它触发了基实体的状态变更)时,最好使用其对应的动词,而不是一个像POST这样的通用动词。 有一点需要引起重视的是,这个所建议的元模型不能很好地对变更概要(Change Summary)定义提供支持。然而,有人可能会认为,变更概要模式可以由合适的算法从实体定义中产生。

\

PREPARE和SUBMIT动词是公用动词的例子,这些动词值得在整个企业范围内被标准化到一个统一接口中。例如,像采购订单这样的一个特殊实体 常常会有一个“准备”状态,即在准备“提交”并开始其生命周期之前,要创建并修改它。对于这类提交(或是其他动词)的响应动词是“批准 (confirm)”。

\

CANCEL动词被用作一种标准的动作动词,其表示的意图是结束某业务实体的生命周期(如,取消采购订单)。

\

SHOW动词用作响应,比如响应一个GET请求。

\

CONFIRM动词用来响应某个动作请求,如SUBMIT或CANCEL。

\

这两个动词(SHOW和CONFIRM)并不存在于REST中,因为REST是RPC导向而不是消息导向的。除了在Atom集合的情况下,REST中的响应并没有特殊的语义。REST并不区分“技术性”确认和“业务性”确认。

\

这时,该消息类型DSL可被用来产生所有消息类型的模式了。某些方面,如版本管理或业务信封,可被编织进目标模式产生器(图5)。业务信封将消息负 荷包装在一个信封中,它包含了与交互相关以及与参与交互的各方或组件相关的信息。例如,开放应用小组就把“BOD”(业务对象文档)用于这个用途。我们强 烈推荐使用这个业务信封模式,而不是去开发一个私有的SOAP报头。SOAP报头应该只由需要实现某种策略或服务质量(安全、可靠性、事务等)的服务容器 使用。

\

你可能还想用同样的方法来创建一个服务接口的DSL,如图8显示的,它可被用来产生抽象的WSDL(缺少绑定或服务端点)。

\

一种针对SOA的消息类型架构

\

图 8. 一种很适合产生抽象WSDL的服务接口DSL

\

我们在这里不会详细地说明XML模式是如何从这个消息类型定义中产生的。这个主题值得再写一篇文章了。然而,值得注意的是,我们的消息类型产生方法**了两个重要的行为:

\
  • 首先,任何消息类型XML模式都可以单独产生。这意味着,只要EDM中发生任何改变,我们都可以有选择性地(从相同的消息类型定义中)重新产生 XML模式。你可能想跟踪EDM版本和它产生的模式。在使用复杂的XML导入时,其中一个导入的任何一次改变都会传播到所有消息类型模式。\
  • 其次,我们的方法并不要求服务提供者和服务消费者之间有一个“规范模式模型(Canonical Schema Model,CSM)”。一个CSM缺省情况下会迫使任何消息的传递中有2次转换(请求和响应都需要)。现代SOA概念提倡“智能”边界,它能完成传入和 传出消息的转换。如果消息是由单一后台系统“产生”和“消费”,那么就没有理由把它转换成一个规范格式。只需在消费者侧简单地将其从提供者的任何模式转换 过来。\

Jack van Hoof认为

\
从技术角度来看[规范模式模型]有一个好处,就是在端点,每个消息类型只需要配置一个转换服务。不管是否有多个来源,一个订阅者只需要订阅一种消息类型。
\

但是,这种看法并不是真的适用于SOA和服务提供者/消费者模式。在同步/复制场合中,Jack的推荐是合理的。在那里,端点实际上是记录系统本身,但是SOA的一个主要目标就是要通过在构建新解决方案时避免创建新的记录系统来避免同步/复制模式。SOA不是集成,尽管它和集成有相同的技术。SOA的目的是创建封装现有记录系统的服务,这样,新的解决方案就能通过消费这些服务来创建,无需由其他记录系统复制信息(图 9)。一旦信息不是复制的,它就没有必要被同步和复制。

\

在面向服务架构中,服务接口“就是”规范模型(图 9)。它隔离了服务消费者和记录系统。当服务经过了良好地设计,所有消费者都调用那个特殊的服务,该服务进而调用所有必需的后台系统。在服务接口之上再引 入“规范模式模型”,在我们看来纯属画蛇添足。某些人可能会认为,缺少它之后,服务接口就不一致了,每个开发者会创建其自己的语义。我们完全同意这个观 点,这也是为什么我们的方法要采用EDM定义来定义消息类型的原因。消息类型DSL提供了某些灵活性,让你可以由EDM语义进行派生,但是它还需要更多的 工作。缺省情况下,它使用EDM语义和结构,它基本上给所有服务接口提供了一致的消息类型。

\

同时,服务消费者与不同类型的服务进行交互也不太可能的。这在B2B场景下完全可能发生,也可能发生在大型组织中,但这通常是不期望出现,因为它可能仅仅意味着你不正确地设计了你的服务接口。

\

一种针对SOA的消息类型架构

\

图 9. 服务利用现有记录系统对新解决方案提供支持。该图描述了在服务接口背后的每个记录系统中出现的实体。

\

CSM还有悖于许多SOA版本管理原则, 因为它“迫使”所有端点都服从相同的“规范”模式,我们认为这是不现实的,因为缺乏正确的版本管理策略的组织往往最终会根据每个消费者创建一个服务接口, 因而破坏了CSM的目的。SOA技术(如XML或WSDL)其本身的预期目的就是为了减少服从CSM的需要,CSM曾是90年代集成平台的一个关键设计模 式,但最终这个模式却给端点带来了太多的改变,而要是契约是以兼容方式设计的,这一切原本是可以避免的。

\

CSM还是带来了一些重要的好处。例如,Jack强调道

\
定义规范消息格式使得有机会给公司提供一个无二义性的关于(代表有价值业务资产的)业务事件的可用消息目录。
\

Nick Malik把这称为“业务事件本体(Business Event Ontology)”。

\

这种能力对于业务活动监视和复杂事件处理至关重要。我们通过我们在这个消息类型定义中引入的业务信封概念实现了这一能力。在我们的模型中,事件和动作都被清晰地表示,并在消息负荷之外的企业层面上取得了一致。

\

如果你想集成竖井(即自治的信息系统),事件驱动架构是一个合适的架构。但是EDA的原则通常并不适合SOA。事件(被定义为一个状态的出现)和消息事件当然是面向服务架构的一个重要组成,但是单有EDA并不能成为组合编程模型的基础。

\

总结

\

消息类型的管理在面向服务架构中是一个复杂的主题。从创建复杂的XML模式导入结构,到作为一组OO类和注解表示的“数据契约”(被用作DSL), 已有不同的方法被采用。这些方法似乎都没有给出令人满意的结果,因为它们缺乏企业数据模型的支撑。本文给出的方法巩固了从“契约”角度(而不是代码)开始 设计服务接口的需要,并以企业关键资产之一的EDM为基础,建立了一种重用策略。

\

我们的方法同样也显现了数据治理和SOA治理之间的协同。随着新服务的发现、资助和实现,以企业数据模型为基础设计企业中出现的消息类型变得至关重 要。不使用EDM,服务接口将往往带有特定项目和后台系统的影子,降低了它们被其他消费者重用的能力。这种方法还使得数据治理可以有效地将企业数据模型的 变更告知SOA治理团队,在必要时,他们将触发服务生命周期内一个新的版本阶段。

\

笔者在此还要感谢Kjell-Sverre Jerijærvi和Boris Lublinsky对于本文富有建设性的讨论。

\

查看英文原文:A Message Type Architecture for SOA

\

感谢黄璜对本文的审校。

\

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至[email protected]。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。