Spring integration 轮询器和内存泄漏

Spring integration 轮询器和内存泄漏,spring-integration,Spring Integration,我在spring集成参考文档中遇到了以下内容 receiveTimeout属性指定轮询器调用接收操作时,如果没有可用消息,则轮询器应等待的时间量。例如,考虑表面上看起来相似的两个选项,但实际上是完全不同的:第一个具有5秒的间隔触发和50毫秒的接收超时,而第二个具有50毫秒的间隔触发和5秒的接收超时。如果消息在其一个轮询调用返回后立即到达,则第一个轮询调用可能会比到达通道的消息晚4950毫秒。另一方面,第二种配置将不会错过超过50毫秒的消息。不同之处在于,第二个选项需要线程等待,但因此它能够更快地

我在spring集成参考文档中遇到了以下内容

receiveTimeout属性指定轮询器调用接收操作时,如果没有可用消息,则轮询器应等待的时间量。例如,考虑表面上看起来相似的两个选项,但实际上是完全不同的:第一个具有5秒的间隔触发和50毫秒的接收超时,而第二个具有50毫秒的间隔触发和5秒的接收超时。如果消息在其一个轮询调用返回后立即到达,则第一个轮询调用可能会比到达通道的消息晚4950毫秒。另一方面,第二种配置将不会错过超过50毫秒的消息。不同之处在于,第二个选项需要线程等待,但因此它能够更快地响应到达的消息。这种技术称为长轮询,可用于模拟轮询源上的事件驱动行为

根据我的经验,第二个选项可能会导致问题,因为50毫秒的间隔将使轮询器每50毫秒运行一次,但是如果没有消息要拾取,则创建的每个线程将等待5秒钟以显示消息。在这5秒钟内,轮询器将再执行100次,可能会再创建100个线程,以此类推

这很快就消失了

我的问题是我是否误解了这一切的运作方式?因为如果我是正确的,我认为应该更改参考文档,或者至少添加一个警告

e<bean id="store" class="org.springframework.integration.jdbc.store.JdbcChannelMessageStore">
    <property name="dataSource" ref="channelServerDataSource"/>
    <property name="channelMessageStoreQueryProvider" ref="queryProvider"/>
    <property name="region" value="${user.name}_${channel.queue.region:default}"/>
    <property name="usingIdCache" value="false"/>
</bean> 

<int:transaction-synchronization-factory id="syncFactory">
    <int:after-commit expression="@store.removeFromIdCache(headers.id.toString())" />
    <int:after-rollback expression="@store.removeFromIdCache(headers.id.toString())"/> 
</int:transaction-synchronization-factory>

<int:channel id="transacitonAsyncServiceQueue">
    <int:queue message-store="store"/> 
    <!--  <int:queue/>  --> 
</int:channel>

<bean id="rxPollingTrigger" class="org.springframework.scheduling.support.PeriodicTrigger">
    <constructor-arg value="500"/>
    <constructor-arg value="MILLISECONDS"/>
    <property name = "initialDelay" value = "30000"/> 
    <!-- initialDelay important to ensure channel doesnt start processing before the datasources have been initialised becuase we
         now persist transactions in the queue, at startup (restart) there maybe some ready to go which get processed before the
         connection pools have been created which happens when the servlet is first hit -->
</bean> 

<int:service-activator ref="asyncChannelReceiver" method="processMessage" input-channel="transacitonAsyncServiceQueue">
    <int:poller trigger="rxPollingTrigger" max-messages-per-poll="20"  task-executor="taskExecutor" receive-timeout="400">
        <int:transactional transaction-manager="transactionManagerAsyncChannel" /> 
    </int:poller>
    <int:request-handler-advice-chain>
        <ref bean="databaseSessionContext" />
    </int:request-handler-advice-chain>
</int:service-activator>

<task:executor id="taskExecutor" pool-size="100-200" queue-capacity="200" keep-alive="1" rejection-policy="CALLER_RUNS" />
我的问题是我是否误解了这一切的运作方式

是的,你误解了

在这种情况下,只有在当前轮询退出时,才会参考间隔为50ms的PeriodicTrigger触发器来计算下一次轮询时间

只有一个轮询器线程同时运行。如果没有消息,轮询线程暂停5秒;然后在t.nextExecutionTime查询触发器,下一次轮询计划为+50ms;因此,在没有数据的情况下,单个线程将每5.05秒运行一次

如果存在消息,并且希望并发性大于1,则可以使用任务执行器允许轮询器线程切换到另一个线程,以便在下次轮询时立即查询触发器

根据我的经验

请澄清您的经验,并展示配置、证据等

如果怀疑有线程泄漏,通常第一步是进行线程转储,以了解它们都在做什么

编辑:回应您下面的评论

在这个场景中,CALLER_的运行并没有什么坏处,因为尽管当前线程跳到了排队任务的前面,但这个轮询并不是比排队任务有更新的数据,它毕竟只是一个轮询。但是,轮询器线程是一种有限的资源,尽管限制可以更改,因此通常不鼓励轮询器线程上的长时间运行任务

中止可能会在日志中引起一些噪音;另一种方法是配置通知,通知可以在其中查看任务队列并以静默方式忽略当前轮询。在4.2中,我们得到了


你会发现互联网上有很多文章说使用RDBMS作为队列不是最好的主意;您可能需要考虑JMS或RabBMQ支持的通道。如果您绑定到JDBC,那么应该确保使用JdbcChannelMessageStore,而不是JdbcMessageStore。前者优先用于支持通道,因为它只使用1个表;后者在用于支持通道时存在一些性能问题,因为消息组表上存在争用。有关更多信息,请参阅。

您好,根据我的经验,我在旧春论坛上发布了一个问题,我现在找不到用户名,我想是Tim。Taylor你最近在Stackoverflow上回答了另一张海报,其中提到了我在春季论坛上回答的关于每个轮询的最大mesaages的帖子。我以前在两个网站上都找不到的问题是关于我的内存泄漏,我肯定是因为我设置了使用task:executor for concurrency时,interval触发器短于接收超时,可能我也理解错了答案-或者我记错了答案,或者,如果将task executor与轮询器一起使用,则可能需要约束与有界task executor的并发性,例如,使用具有有界队列的线程池。当没有可用线程且队列已满时,可以将执行器配置为中止轮询,或者只需在轮询器线程调用者运行策略上运行此轮询,从而暂停轮询,直到当前轮询完成。如果您使用无限任务执行器,那么,是的,您的内存可能会很快用完。谢谢Gary。我使用的是一个有界执行器:那么,继续,如果我们有一个间隔触发器 50毫秒,超时5秒,加上一个线程池,池中的所有线程都将被用来等待消息到达通道,对吗?也许这就是我之前的文章所涉及的。