简介
我们都知道商业智能(Business Intelligence,BI)能给组织带来许多优势。通过整理、聚集和分析数据,BI 能帮助我们洞悉组织内正在发生的事情,以及将要发生的事情。BI 让我们识别出组织前进的方向或者应该前进的方向。BI 的过程通常从提取、转换和加载数据(Extract、Transform、Load,ETL)开始。一般来说,ETL 是数据仓库(Data Warehouse)中的一个过程,其中包括:
- 从外部和内部数据源提取数据。
- 转换数据以符合业务的需要。
- 将转换后的数据加载到数据仓库(或者数据集市,Data Mart)
基本上,我们要达到 BI 的圆满境界,“只”需要一样东西:数据。BI 需要隐藏在组织系统中的数据。
走进 SOA
在过去的数年间,我们已经看到了面向服务架构(Service-Oriented Architecture,SOA)在 IT 架构前沿的进步。随着夸大的宣传渐渐平息,而各个组织逐渐完成向 SOA 的过渡,突然之间人们发现 BI 所需的数据被分散到了各个服务之中,被隐藏到了各种接口契约之后。
请看图 1 所示的 SOA 组件(来自我的论文《到底什么是 SOA?》),我们可以看到除了最主要的组件——服务——之外,SOA 还有若干与服务接口相关的其它组件:
- 契约,服务所实现的契约
- 端点,与服务建立联系的所在
- 消息,在服务与其用户之间来回传递的消息
- 策略,服务遵循的策略
- 用户,与服务交互的用户
这些组件,以及 SOA 的“共享数据定义(Scheme)而非数据”和“服务应当是自治的”等信条,都告诉我们 SOA 对其接口的重视。正是通过这种对严密定义的接口通信的强调,给 SOA 在松耦合、灵活性和敏捷性等方面带来了技术和业务上的优势。
图 1:SOA 组件及其关系
一方面 BI 着力在对数据的深入理解,另一方面 SOA 着力在将内部数据隔离到接口之后,目标冲突是真实存在的。正如 Pat Helland 在《外部数据vs. 内部数据》中所说,服务的内部数据绝不应该暴露到服务的外部,而这些数据正是BI 所需要的。正是出于这个原因,根据最近 Ventana Research 进行的一项调查(由 Dan Everett 在 Dr. Dobb’s Journal 上发表),只有 1/3 的调查对象认为他们的内部 IT 人员有知识和能力去实现 BI 服务,这个结果并不令我们感到惊讶。
我们似乎面对两个选项:要么直接获得数据而无视某些 SOA 原则(比如“共享数据定义而非数据”),要么遵循眼前的接口契约而盲目地期望 BI 能获得足够的数据。(第三个选项则跟第一个选项等效,我稍后会讨论到,即创建特定于 BI 需要的契约。)
直接获取数据,或者……
第一个选项是直接获取 BI 所需的数据,其过程则按照过去已经充分证明有效的 ETL。
SOA 给 ETL 带来了一点挑战,你必须从许多分散的位置(服务)将数据集中起来。不过,从多个资源中汇集数据对 BI 或者 ETL 来说都不是什么新问题。大企业中已经存在许多数据源:ERP、CRM、分散在各个部门的数据竖井(data silos),诸如此类。有了 SOA,ETL 反而可能更容易,如果考虑到 SOA 承诺把企业数据编织成高内聚的组织结构,而不是意大利面条式的点对点集成。(请注意“承诺”这个词,事实上要达到高内聚的服务组织结构不是一件容易的事。不过这是题外话了,这个问题要用另一篇文章甚至一本书才能解释清楚。)
前面我已经说过,ETL 已经很成熟,也已经被证明是成功构建 BI 解决方案的基础。然而,使用 ETL 基本上就意味着抹杀大部分当初让我们追寻 SOA 的那些好处。在 SOA 史前时代,我们面对的主要问题(在许多组织中这个问题仍然存在)之一是,企业系统的意大利面条式集成。请考虑图 2 所示的情形。由于历史的原因,每个部门都建立了自己的系统。随着新的业务需求的显现,其结果就是一堆各自为营的、条块分割的系统。然后,当系统间需要共享数据时,就加入新的点对点的接口来解决系统集成的需要。随着人们使用系统,他们发现自己需要另一个系统的数据,结果又是一个点对点的集成。图 2 展示了四种类型的点对点集成:ETL(提取、转换和加载),这是一种数据库间的关系;线上集成和基于文件的集成,两者都是应用间的关系;到数据库的直接连接,这是应用到数据库的关系。这里列举的关系并不完整;还存在更多的关系类型,如复制(replication)、基于消息的关系等等,都没有在图 2 中表示出来。
最终的结果就是意大利面条式的系统。对一个系统的改动会波及到其他系统,其结果是不可预测的。SOA 强调通用的接口和自治性就是为了解决这些问题。
图 2:典型的意大利面条式企业系统集成
把 ETL 作为获取服务数据的直接管道就等于加入了一个新的点对点接口——这就破坏了 SOA 的“接口防御机制”,并在 BI 与服务间引入了依赖关系。同时也为其他绕过 SOA 契约的做法打开了大门。(如果 BI 可以这样做,为什么其他应用、服务或系统不可以这样做?)
实行 ETL 的一个变通做法可以先将 SOA 数据复制到一个外部的数据库,然后对这些复制的数据进行 ETL。然而,这跟直接对服务的数据库进行 ETL 并没有什么两样,我们仍然绕过了 SOA 的契约,我们仍然和内部数据的结构耦合到了一起。
好吧,使用 ETL 可能并不是最好的方案。让我们试试第二个选项,看按照 SOA 的原则运用契约来集成 BI 和 SOA 结果如何。
抽取 SOA 数据(请求 / 响应)
集成 SOA 和 BI 的最简单的方案是不为 BI 过程做任何特殊的调整。如果我们采用契约,那些按照 SOA 的基本精神而拟就的契约,结果又会如何呢?为了满足 BI 的需求,我们需要周期性地轮询服务的接口,以便能够获得趋势性的和有历史意义的数据。
这种方法大致有两个问题。其一是网络带宽的问题。轮询我们需要的每个接口会产生非常大的数据流量。要解决这个问题,我们可能要增大轮询的时间间隔。然而,这样做会导致我们遇到第二个问题:我们面临着错失在轮询间隔期间发生的重要事件的风险。就好像我们在早晨和傍晚观察天空,而完全错过了在中午发生的日食。因此,不幸地,这种方法虽然聊胜于无,但看起来并不是特别有前途。
采用 SOA 契约的另一种方式是为 BI 的需要定制特殊的契约;也就是说,让契约允许从服务的内部结构中获取数据,以供 BI 使用。不过,这跟使用标准的 ETL 基本上是一回事;你仍然建立了一个点对点的集成,并为特殊用途的特殊契约树立了一个先例。
现在的情况看起来不太乐观。我们发现自己陷进了前有狼后有虎的一个处境;要么我们放弃一些 SOA 的原则和优点,要么我们屈就一个不好的 BI 方案。
嘿,等一下:可能还有第三条路……
转变 SOA 思路:转向“推”模型(Push Model)
第三个选项的基础是将 SOA 向前推进,超越我们习惯的简单的请求 / 响应模型,将 SOA 与另一种架构风格——事件驱动的架构(Event-Driven Architecture,EDA)相结合。
简而言之,EDA 跟 SOA 类似,是一种建立在“推”模型上的架构风格。EDA 组件向外发布事件。从逻辑上说,事件是发布该事件的组件中发生的任何值得注意的变化。该变化可以是正常行为的结果,比如一份订单已被处理;也可以是一个错误,比如数据库宕机;也可以是系统超过了一个阈值,比如第一百万名顾客做出购买行为;或者任何你认为重要的事情。从物理上来说,事件是带有描述该事件的元数据的头部和包含事件内容的正文的一个消息。
一旦事件被产生,就被传播到订阅了该事件的组件。在处理了该事件之后,这些组件也可以产生新的事件,以此类推。以航空公司为例,事件可以是一份航班延误的通知。这个事件会触发另一个负责转机的组件,试图为延误航班上的旅客寻找候补航班。(是是,如果真的有就好了。)相较于其他推技术,EDA 独具的特色是它的事件流处理(Event Stream Processing,ESP)和复杂事件处理(Complex Event Processing,CEP)的概念。我们将事件看作是相互关联的链条,而不是一个个孤立的。通过观察事件链——或者更进一步,观察结合在一起的若干事件链(即事件云)——我们可以做到在时间上的追溯分析,以及其他对事件模式的高级分析。
EDA 的运用可以独立于 SOA;但融合两者可以带来更多的好处。
当 SOA 遇上 EDA
如果我们把消息发布加入到契约会怎么样?“发布消息”的意思是服务将其状态发布给任何监听者,可以是周期性地,也可以是每个事件都发布。我喜欢将这种服务通讯模式叫做“通讯倒置(Inversion of Communications)”,因为它反转了 SOA 通常的请求 / 响应的通讯模式。看上去好像这种方式的网络负载跟服务轮询差不多,但实际上要少很多。另一方面,当采用通讯倒置时,关注服务的每个消费者每个事件最多只会得到一次,而轮询时消费者会多次得到状态变化的信息(或者错过该数据)。
为了使方案完整,你可以增加额外的请求 / 响应或者请求 / 反应消息,让服务的消费者能够获得初始的快照。通过这种方式,你获得了服务内部变化的一个事件流,而且这种方式并不是专门针对 BI 的。实际上,让其他服务也对事件流作反应可以降低系统整体的耦合程度;比如,你可以缓存其他服务的状态,从而减轻服务间的临时耦合。而且,通过实现汇总报告模式(Aggregated-Reporting Pattern),将 EDA 加入 SOA 可以作为解决 SOA 的报告问题的基础。
EDA 加上 SOA 解决了 BI 的问题;只要你在网络中准备好了事件流,BI 组件就可以抓取数据,按照它们的需要操纵数据,将数据塞进它们的数据集市或者数据仓库。而且,数据流还可以让 BI 更上一层楼,数据流让 BI 得以对实时事件和实时的趋向性数据进行更复杂更有意义的分析,并运用复杂事件处理(CEP)工具取得实时的业务活动监控(Business-Activity Monitoring,BAM)。事件处理到底是什么样子的呢?想象你有一个订单服务,它发布的事件以 XML 的形式描述了她所处理的每个订单,如列表 1 所示:
<ORDER ID="1234-5679"<br></br> OrderDate="2007-04-02T00:00:00"<br></br> DueDate="2007-05-15T00:00:00"><br></br> <OrderLine SKU="ipdshfl-123" ProductName="Apple 1 GB iPod Shuffle <br></br> AAC/MP3 Player - Metal (2nd Generation)" Price="85.99" Quantity="4"/><br></br> <OrderLine SKU="mszn-456" ProductName="Zune 30GB MP3 / Video Player <br></br> - Black" Price="245.99" Quantity="2"/><br></br> </ORDER>
列表 1:订单汇总的 XML 片断
我们可以用 ESP 或 CEP 工具来监控这个事件流,并持续从中抽取感兴趣的事件供进一步分析和行动。例如,列表 2 展示了一个查询,该查询用来在订单流中查找超过 $100,000 的订单。请注意,虽然这个查询看起来非常像是 SQL(确实是从 SQL 发展而来),它仍然有相当不一样的地方;该查询不间断地对一个非持久化(non-persistent)的事件流进行操作。
INSERT INTO LargeOrders<br></br> SELECT<br></br> orderid as orderid,<br></br> SUM(Ords.price * Ords.qty) AS TotalValue,<p> FROM</p><br></br> OrdersStream AS Ords XMLTable (val<br></br> ROWS '//OrderLine'<br></br> COLUMNS<br></br> Orderid as orderid,<br></br> TO_FLOAT (XMLExtractValue ('@Price')) AS price,<br></br> TO_FLOAT (XMLExtractValue ('@Quantity')) AS qty );<br></br> WHERE<br></br> TotalCost>100000
列表 2:Coral8 的持续计算语言(Continuous Computation Language)查询,用来从订单流中查找超过 $100,000 的订单,并将其插入 LargeOrders 数据表
CEP 工具要迈向主流仍然有很长的路要走,不过已经有一些厂商在实现这方面的解决方案。即便我们不使用 CEP,我们仍然能够从访问这些事件流中获得许多好处。例如,数据仓库中的一个库存管理服务可以监听订单服务的订单处理事件流,从而快速妥当地完成订购新库存,管理现有货物的工作。
当我们用 EDA 加 SOA 来构建 BI,基本上我们是将 BI 作为服务的 Mash-up 来构建。我们可以更进一步,让 BI 组件将它的趋势数据或者其他分析结果作为服务暴露出来。这样我们就可以在其他应用中使用这些数据。比如,如果我们让列表 2 的 CEP 查询每当遇到超过 $100,000 的订单都生成一个事件,我们就可以在 CEO 的门户上显示一个漂亮的面板,上面实时显示了组织中每小时或每天处理了多少个大订单,以及其他类似的有意义的图表。
图 3:用 Mash-up 的形式显示 BI
不过,我们还没有回答一个问题:我们的服务如何产生这些事件?
请求 / 响应模型怎么了?
从实现的角度来看,我们可以看到所需的基础设施已经出现或者已经存在。如果你在 ESB 的基础上实现 SOA,实现是很简单的,因为大多数 ESB 都直接支持事件的发布。在 WS-* 协议栈中,你可以采用 WS-BaseNotification、WS-BrokeredNotification、WS-Topic 等一整套标准。
如果你是在 REST 的阵营,或者不想被前述相对不成熟的 WS 协议的复杂性所困扰,我想你需要自行实现发布 / 订阅模型。不过,这个问题也已经被解决了:就是 RSS。当某人在他的博客上发表文章,你的 RSS 阅读器通过同步的请求 / 响应模型访问该博客,并获取自上次请求后增加的新文章。怎么样,不错吧:RSS 给了我们松耦合的发布 / 订阅模型,以及主题(分类),而且都是建立在同步请求 / 响应模型的基础上的。
你的服务可以用 feed 的方式来发布事件流,就跟你的博客一样,同时还获得了一些架构上的好处。比如说,服务不需要再管理订阅者。第二,当事件发生时消费者不必在场也可以消费该事件。而且,管理和配置比起队列引擎或者任何我能想到的技术都要简单容易。
结论
结合运用 EDA 和 SOA 给了我们一个不必打破 SOA 原则同时又能满足 BI 需求的解决方案。不过,结合 EDA 和 SOA 的方法面临两个困难。其一是用 EDA 和 SOA 来解决 BI 问题还没有很多实践经验(跟久经考验的 ETL 相比)。其二是这种方式需要做更多的工作甚至重做,因为第一波的 SOA 实现是建立在更简单的同步消息方式的基础上。在现有的 SOA 方案上加入 EDA 不是一件简单的工作。不过,在 SOA 中采用 ETL 也同样不简单,因为我们需要从许多来源抽取数据,而每个服务都有自己的内部数据,并且对任何普通大小的 SOA 方案来说,服务的数目都不会少。
我的观点是,几乎从任何方面看,EDA 和 SOA 都要胜过采用 ETL。
从 SOA 的角度来看,在 SOA 中加入 EDA 对整个 SOA 方案都有好处。EDA 对于建立更加自治的服务来说是一件有价值的工具。例如,服务可以缓存从其他服务中获得的相关数据,并在数据变更时得到通知。因此,作为消费者的服务可以从时间上与它所依赖的服务解耦,它不再依赖其它服务的可用性——当采用同步的请求 / 响应模型时就要面临这个问题。
从 BI 的角度来看,好处就更多了。利用 EDA 可以让我们获得传统 BI 机制难以达到的目标——实时的洞察力。运用 EDA 产生的事件流,我们现在可以实时地获得数据,并且通过 CEP 工具,我们可以实时地处理数据,并在趋势浮现时实时地采取行动。
总而言之,采用 EDA 和 SOA 来实现 BI 胜过采用传统的 ETL。我们不光能得到基本的 BI,我们还可以做得更好——实时 BI,更不用说对 SOA 整体质量的提高了。
关于作者
Arnon Rotem-Gal-Oz 是一位经理和架构师,他对在各种平台(从 HP-UX、Solaris 到 AS400 和 Windows)上构建大型、复杂的分布式系统有着非常丰富的经验。Arnon 的博客在 www.rgoarchitects.com/blog ,他还在 Dr. Dobb’s Portal 撰写软件架构和设计方面的内容,请见 www.ddj.com/dept/architect 。你可以通过 arnon@rgoarchitects.com 联系 Arnon。
评论