李秋菊的空间

我们一直在努力....

放松点!松散耦合您的企业信息系统

标签: 松散耦合 服务 架构
尽管面向服务架构的完整定义在各种文章中和各个厂商的眼中各不相同,但有一个术语词却是大家一致使用的,那就是“松散耦合”。这个词对服务是什么以及服务如何改变企业系统面貌有着巨大影响,然而它还含有多重意义。 
如果正确使用,松散耦合系统将带来在技术和业务上都看得见的好处。我们很容易就可以想到健壮性、可维护性、可变性、变更弹性、可伸缩性和平台无关性等。但是这两个词是如何实现上述种种好处的呢?本文将阐述服务“松散耦合”的含义和最能利用这一重要属性的模式,然后再讨论松散耦合的其中一个方面——定位和调用无关性。
 主题的变化
SOA的核心是通过明确无误、平台和语言无关的接口契约规定的服务定义。服务接口(通过WSDL)定义了可在服务上执行的操作以及各个操作所需的数据。通过像BPEL4WS这样的高级构造,整个流程可被描述,但仍不一定能具体实现。其他标准可按照类似的方式在众多选择中定义安全性(WS-Security)、定位和关系管理(WS-Addressing)、政策实施(WS-Policy)和可靠的消息传送(WS-ReliableMessaging)。
松散耦合跨越上述所有方面,并且一项服务与其消费者的耦合的松散度取决于它们本身。与这一概念紧密相连的是绑定的概念——选择某一特定方面的一个具体约定或者实现。系统运行期间绑定中的灵活性正是衡量耦合度的一种途径。
粒度
服务的粒度对服务与消费者之间的紧密耦合具有很大的影响。如果一项服务具有很多需要按照特定顺序执行的操作,那么它的消费者就要比具有很少几个粗粒度操作的服务的消费者更紧密地被绑定。
将远程过程调用(RPC)集成方案(通过CORBA、EJBS、 COM+对象等实现)与基于消息的系统作比较就很容易看到这一点。大多数的RPC调用依赖于获得对象引用,并调用很多细粒度的方法(比如setName)。如果还需要其他属性,或者进行了对象重构,那么所有消费者都需要对他们的代码进行实实在在的改动。基于消息的系统向消费者隐藏了实现,减少了接口被改动的可能性,从而通过约束更小的文档确认技术更好地处理版本控制。
数据类型
RPC调用可能比消息具有更强的类型。远程过程调用,即使通过SOAP编码的Web服务,仍然需要在设计时就设置类型。相反,消息中的元素可能代表一个数字,但是可以根据上下文环境具体实现为整数、浮点数、或者更大规模的表示法。这种消息的消费者可以选择在消息到达时对该数字进行动态类型转换,以免在消息的提供者改变数字的规模时发生错误。服务的生产和消费阶段中灵活动态的类型转换的使用提供了更加松散耦合的环境。
调用
需要通过同一通信通道对请求做出立即响应的服务消费者,比那些可以等待并且可以从另一个通信通道接收响应的消费者更加紧密地与该服务绑定在一起。也就是说,同步服务比异步服务更加紧密地耦合。
另外,对服务的直接调用(其中端点在消费者那里被编码)导致了比代理或动态服务查询更高的耦合度。发布/订阅(我很关心)和广播消息(有人关心吗?)分别通过去掉另一种耦合度——时间依赖性——产生了越来越松散的耦合。
通信
选择一种被很多协议都支持的调用方案提供了更多的实现选择,从而带来了比选择支持较少的方案更多的绑定灵活性。需要服务是HTTP上的SOAP这一点排除了服务在本地调用的可能性。坚持服务的同步执行将JMS和其他消息代理从潜在通信通道的列表中删除。最松散耦合的服务允许在大量通信通道上进行调用,其中消费者在运行时动态地选择适当的通信通道。
不错的开端
松散耦合系统理论上说起来是一回事,但实际应用起来又是另外一回事。松散耦合的某些方面很容易通过利用粗粒度的基于消息的异步通信服务来实现。
一般来说,应该在所有时候都使用基于消息的服务。这一点似乎被业界强烈支持。在Web服务的早期阶段,绝大多数的服务都是RPC/SOAP编码的,但是最近的趋势已经朝着鼓励使用Document/Literal样式(比如,基于消息)的服务的方向发展了。
另一个趋势是朝着异步服务的方向发展,这与从RPC向消息发送转变的大趋势有关。大多数RPC服务都是同步的——从早期分布式对象技术比如CORBA、EJBs、COM+等遗留下来的残留。向基于消息的服务转变也是如何设计系统的观念、方法和粒度的转变。
朝基于消息的异步服务迈进并不是一件轻松的事情;有很多问题亟待解决,当然也有很多有意思的解决方案。出于本文的目的,我们假定通过使用这样的服务已经获得了良好的松散耦合度。下一步是要确定服务定位、调用和通信的模式。
定位定位、定位
抽象服务的定位,并为松散耦合提供间接调用和多协议通信的模式有很多种。我们这里会讨论几种,分别说明其优缺点,并解释其用法与用途。
服务注册器和静态绑定
解决定位服务问题的最初方法是引进服务注册器。当Web服务流行之后,三种主要的规范是SOAP、WSDL和UDDI(通用描述、发现和集成)。
 UDDI注册器背后的含义是服务提供商可以发布众多信息中有关服务接口和实现的信息,而由消费者来发现它们。尽管最初被当作所有服务的一个全局复制库,私人UDDI注册器现在已经被推荐给企业来管理内部业务。最简单的模型是只设计时间。服务提供商已经创建和发布了关于服务及其接口的信息(用WSDL)。消费者发现该服务,使用WSDL来创建平台相关的调用代码,并静态绑定到注册器中或者WSDL服务元素中指定的端点。这样的静态绑定不是松散耦合,这一点应该很明显。它与该服务的一个具体实例绑定,并且如果该服务离线,消费者就会失败。
服务注册器和动态绑定
无论如何,UDDI允许多个提供商实现同样的服务接口。这将实现一种更松散耦合的方法,并且支持运行时故障切换或者负载均衡。
在该模型中,UDDI注册器不仅被设计时工具使用——需要运行时连接。一种解决方法是总是在运行时发现服务。这将导致明显的性能问题。更好的办法是只使用注册器来在原始服务失败时寻找替代服务。于是该替代服务就变成后续迭代的默认服务。
对那些对同一请求需要多个响应的系统来说,运行时方案也很有用。一个很明显的例子就是获取保险报价。如果报价服务是通过一个接口定义的,并且多个供应商都发布了该接口的实现,那么就很容易看到是如何对每一个进行调用从而获得所有供应商的报价的。此外,这种方案的耦合相当松散。获得报价的系统可能不知道哪个供应商实现了它们的接口。
注册器的使用提供了一种直接绑定机制。消费者用注册器来定位服务信息,然后利用注册器中的信息直接与该服务绑定。
服务代理
另一种方法是使用服务代理或者路由器。客户不是直接调用提供商的服务,而是通过代理访问服务。这通过打破提供商和消费者之间的直接绑定提供了松散耦合和灵活性。
简单的说,代理的任务就是确定被请求服务的提供商,并将调用路由给该提供商。
更复杂的方案可以合并基于内容或者基于规则的路由选择、负载均衡、故障切换、数据传输、转换和内容过滤。由于所有调用都要经过代理,所以拦截模式可以很轻易地在所有服务中加入安全性、登录和审计。代理还应该处理多种协议以及协议交换,这使得基于HTTP的消费者可以与JMS提供的服务通信。
这种机制的一个问题是代理变成了一个故障点,并且成为一个潜在的调用瓶颈。这个问题可以通过服务代理组件的群集或多或少地得到缓解。然而,这并不能解决其他问题,比如在对等方案中为直接绑定引进了另外一跳,从而导致性能的下降。
分布式服务代理
这些问题可通过为所有服务提供商和消费者引进本地组件得到缓解。本地组件与服务合作伙伴的平台有着更加紧密的集成,但是仍然与实际的业务流程松散耦合。
 本地代理与中央系统交流本地服务返回中央系统时的服务注册器数据复制和中继信息。它们还可用作中央代理的心跳信息,以指明特定服务当前处于什么状态。
现在这被归结为节点间服务信息的协调,而不是所有流量都要经过中央代理。一旦找到了相关服务,流量就被按照对等的方式在各个本地代理之间定向。
如果中央代理出现故障,本地组件仍然能够定位并调用服务。如果其中任意一个提供商出现问题,那么该信息将被转发到消费者的本地组件上,本地组件然后再选择另一项服务。
尽管这需要添加一个本地组件并将其紧密耦合到消费者和提供商运行的技术平台上,但是消费者并不知道服务的提供商,提供商也不知道它们的消费者。
本地组件还带来了另外一级的灵活性。通常,提供服务的系统本身也是该服务的消费者。本地代理将发现到这一点,并且通过本地交互(本机Java、EJB)而不是使用远程调用来执行该服务。这对于消费者来说是透明的。现在消费者与提供商之间只有很松散的耦合。
服务总线
仍然有一种直接或代理交互紧密耦合的方法,那就是通过时间。服务的提供商需要在消费者请求该服务时是可用的。这一问题可通过引进发布/订阅机制或者能产生这一机制的企业服务总线来缓解。
 基本规则是提供商订阅,消费者向总线发布他们的请求。这些被发布的请求中包含了这样的信息(可能通过WS-Addressing):告诉提供商如何向消费者返回信息(如果必要)。在订阅时,提供商告诉总线它对哪些消息感兴趣。当消费者发布一条请求时,只有相关方才会被通知。所有响应都通过连接该消费者的总线被返回去。
这里相对于代理的优势在于提供商不需要在消费者发布请求时处于活动状态。总线是消息代理的扩展,提供了存储和转发功能,保证相关提供商最终都能得到该消息。其他提供商也能轻易地连接到总线上,而无需对消费者有任何了解,这样做除了去掉时间依赖性,还更进一步松散了耦合。另外,总线还可以按照路由选择、负载均衡、故障切换、数据传输、转换、内容过滤和协议适配的方式提供类似代理的特性。
分布式服务总线
分布式服务总线是这种模式的一个扩展,它按照与分布式服务代理类似的方法在各个服务平台中添加了本地总线。这些本地总线在本地透明地处理与同地协作(co-located)服务的交互,但是仍然将消息传播给连接在它上面的相关方的中央总线。通过将总线连接到企业内外,还可以对这种模式作进一步的扩展。
这为松散耦合提供了最终结果。消息可以异步放在总线上。相关方接收这些消息并处理它们,如果必要还可以将应答返回给总线。服务的消费者不知道提供商,反之亦然。其他总线也可以从企业内或者从企业外部连接到该总线上。
松散耦合的实际情况
目前企业中可以实现的松散耦合度因企业使用的平台的容量以及工具的不同而异。BEA WebLogic Platform的SOA组件在设计时已考虑了松散耦合。
尽管可以创建RPC/编码的紧密耦合服务,但是我们仍然鼓励开发人员在WebLogic Platform中创建Document/Literal Web服务。内置的UDDI支持提供了最初的服务发布和发现,服务代理集成组件为动态绑定和服务代理模式提供了必需的功能。
支持Web服务、缓冲(通过透明的JMS队列)服务、对等和发布订阅JMS服务形式的异步服务使得松散耦合应用不但成为可能,而且还很容易实现。对XML和数据转换的广泛支持刺激了消息发送模型的出现,并且Xquery功能也使得基于内容的路由选择成为现实。
尽管服务总线的名字并没有包含进去,但是创建一条服务总线所需的所有功能以及所有的服务总线功能都在未来的产品发布中占了一席之地。所有这一切都为WebLogic Platform带来了一个松散耦合的未来

    评分: 请先登录再投票,同一篇博客一月只能投票一次!
    无人投票

相关博客:


评论


发表评论

关注此文的人们还关注