Mule是一个企业服务总线(ESB)消息框架.它的主要特性包括:
1.基于J2EE1.4的企业消息总线(ESB)和消息代理(broker).
2.可插入的连接性:比如Jms,jdbc,tcp,udp,multicast,http,servlet,smtp,pop3, file,xmpp等.
3.支持任何传输之上的异步,同步和请求响应事件处理机制.
4.支持Axis或者Glue的Web Service.
5.灵活的部署结构[Topologies]包括Client/Server, P2P, ESB 和Enterprise Service Network.
6.与Spring 框架集成:可用作ESB 容器,也可以很容易的嵌入到Spring应用中.
7.使用基于SEDA处理模型的高度可伸缩的企业服务器.
8.强大的基于EIP模式的事件路由机制等.
Mule发布最新版本1.1,这个发布包括集成了JBI,对 BPEL的支持,还增加一些新的传输器(transport)Quartz,FTP,RMI与EJB等。
一、总述
Mule的运作能力也许是它在开源ESB中最大的优势:商业的支持公司Mulesource.com,给大家贡献代码的MuleForge.org,年度大会MuleConf,还挖来了CXF的作者与SaleForces的CXO......
二、示例
三、Mule的功能
1. 重温ESB的功能
- 解耦中介:客户对实际服务提供者的身份、物理位置、传输协议和接口定义都是不知道也不关心的,交互集成代码提取到了业务逻辑之外,由ESB平台进行中央的宣告式定义。
ESB平台实现协议转换(WebService,Http,JMS...),消息转换(转换、充实、过滤),消息路由(同步/异步、发布/订阅、基于内容路由、分支与聚合...)。
- 服务中介:ESB平台作为中介提供服务交互中的基础服务。
ESB平台实现SLA(可靠性保证,负载均衡,流量控制,缓存,事务控制,加密传输),服务管理监控(异常处理,服务调用及消息数据记录,系统及服务的状态监控,ESB配置管理),统一安全管理(这个有点理想主义)。
- 服务编排:多个服务进行编排形成新的服务。
ESB支持一个直观的形式定义新组合服务的流程(工作流、BPEL 或 代码级编排)。
2. Mule的解耦中介
Pluggable的传输层,路由器,转换器是所有ESB必然支持的核心功能,作为《Enterprise Intergration Patterns》的遵循者提供如下:
- Transport:WebService、JMS等常用的协议都已满足,IBM MQ在企业版中提供,只缺Weblogic Tuxedo了。
- Router/Filter:提供EIP中描述的路由
1.基于内容路由,Fillter提供消息类型、消息属性、JXPath和OGNL表达式的基础过滤能力。另有去除重复消息的Router。
2.接收表基类,由用户自行实现。
3.分拆聚合重排路由。
4.流程编排路由见后。
- Transformer:提供基础层次上的的协议类型转换、XML<->Java转换、编码、压缩、加密转换。业务级转换由用户实现。
不过,1.4版中的Transport的实现质量很一般,而Router、Filter、Transformer都实现得较简单和基础,
最后,Mule额外提供了POJO的编程模型,而不是痛苦的XQuery Base的XML消息。
3. Mule的服务中介
提供较基本的中介服务:
- 事务(支持XA的JDBC,JMS,VM queue)
- 异常处理(支持异常控制策略与Dead Letter Channel)
- 安全 (用Acegi意思了一下,弱)
- JMX监控及其他工具
其他的能力如流量控制、负载均衡,可基于Mule的机制自行实现。
4. 服务编排
- ChainRouter简单实现Pipeline模式
- JBPM Router(见loanbroker example)。
- 在1.4版中还有OSWorkflow Router 和Apache PXE BPEL Router。
5. Service Container
这是个额外的Bonus。Mule的身份并不纯粹。如果Component是什么都不干的Bridge Component,它就是真正纯调度外部服务的ESB。
如果Component是业务POJO,在Mule中运行业务逻辑,Mule就成为一个Service Container,类似于SCA Domain。
这时候它本身就是Spring+CXF的,额外有多通信协议支持,有SEDA(Staged Event-Driven Architecture),有异步编程模式,有服务中介基础设施,作为后台服务容器也是个不错的选择。
日后自己可能会越来越多使用Mule 2.0+Terracotta作为自己的服务容器方案。
四、Mule2.0 印象
与Mule 2.0抵死缠绵了两周,喜忧掺半。但只在2.0之后,Mule才算真正站到了ESB的起跑线上。
1. 很Spring,很SCA的配置文件
- 全Spring又全nameSpace化的配置文件,简洁而规范,在IDE中有良好的提示。
尤其是transport相关的endpoint的改进明显,原来的URI<endpoint address="pop3://bob:secret@localhost:62002"> 或如下的connector
<connector name="SystemStreamConnector" className="org.mule.providers.stream.SystemStreamConnector">
<properties>
<property name="promptMessage" value="Please enter something: "/>
<property name="messageDelayTime" value="1000"/>
</properties>
</connector>
改为transport特定的namespace后,IDE中清晰显示了可选的配置项。
<stdio:connector name="SystemStreamConnector" promptMessage="Please enter something: "messageDelayTime="1000"/>
- SCA的Service/Component概念。
Service/Component代替了原来注定要被遗忘的MuleDescriptor,其中Component定义业务逻辑的POJO,Service定义如何以服务的方式管理组件的配置。
在POJO中调用远程服务的Nested Router也改为了很SCA的Binding。
Component也有Component 与 PooledComponent的选项。完整的例子如下:
<pooled-component>
<spring-object bean="mySpringPojo"/>
<binding interface="org.mule.example.loanbroker.credit.CreditAgencyService">
<outbound-endpoint ref="CreditAgency"/>
</binding>
<pooling-profile exhaustedAction="WHEN_EXHAUSTED_FAIL" initialisationPolicy="INITIALISE_ALL"
maxActive="1" maxIdle="2"maxWait="3"/>
</pooled-component>
上文按pooling-profile定义的pooled-component,在spring中定义mySpringPojo,并将一个远程的CXF Endpoint binding到POJO的CreditAgencyService变量中,可直接调用;
- 可视化拖拽的Eclipse 插件Mule IDE。
虽然还非常原始,但总算有个盼头。
2. 架构的更改
- Web Service支持增强
随着CXF作者的加入,Web Service这事实上SOA里最重要的Transport得到了加强,WSDL终于可以通过annotation准确配置。
虽然无奈,就冲这个理由就应该升级到2.0了。不是2.0太好,而是1.4太差了。
- REST支持增强
Mule RESTPack,支持apache abdera(Atom Publish协议实现),Jersey(JSR131 RESTful WebService实现)和Restlet 三种Transport。
- 代码结构的合理化
抽象出相对稳定的org.mule.api接口包,代替原来的org.mule.umo包。
开发团队还检查调整了Mule中所有对象的定义,使其更加准确。
- 各个模块的升级
如核心MuleManager大对象拆成MuleContext and Registry,运行时Reistry支持动态加载Service,支持向OSGI进军;
如以流的方式转换处理消息。
如SEDA模型定义的细化,见后。
- 工具增强
Mule Galaxy SOA治理工具(开源), Mule Saturn 消息流监控工具,Mule HQ 底层监控工具。
不过还没试用不知道实际效果如何。
3. 遗憾的地方:
- 性能下降
无论是代替XFire的CXF还是Mule 2.0,都拖得性能大大下降。(但用JDK6的话情况又好一点)
- 仍然没有自带的集群,负载均衡,流量控制实现。
不像BEA、ServiceMix都使用JMS的底层,Mule使用vm queue在单一JVM的节点间流动。
我们团队主要用TerraCotta在集群里同步状态数据,流量控制与负载均衡也是自己实现。
- CXF transport 仍然使用Mule自己实现的Http Connector。
CXF Standlone也是用Jetty的,看tomcat们努力的劲头,相信谁都能随便实现一个不错的Http Connector。
- 从1.4升到2.0非常的花时间。
估计团队重构的太兴奋了,从代码到配置文件再到XFire to CXF,一些代码级修改还没文档详述。
- 文档从1.4版更新到2.0版的进度太慢,而且文档仍然简略。
- 质量仍然在使用中检验。
文档说2.0版本的比1.x版本增加了30%的单元测试用例,按理来说项目质量应该提高了。
但还是被我发现了在很重要的AbstractEntryPointResolver类里,居然有内存泄漏。(http://mule.mulesource.org/jira/browse/MULE-3521)
原因是用了StringBuffer作为HashMap的key,而SB并没有重载Object的equals()函数的,结果map永远都在增大。
这说明了,开源项目的质量,最终是靠一个积极使用和反馈的用户群和一个活跃的开发团队,"用"出来的。
五、诡异的消息流
不同的inbound-outbound模式下,Mule中的消息流与交互模式非常诡异,不熟悉的人会很痛苦,详见交互编程模式
- 同步模式:如果component有outbound,最终向调用者的返回结果就是outbound的返回结果而不是component的。
当不再有outbound后,如果component的函数返回null,则返回NullPayload,如果函数为void,返回请求参数,其余正常返回。
- 异步请求应答模式:一个同步Inbound,一个Ountbound(通常有reply-to的配置),一个 async-reply。Component请求,发给outbound,在async等待outbound返回,再返回给调用者。
六、诡异的SEDA模型
Mule 2.0的SEDA模型配置更加细腻,但却没有文档描述,以下都是从配置文件的Schema读出。
SEDA的配置项仍然分Thread Pool、Component Pool、Queue三项,但其中Thread Pool又细分Receiver,Dispatcher ,Component 三项。
- <configuration>可设定全局的Thread Pool,又分default-threading-profile与default-receiver-threading-profile等四项。后面三项如果没有特别设定,则采用第一项的值。
- <connector>可设自己的dispatcher与receiver threading profile。
- <model>可设自己的queue profile。
- <service>可设自己的component-threading-profile与queue profile
- <pooled-component>可设自己的pooling-profile。
换个角度描述:
- Threading:<configuration>描述全局默认Threading,<connector>描述dispatcher与receiver,service描述compent-threading
- Compoent Pool:<pooled-component>
- Queue:<model>,<service>
最后结果,配了default-threading-profile为100后,系统开了100条的http.receiver,其他component和vm.receiver都只有1条线程。在典型场景的CXF -> component->同步VM Queue ->component的情况下,一个请求的两个component都在同一个http.receiver线程内执行。
相对于1.4的改进:
Thread Pool的配置细腻了,而且不会去开N条实际用不到的vm.receiver
Component 不再默认有个对象池,也可以是<component>指向自身或Spring的单例,<pool-component>时才做池化处理。