博科光纤交换机java_带有光纤的可扩展,健壮和标准的Java Web服务

博科光纤交换机java

这篇博客文章讨论了负载下的基准Web服务性能。 要了解有关Web服务性能理论的更多信息,请阅读利特尔定律,可伸缩性和容错 。

使用阻塞和异步IO对Web服务进行基准测试

Web应用程序(或Web服务)如何在负载下,面对各种故障时以及在两种情况的组合下表现如何,这是我们代码最重要的特性-当然是正确的。 由于Web服务通常执行非常常见的操作-询问缓存,数据库或其他Web服务以收集数据,将其组合并返回给调用方-因此,这种行为主要取决于Web框架/服务器及其架构的选择。 在先前的博客文章中 ,我们讨论了利特尔定律,并将其应用于分析Web服务器采用的不同体系结构方法的理论限制。 这篇文章(对该文章的补充)重新讨论了同一主题,只是这次我们将在实践中衡量绩效。

Web框架(我用这个术语来指代任何通过运行用户代码来响应HTTP请求的软件环境,无论是被称为框架,应用程序服务器,Web容器,还是语言的标准库的一部分),都选择以下一种两种架构。 首先是分配一个OS线程,该线程将运行我们的所有代码,直到请求完成。 这是标准Java servlet , Ruby , PHP和其他环境所采用的方法。 这些服务器中的某些服务器在单个线程中运行所有用户代码,因此它们一次只能处理一个请求。 其他人在不同的并发线程上运行并发请求。 这种称为“每个请求线程”的方法需要非常简单的代码。

另一种方法是对一个或多个OS线程(尽可能使用比并发请求数更少的OS线程)使用异步IO并尽可能多地将请求处理代码调度到多个并发请求。 这是Node.js ,Java 异步servlet和JVM框架(如Vert.x和Play)采用的方法 。 据推测,这种方法的优点是(这正是我们要衡量的)更好的可伸缩性和鲁棒性(面对使用率高峰,失败等),但是为此类异步服务器编写代码比为线程编写代码更复杂。每个请求的。 代码的复杂程度取决于使用各种“回调地狱缓解”技术(例如promise和/或其他通常涉及monad的功能编程方法)的使用。

其他环境则试图将两种方法的优点结合起来。 在幕后,他们使用异步IO,但是他们没有让程序员使用回调或monad,而是为程序员提供了光纤 (又称轻量级线程或用户级线程),这些光纤消耗很少的RAM并且阻塞开销可以忽略不计。 这样,这些环境在保持同步(阻塞)代码的简单性和熟悉性的同时,具有与异步方法相同的可伸缩性/性能/鲁棒性优点。 这样的环境包括Erlang , Go和Quasar (将纤维添加到JVM)。

基准测试

  • 完整的基准测试项目可以在这里找到。

为了测试两种方法的相对性能,我们将使用一个简单的Web服务,该Web服务是使用JAX-RS API用Java编写的。 测试代码将模拟微服务的现代通用体系结构,但结果绝不限于使用微服务。 在微服务架构中,客户端(Web浏览器,手机,机顶盒)将请求发送到单个HTTP端点。 然后,该请求由服务器分解成几个(通常是很多)其他子请求,这些子请求被发送到各种内部HTTP服务,每个子服务负责提供一种类型的数据或执行一种操作(例如,一个微服务可负责返回用户个人资料,另一个微服务负责返回其朋友圈)。

我们将对单个主服务进行基准测试,该主服务向另一个或两个其他微服务发出调用,并检查当微服务正常运行或发生故障时主服务的行为。

将通过安装在http://ourserver:8080/internal/foo的此简单服务来模拟微服务:

@Singleton
@Path("/foo")
public class SimulatedMicroservice {@GET@Produces("text/plain")public String get(@QueryParam("sleep") Integer sleep) throws IOException, SuspendExecution, InterruptedException {if (sleep == null || sleep == 0)sleep = 10;Strand.sleep(sleep); // <-- Why we use Strand.sleep rather than Thread.sleep will be made clear laterreturn "slept for " + sleep + ": " + new Date().getTime();}
}

它所做的就是使用一个sleep查询参数,该参数指定服务在完成之前应Hibernate的时间(以毫秒为单位)(至少10毫秒)。 这可以模拟可能需要很长时间(或很短时间)才能完成的远程微服务。

为了模拟负载,我们使用了Photon , Photon是一种非常简单的负载生成工具,使用Quasar光纤以相对较少的协调遗漏的方式发出大量并发请求并测量其延迟:每个请求都是由新生成的请求发送的纤维,然后依次以恒定速率生成纤维。

我们在三种不同的嵌入式Java Web服务器上测试了该服务: Jetty , Tomcat (嵌入式)和Undertow (为JBoss Wildfly应用程序服务器提供动力的Web服务器)。 现在,由于所有三个服务器均符合Java标准,因此我们为所有三个服务器重用了相同的服务代码。 不幸的是,没有用于以编程方式配置Web服务器的标准API,因此,基准测试项目中的大多数代码都简单地抽象出了三台服务器的不同配置API(位于JettyServer , TomcatServer和UndertowServer类中)。 Main类仅解析命令行参数,配置嵌入式服务器,并将Jersey设置为JAX-RS容器。

我们已经在c3.8xlarge EC2实例上运行了Load Generator和服务器,分别运行了Ubunto Server 14.04 64位和JDK8。如果您想自己使用基准测试,请按照此处的说明进行操作。

此处显示的结果是在Jetty上进行测试时获得的结果。 Tomcat对普通阻止代码的响应类似,但是使用光纤时,其响应性比Jetty差(这需要进一步研究)。 Undertow的行为与之相反:使用光纤时,其性能与Jetty相似,但是当线程阻塞代码面临高负载时,崩溃很快。

配置操作系统

因为我们将在高负载下测试我们的服务,所以需要一些配置才能在操作系统级别上支持它。

我们的/etc/sysctl.conf将包含

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_syncookies = 0
net.ipv4.ip_local_port_range = 1024 65535

并因此被加载:

sudo sysctl -p /etc/sysctl.conf

/etc/security/limits.conf将包含

*		hard nofile	200000
*		soft nofile	200000

配置垃圾收集

大多数Java垃圾收集器都是基于生成假设的 ,该假设假设大多数对象的寿命都非常短。 但是,当我们开始使用(模拟的)失败的微服务测试系统时,它将生成持续数秒的开放连接,然后才断开。 这种“中等寿命”(即也不短,但也不能太长)是最糟糕的一种垃圾。 看到默认的GC导致了令人无法接受的暂停,并且不想浪费太多时间来微调GC之后,我们选择尝试使用HotSpot的新(ish)G1垃圾收集器。 我们要做的就是选择一个最大暂停时间目标(我们选择了200ms)。 G1表现出色(1),因此我们没有花更多时间调整收集器。

  1. 可能是因为对象是按组分配的,这些组都在同一年龄段死亡。 这种模式可能正好发挥了G1的优势。

基准同步方法

这是我们的待测服务代码,从同步方法开始,该代码安装在/api/service 。 (完整的类,其中还包括HTTP客户端的配置,可以在此处找到):

@Singleton
@Path("/service")
public class Service extends HttpServlet {private final CloseableHttpClient httpClient;private static final BasicResponseHandler basicResponseHandler = new BasicResponseHandler();public Service() {httpClient = HttpClientBuilder.create()... // configure.build();}@GET@Produces("text/plain")public String get(@QueryParam("sleep") int sleep) throws IOException {// simulate a call to a service that always completes in 10 ms - service AString res1 = httpClient.execute(new HttpGet(Main.SERVICE_URL + 10), basicResponseHandler);// simulate a call to a service that might fail and cause a delay - service BString res2 = sleep > 0 ? httpClient.execute(new HttpGet(Main.SERVICE_URL + sleep), basicResponseHandler) : "skipped";return "call response res1: " + res1 + " res2: " + res2;}
}

然后,我们的服务会调用一个或两个其他微服务,我们可以将它们命名为A和B(当然,两者都是由SimulatedMicroservice )。 虽然服务A总是需要10毫秒才能完成,但是可以模拟服务B以显示变化的延迟。

假设服务B正常运行,并在工作10毫秒后返回其结果。 这是我们的服务随时间推移每秒响应1000个请求的方式(服务器使用2000个线程池)。 红线是同时需要两种微服务的请求的延迟,绿线是仅触发对微服务A的调用的请求的延迟:

stat_j2knf_10_1000

我们甚至可以将速率提高到3000Hz:

stat_j2knf_10_3000

超过3000Hz,服务器会遇到严重困难。

现在,我们假设在某个时刻,服务B发生故障,导致服务B以大大增加的延迟进行响应。 比方说5000毫秒 如果每秒我们在服务器上触发300个触发服务A和B的请求,以及另外10个仅触发A(这是控制组)的请求,则该服务将按应有的方式执行:触发B的那些请求会增加延迟,但是绕过它的人不受影响。

stat_j2knf_5000_300

但是,如果我们随后将请求速率提高到400Hz,则会发生不好的情况:

stat_j2knf_5000_400

这里发生了什么? 当服务B失败时,触发主服务的对主服务的请求将长时间阻塞,它们中的每一个都持有一个线程,直到请求完成,该线程才能返回到服务器的线程池。 线程开始堆积,直到它们耗尽服务器的线程池为止,此时,没有请求-甚至没有尝试使用失败的服务的请求-都无法通过,服务器实质上崩溃了。 这被称为级联故障 。 单个失败的微服务可以关闭整个应用程序。 我们怎样做才能减轻这种故障?

我们可以尝试进一步增加最大线程池大小,但最大限制为(相当低)。 OS线程给系统带来了两种负担:第一,它们的堆栈消耗相对大量的RAM;第二,它们的堆栈占用大量RAM。 使用该RAM来存储数据缓存的响应式应用程序要好得多。 其次,将多个线程调度到相对较少的CPU内核上会增加不可忽略的开销。 如果服务器仅执行很少的CPU密集型计算(通常是这种情况;服务器通常只是从其他来源收集数据),则调度开销可能会变得很大。

当我们将线程池大小增加到5000时,服务器性能会更好。 在500Hz的频率下,它仍然运行良好:

stat_j5knf_5000_500

在700 Hz时,它摇摇欲坠:

stat_j5knf_5000_700

…并在我们增加费率时崩溃。 但是,一旦我们将线程池大小增加到6000,其他线程便无济于事。 这是在1100Hz下具有6000个线程的服务器:

stat_j6knf_5000_1100

这里有7000个线程,处理相同的负载:

stat_j7knf_5000_1100

我们可以尝试在微服务调用上设置超时。 超时始终是一个好主意,但是选择什么超时值? 太低了,可能会使我们的应用程序无法使用。 太高,我们还没有真正解决问题。

我们还可以安装一个断路器,例如Netfilx的Hystrix ,它将试图Swift发现问题并隔离发生故障的微服务。 像超时一样,断路器始终是一个好主意,但是如果我们可以显着提高电路的容量,我们可能应该这样做(并且为了安全起见,仍然要安装断路器)。

现在让我们看看异步方法的发展。

对异步方法进行基准测试

异步方法不为每个连接分配线程,而是使用少量线程来处理大量IO事件。 Servlet标准现在除了阻塞API之外还支持异步API,但是由于没有人喜欢回调(特别是在具有共享可变状态的多线程环境中),因此很少有人使用它。 Play框架还具有异步API,为了减轻与异步代码始终相关的某些痛苦,Play用功能性编程的monadic组合替换了简单的回调。 Play API不仅是非标准的,对于Java开发人员来说也感觉很陌生。 这也无助于减少与无法避免竞争条件的环境中运行异步代码相关的问题。 简而言之,异步代码是一团糟。

但是,我们仍然可以使用光纤测试这种方法的行为,同时保持我们的代码美观,简单和阻塞。 我们仍将使用异步IO,但丑陋将对我们完全隐藏。

Comsat是一个开源项目,将标准或流行的Web相关API与Quasar光纤集成在一起。 这是我们的服务,现在利用Comsat( 此处为全班制):

@Singleton
@Path("/service")
public class Service extends HttpServlet {private final CloseableHttpClient httpClient;private static final BasicResponseHandler basicResponseHandler = new BasicResponseHandler();public Service() {httpClient = FiberHttpClientBuilder.create() // <---------- FIBER....build();}@GET@Produces("text/plain")@Suspendable  // <------------- FIBERpublic String get(@QueryParam("sleep") int sleep) throws IOException {// simulate a call to a service that always completes in 10 ms - service AString res1 = httpClient.execute(new HttpGet(Main.SERVICE_URL + 10), basicResponseHandler);// simulate a call to a service that might fail and cause a delay - service BString res2 = sleep > 0 ? httpClient.execute(new HttpGet(Main.SERVICE_URL + sleep), basicResponseHandler) : "skipped";return "call response res1: " + res1 + " res2: " + res2;}
}

该代码与我们的线程阻塞服务相同,除了几行(用箭头标记)和Main类中的一行。

当B正确执行时,一切都很好(当服务器处理前几个请求时,您会在控制台上看到一些警告,提示光纤占用了太多的CPU时间。没关系。这只是执行的初始化代码):

事不宜迟,以下是我们的光纤服务(使用40个OS线程,这是Jetty的最小线程池大小),频率为3000Hz:

stat_j40f_10_3000

在5000Hz时:

stat_j40f_10_5000

在6000Hz时,需要一些时间才能完全预热,但随后会收敛:

stat_j40f_10_6000

现在,让我们踢出问题的微服务,即我们亲爱的服务B,使其经历5秒的延迟。 这是我们的服务器,频率为1000Hz:

stat_j40f_5000_1000

在2000Hz时:

stat_j40f_5000_2000

使用错误的服务B响应请求时,除了偶尔出现峰值外,航行仍然平稳,但是仅撞到A的人什么也没有。 在4000Hz时,它开始显示出一些明显的但不是灾难性的抖动:

stat_j40f_5000_4000

每秒需要处理5000个请求(在失败条件下!),以使服务器无响应。 糟糕的是,服务B可能会导致20秒的延迟,但我们的服务器仍然可以每秒处理1500次触发失败服务的请求,而那些未达到故障服务的请求甚至都不会注意到:

stat_j50f_20000_1500

那么,这是怎么回事? 当服务B开始显示很高的延迟时,为调用B的请求服务的光纤会堆积一段时间,但是由于我们可以拥有这么多的光纤,并且由于它们的开销如此之低,系统很快就达到了一个新的稳态-成千上万的阻塞光纤,但这完全可以!

进一步扩大我们的能力

因为我们的Web服务向微服务发出传出请求,并且因为我们现在可以服务很多并发请求,所以我们的服务最终可能会遇到另一个操作系统限制。 每个传出的TCP套接字都捕获一个临时端口 。 我们已经将net.ipv4.ip_local_port_range设置为1024 65535 ,总共65535 – 1024 = 64511传出连接,但是我们的服务可以处理更多内容。 不幸的是,我们不能再提高此限制,但是由于此限制是针对每个网络接口的,因此我们可以定义虚拟接口 ,并让传出请求随机或基于某种逻辑选择一个接口。

结论

光纤使用户能够享受异步IO,同时保持简单和标准的代码。 因此,我们通过异步IO获得的好处不是减少延迟(我们尚未进行基准测试,但是没有理由相信它比纯线程阻塞IO更好),但是容量显着增加。 系统的稳定状态支持更高的负载。 异步IO可以更好地利用硬件资源。

当然,这种方法也有缺点。 其中最主要的(实际上,我认为这是唯一的)是库集成。 我们在光纤上调用的每个阻塞API都必须专门支持光纤。 顺便说一下,这并不是仅轻量级线程方法所独有的:要使用异步方法,所有使用的IO库也必须是异步的。 实际上,如果库具有异步API,则可以轻松地将其转换为光纤阻塞的API。 Comsat项目是一组将标准或流行的IO API与Quasar光纤集成在一起的模块。 Comsat的最新版本支持servlet,JAX-RS服务器和客户端以及JDBC。 即将发布的版本(以及基准测试中使用的版本)将增加对Apache HTTP客户端,Dropwizard,JDBI,Retrofit以及可能的jOOQ的支持。

翻译自: https://www.javacodegeeks.com/2015/04/scalable-robust-and-standard-java-web-services-with-fibers.html

博科光纤交换机java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

很棒的C语言入门笔记,推荐收藏!

点击蓝字关注我们c语言入门C语言一经出现就以其功能丰富、表达能力强、灵活方便、应用面广等特点迅速在全世界普及和推广。C语言不但执行效率高而且可移植性好&#xff0c;可以用来开发应用软件、驱动、操作系统等。C语言也是其它众多高级语言的鼻祖语言&#xff0c;所以说学习…

C语言的注释要注意几点

点击蓝字关注我们如果领导给你一个项目的源码让你阅读&#xff0c;并理解重构代码&#xff0c;但里面一句注释都没有&#xff0c;我想这肯定是之前同事“删库跑路”了。看一份源码什么很重要&#xff1f;除了各种代码规范之外&#xff0c;还有一个比较重要的就是注释。注释虽然…

java自动推断类型_推断:Facebook的新Java静态分析工具

java自动推断类型如何使用Facebook的Infer改善Java开发工作流程&#xff1f; 如果您与技术话题保持同步&#xff08;如果您正在阅读此博客&#xff0c;我想您会这样做&#xff09;&#xff0c;那么您可能听说过Facebook 刚刚向公众发布的新工具&#xff1a;推断。 由于它来自F…

android官方架构组件,Android 架构组件官方文档01——LifeCycle

使用生命周期感知组件处理生命周期支持生命周期的组件执行操作以响应另一个组件(例如Activity和fragment)的生命周期状态更改。这些组件可帮助您生成组织性更好&#xff0c;并且通常更轻量的代码&#xff0c;这些代码更易于维护。常见的模式是在Activity和fragment的生命周期方…

C语言的核心和灵魂

点击蓝字关注我们提起C语言大部分开发者很自然就会想到指针二字&#xff0c;没错&#xff0c;作为C的核心和灵魂&#xff0c;它的地位咱们就不再赘述了。今天我们想跟大家讲的是指针中的两个特有名词&#xff1a;“悬空指针”和“野指针”。悬空指针C语言中的指针可以指向一块内…

javaone_JavaOne 2015 –提交技巧和建议

javaone大家都知道JavaOne 。 感觉就像一直存在。 而且&#xff0c;即使我们跌宕起伏&#xff0c;而地理位置也不是我们想要的那样&#xff0c;旧金山也很昂贵&#xff0c;而且和。 这是有关各种Java的顶级会议。 今年又再次成为程序委员会&#xff08;“ Java&#xff0c;DevO…

C语言_结构体总结,附实例源码

点击蓝字关注我们当前文章介绍动态堆空间内存分配与释放&#xff0c;C语言结构体定义、初始化、赋值、结构体数组、结构体指针的相关知识点&#xff0c;最后通过一个学生管理系统综合练习结构体数组的使用。1. 动态内存管理C语言代码----->编译----->链接------>可执行…

四大C语言知识总结

点击蓝字关注我们1、#define宏定义以#号开头的都是编译预处理指令&#xff0c;它们不是C语言的成分&#xff0c;但是C程序离不开它们&#xff0c;#define用来定义一个宏&#xff0c;程序在预处理阶段将用define定义的来内容进行了替换。因此在程序运行时&#xff0c;常量表中并…

jdbc select语句_SELECT语句使用JDBC和Hibernate批量获取

jdbc select语句介绍 现在&#xff0c;我已经介绍了Hibernate对INSERT &#xff0c; UPDATE和DELETE语句的批处理支持&#xff0c;是时候分析SELECT语句结果集的批量提取了。 JDBC ResultSet提供了一个客户端Proxy游标&#xff0c;用于获取当前语句的返回数据。 执行该语句后&…

看懂开源项目,你得熟悉这几个 C++11 新特性

点击蓝字关注我们C11 中增加了许多的新特性。在本文中&#xff0c;我们来聊一下 lambda 表达式&#xff0c;闭包&#xff0c;std::function以及std::bind。lambda 表达式C11 中新增了 lambda 表达式这一语言特性。lambda 表达式可以让我们快速和便捷的创建一个 “函数”。下面是…

5元素升级android6,【五元素ifive X.7】无障碍升级,ifveX详细升级固件教程,快为爱机升级吧。...

android系统的乐趣就是可以随意的刷机&#xff0c;所以拿到如此高配置的ifiveX也是想随时体验最新的android系统。而很多朋友可能只会用设备&#xff0c;刷机这种比较技术性的动作就不太会弄了。也就在这周&#xff0c;才帮同事刷RUU把已经无法启动的G12刷了回来。所以刷机还是…

昆仑通态复制的程序可以用吗_昆仑通态专题(七):MCGS组态软件的设备窗口...

点击上方蓝色字体&#xff0c;关注我们设备窗口是MCGS嵌入版组态软件系统的重要组成部分&#xff0c;在设备窗口中建立系统与外部硬件设备的连接关系&#xff0c;使系统能够从外部设备读取数据并控制外部设备的工作状态&#xff0c;实现对工业过程设备的实时监控与操作。01 设备…

嵌入式C语言程序调试和宏使用的技巧

点击蓝字关注我们01.调试相关的宏在Linux使用gcc编译程序的时候&#xff0c;对于调试的语句还具有一些特殊的语法。gcc编译的过程中&#xff0c;会生成一些宏&#xff0c;可以使用这些宏分别打印当前源文件的信息&#xff0c;主要内容是当前的文件、当前运行的函数和当前的程序…

matlab中欠定方程组超定方程组_《数值天气预报》:球坐标系中的基本方程组

人们是如何预报天气的&#xff1f;目前的预报方法主要有两种&#xff1a;一种是基于由各种探测资料绘制的天气图&#xff0c;结合历史资料进行分析预测&#xff1b;另一种是基于大气方程组&#xff0c;利用数值解法对其进行求解&#xff0c;从而得到未来时刻的大气状态。后者就…

浏览器总是跳转到缓存界面_跳转到企业缓存之前要考虑的事项

浏览器总是跳转到缓存界面介绍 关系数据库事务是ACID &#xff0c;强大的一致性模型简化了应用程序开发。 由于启用Hibernate缓存是一项配置 &#xff0c;因此&#xff0c;只要数据访问层开始出现性能问题&#xff0c;就转向缓存非常吸引人。 添加缓存层确实可以提高应用程序性…

CryptoTab 服务器_如何架设FTP服务器,如何架设FTP服务器,具体架设方法

FTP服务器&#xff0c;则是在互联网上提供存储空间的计算机&#xff0c;它们依照FTP协议提供服务。 FTP的全称是File Transfer Protocol(文件传输协议)。顾名思义&#xff0c;就是专门用来传输文件的协议。简单地说&#xff0c;支持FTP协议的服务器就是FTP服务器。那么&#xf…

C语言和C++的区别和联系

点击蓝字关注我们C语言和C到底是什么关系&#xff1f;首先C和C语言本来就是两种不同的编程语言&#xff0c;但C确实是对C语言的扩充和延伸&#xff0c;并且对C语言提供后向兼容的能力。对于有些人说的C完全就包含了C语言的说法也并没有错。C一开始被本贾尼斯特劳斯特卢普&#…

hibernate语句_如何优化Hibernate EllementCollection语句

hibernate语句介绍 Hibernate支持三种数据映射类型 &#xff1a; 基本 &#xff08;例如String&#xff0c;int&#xff09;&#xff0c; Embeddable和Entity 。 通常&#xff0c;数据库行被映射到Entity &#xff0c;每个数据库列都与一个基本属性相关联。 当将多个字段映射组…

C++ 虚函数表剖析

点击蓝字关注我们一、概述为了实现C的多态&#xff0c;C使用了一种动态绑定的技术。这个技术的核心是虚函数表&#xff08;下文简称虚表&#xff09;。本文介绍虚函数表是如何实现动态绑定的。二、类的虚表每个包含了虚函数的类都包含一个虚表。我们知道&#xff0c;当一个类&a…

aix pax_通过Pax考试对JBoss Fuse 6.x进行集成测试,第一部分

aix paxJBoss Fuse是一个功能强大的分布式集成平台&#xff0c;具有内置功能&#xff0c;可用于针对集成的微服务部署进行集中式配置管理&#xff0c;服务发现&#xff0c;版本控制&#xff0c;API网关&#xff0c;负载平衡&#xff0c;故障转移等。 JBoss Fuse 6.x构建在Fabri…