Apache Camel Splitter,Threadpool和JMS

时间:2015-07-27 06:03:41

标签: java spring apache-camel

我在spring xml中定义了以下路由来拆分文本文件中的行并将每行发送到JMS队列

<bean id="myPool" class="java.util.concurrent.Executors" factory-method="newCachedThreadPool"/>

<camelContext id="concurrent-route-context" xmlns="http://camel.apache.org/schema/spring" trace="true">
    <route id="inbox-threadpool-split-route">
        <from uri="{{inbox.uri}}" />
            <log message="Starting to process file: ${header.CamelFileName}" />
            <split streaming="true" executorServiceRef="myPool">
                <tokenize token="\n" />
                <to uri="{{inventory.queue.uri}}" />    
            </split>
            <log message="Done processing file: ${header.CamelFileName}" />
    </route>
</camelContext>

inbox.uri是一个文件组件uri,用于监听目录中的文件,而inventory.queue.uri是一个JmsComponent uri,它连接到JMS服务器中的队列(Tibco EMS 6.X版本)。 JmsComponent uri很简单,比如“JmsComponent:queue:?username =&amp; password =”

上面的路由可以无误地运行,但是从文件中分割出来的行不会作为JMS消息发送到队列(即程序运行后队列仍为空)

如果我从拆分器定义中移除executorServiceRef =“myPool”(其余定义如下),则拆分的消息可以逐个传递到JMS队列。

如果我用“直接”端点替换“to”uri,则无论是否在分割器中使用线程池,都可以传递分割消息

JmsComponent中是否需要任何特殊设置才能使其与Splitter + threadpool一起使用?或者我错过的任何其他配置?

=======编辑20150731 =======

使用1000行的Big CSV文件进行测试时,我遇到了上述问题。如果我使用一个小文件(例如,仅10行)进行测试,我可以看到消息被传递到inventory.queue,但是从日志中看起来需要10秒才能完成拆分并将消息传递到队列。下面抓下了日志:

2015-07-31 11:02:07,210 [main           ] INFO  SpringCamelContext             - Apache Camel 2.15.0 (CamelContext: concurrent-route-context) started in 1.301 seconds
2015-07-31 11:02:07,220 [main           ] INFO  MainSupport                    - Apache Camel 2.15.0 starting
2015-07-31 11:02:17,250 [://target/inbox] INFO  inbox-threadpool-split-route   - Done processing file: smallfile.csv

查看路线于11:02:07开始并在11:02:17显示“完成处理...”声明,即10秒

如果我再次使用5行CSV进行测试,则需要5秒......看起来每行需要1秒才能分割并传送到JMS队列......这很慢

如果我将“to uri”更改为“direct”而不是“JMS”,则可以在一秒钟内快速完成拆分

此外,从JMS侦听器日志中,它能够在同一秒内接收所有10条消息。似乎Splitter将读取并拆分整个文件,为所有十行“准备”10条JMS消息,然后将所有消息传递到队列,但不是“拆分1行并立即传送1条JMS消息”。 。

是否有任何选项或配置可以改变拆分器行为并提高拆分性能?

2 个答案:

答案 0 :(得分:1)

我在使用具有标记化的分割器处理14G文件时遇到了类似的问题。我能够通过在Parsing Large Files with Apache Camel

上的Claus的帖子中使用聚合器来克服性能驼峰。

汇总批处理消息后,我使用生产者模板将这些消息路由到消息系统。希望有所帮助。

答案 1 :(得分:0)

感谢@Aayush Tuladhar分享的参考链接,我更新了我的路线如下:

<camelContext id="concurrent-route-context" xmlns="http://camel.apache.org/schema/spring" trace="false" >
    <route id="inbox-threadpool-split-route">
        <from uri="{{inbox.uri}}" />
            <log message="Starting to process file: ${header.CamelFileName}" />
            <split streaming="true" executorServiceRef="myPool">
                <tokenize token="\n" />
                <log message="split index - $simple{property.CamelSplitIndex}, row content=$simple{body}" />
                <aggregate strategyRef="stringBodyAggregator"  completionInterval="750"  >
                    <correlationExpression>
                        <simple>property.CamelSplitIndex</simple>
                    </correlationExpression>
                    <to uri="{{inventory.queue.uri}}" />
                </aggregate>
            </split>
            <log message="Done processing file: ${header.CamelFileName}" />
    </route>
</camelContext>     

这里的技巧是在分割器中添加了聚合器,使用了

property.CamelSplitIndex 

作为correlationExpression。 CamelSplitIndex为每个拆分行保持递增,因此聚合器实际上并没有“聚合”任何内容,而是结束“聚合”并立即将JMS消息排入JMS队列。 aggregationStrategy只是加入oldExchange和newExchange,但这里并不重要,因为它只是用于为聚合EIP实现必需的属性“strategyRef”

需要注意的一点是,在使用此技巧后,性能瓶颈转移到JMS消息生成器,每秒传递1条消息...我通过利用CachingConnectionFactory在Spring中定义JMS连接解决了这个问题。