Camel 的 SEDA、Direct 和 VM 组件指南
Apache Camel 中的 SEDA、Direct、Direct-VM 和 VM 组件、它们的作用以及何时可以使用它们。带有代码示例。
在设计 Camel 路线时,您有时可能希望路线具有多个输入。也许你想从Web服务接收消息和从JMS队列。
你不能在同一个路由中有多个from()
方法,那么你怎么能在同一个路由中有多个入口点呢?
同样,您可能希望在多个地方重用相同的 Camel 消息处理逻辑,那么如何避免重复代码呢?
这两个问题的答案是使用 Camel 的内存中消息传递组件将您的路由连接在一起:Direct、Direct-VM、VM 和 SEDA。
在本文中,我将解释这些组件中的每一个,它们有何不同,以及如何使用它们使您的路由更加模块化和更棒。
首先……一个示例场景
首先,我将从一个例子开始。
我定义了一个路由,通过将消息传递给某个底层系统来验证传入的订单。我的订单最初是通过 JMS 消息到达的。
但是,当订单开始来自新来源(例如文件上传或 Web 服务调用)时会发生什么?
为了避免重复相同的路由代码,Camel 具有内置功能,允许路由具有多个输入,通过使用一系列连接组件将这些路由粘合在一起。
那么它是怎样工作的?Camel 使用组件 Direct、VM 和 SEDA 将端点粘合在一起。
这些组件以不同的方式将您的 Camel 路线连接在一起。它们统称为 Camel 的内存中消息组件,因为它们允许消息在路由之间传递,而消息始终保留在内存中。这是一个非常重要的细节,我稍后会再次提及。
但是现在,让我们看看这些组件中的每一个,看看它们有什么不同,以及您可以在哪里使用它们。
Direct component
这一定是 Camel 初学者最常问到的问题之一:
路径中的“direct”是什么意思?
您可能已经在网络上的许多 Camel 教程中看到过这些代码direct:...
。但direct
实际上有什么作用呢?
Apache Camel 的Direct 组件是一种将路由连接在一起的方式。当它作为路由中的启动组件使用时,可以从其他路由中调用,作为触发路由的一种方式。由于 Direct 是一个同步组件,因此在同一线程中继续执行。
direct
是将您的路线链接在一起的最简单的方法之一。当它在from()
定义中使用时,它会创建一个可以被其他 Camel 路由调用的同步端点。例如,这段以from(direct)开头的代码:
from("direct:yourname")...
...将创建一个名为yourname
. 这同一个端点然后可以在另一个被调用to()
语句别的地方,就像这样:
.to("direct:yourname"); // sends the message to the direct:yourname endpoint
在示例中,它经常被使用,因为它提供了一个简单的路由入口点,而不必公开 Web 服务,或以其他方式依赖外部接口。
示例:使用 Direct 组件
让我们用一个例子来说明 Direct 组件:
from("file:/home/files/in") // receive a file
.to("direct:processTheFile"); // send to direct endpoint
.to("Body is now ${body}"); // will print 'Eggs!'
// meanwhile...
from("direct:processTheFile") // receive from direct endpoint
.setBody("Eggs!"); // modify the message body</code>
但是,Direct 的简单性也有一些缺点。
直接端点只能被在同一个 CamelContext和同一个 JVM中运行的其他路由访问。这意味着您不能从另一个 CamelContext 访问 Direct 端点。请记住,CamelContext 是创建和启动 Camel 路由的容器。
那么如果你想访问另一个 CamelContext 中的路由会发生什么?您使用下一个组件 Direct-VM。
这个非常简单的示例使用 Camel 的 File 组件接收文件。处理的每个文件都作为 Exchange 传递到直接端点processTheFile
。
另外,我们已将processTheFile
端点定义为修改消息正文的路由的起始组件。完成此操作后,新消息将返回到调用路由。所有这些都是在同一个线程中同步发生的。
Direct-VM component
Direct-VM 是一个组件,它允许您同步调用同一 JVM 中的另一个端点,即使它位于不同的CamelContext 中。
当用作启动组件时,Direct-VM 将该路由公开为可以从另一个路由同步调用的端点。
与Direct-VM 组件的不同之处在于,direct-vm 端点可以从其他 Camel Contexts 中看到,只要它们共享相同的 Java 虚拟机 (JVM)。
示例:使用 Direct-VM 组件
如果我们想炫耀 Direct-VM 组件,我们可以在应用程序 A 中定义一个路由:
java from("file:src/files/input") .to("direct-vm:process-file") // invoke the direct-vm endpoint
这将调用此 Direct 端点,位于应用程序 B 中...:
java from("direct-vm:process-file") // receive from direct-vm endpoint .to("log:samplelog"); // log the message
只要这两个应用程序都在同一个 JVM 中运行——例如,在同一个 Spring Boot 应用程序中使用一个应用程序容器,如 Apache Karaf、Wildfly 甚至不同的 CamelContexts——那么应用程序 A 将能够调用direct-vm应用程序中的端点B.
这开辟了将不在同一 CamelContext 中开发的路由链接在一起的可能性。例如,如果您在一个容器中部署了不同的 CamelContexts,您可能会使用此组件 - 例如当您部署到 JBoss Fuse或Talend ESB 时。
SEDA组件
Camel 的 SEDA 组件允许您使用简单的queue将路由连接在一起。
在 Camel 路由中,当消息被发送到 SEDA 端点时,它被存储在一个基本的内存队列中,并且控制立即返回到调用路由。
然后,SEDA 使用者独立地从队列中提取消息,并开始处理它。
示例:使用 SEDA 组件
下面是一个 SEDA 队列的例子:
java rest("/orders").post() // receive an order via REST .to("seda:processOrder"); // send to the seda queue .setBody("Thanks for ordering!"); // create a REST response
from(“seda:processOrder”) // 从 seda 队列接收 .log(“Processing an order…”) .to(“file:orders/out”);</code>
在上面的示例中,消息将通过 REST 服务接收并发布到 SEDA 端点。消息到达processOrderSEDA 端点并进行处理,然后使用该file:组件将它们写入磁盘上的某个位置。
SEDA 通过创建自己的缓冲区来实现这一点,该缓冲区用于存储传入的消息。SEDA 开箱即用地创建了一个线程池来处理传入的消息,这意味着可以一次处理多条消息,从而使其可能具有更高的性能。
通过这种方式,可以将 SEDA 视为 JMS 队列的简单替代品。它提供了类似队列的功能,但没有运行像 ActiveMQ 这样的外部消息代理的开销。
请记住,Camel 将消息异步发布到 SEDA 端点。
您只能访问位于同一 CamelContext 中的SEDA 端点。那么如果你想向另一个 CamelContext 中的 SEDA 队列发送消息会发生什么?您使用下一个组件 VM。
VM component
与 Direct 和 Direct-VM 的关联方式类似,VM 是与 SEDA 类似的组件。
当用作启动组件时,SEDA 允许从另一个路由异步调用一个路由。
然而,SEDA 和 VM 之间的区别在于VM 组件允许从不同的 Camel 上下文访问端点,只要它们运行在同一个 JVM 中即可。
同样,VM 组件开启了以异步方式将不在同一 Camel 上下文中开发的路由链接在一起的可能性。
SEDA 和 VM 的缺点
使用像 SEDA 和 VM 这样的内存消息传递的最大缺点是,如果应用程序崩溃,您很有可能会丢失所有消息。
如果您设计的集成类型与消息丢失无关紧要,那么这不是主要考虑因素。
但是回想一下本文顶部的订单处理示例。如果订单在服务器中断期间丢失,这可能意味着失去业务。(呃哦。)
考虑一下何时适合使用这些内存中的消息传递组件,以及何时将消息移交给外部消息代理(例如ActiveMQ )更合适,以确保可靠性。
没有硬性规定。正确的解决方案始终取决于您的用例。因此,在使用 Camel 设计集成时,请考虑丢失消息时该怎么办。会有关系吗?如果是这样,请考虑使用事务和持久消息传递来最大程度地减少任何消息丢失。
总结和最佳实践
所以现在您已经了解了每个组件,您应该使用哪个,以及何时使用?
SEDA 与 Direct:
-
对于同一 CamelContext 中的同步(请求/响应)交互,请使用Direct
-
对于同一 CamelContext 中的异步(即发即忘)处理(以类似队列的方式处理消息),请使用SEDA
VM 与 Direct-VM:
-
对于不同 CamelContext但在同一个 JVM 中的**同步(请求/响应)交互,使用Direct-VM**
-
对于不同 CamelContext但在同一 JVM 中的**异步(即发即忘)交互,请使用VM**
Direct、SEDA、VM 和 Direct-VM 的比较
此表比较了每个组件,并显示它们是否可以从另一个 CamelContext(在同一 JVM 中)访问:
Component | 类型 | 来自同一个 CamelContext | 来自另一个 CamelContext |
---|---|---|---|
Direct | 同步 | 是的 | 不 |
Direct-VM | 同步 | 是的 | 是的 |
SEDA | 异步 | 是的 | 不 |
VM | 异步 | 是的 | 是的 |