2015-04-07 40 views
0

我遇到的春天集成參考文檔輪詢器和內存泄漏

的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" /> 

回答

0

我的問題是我誤解這一切的工作方式?

是的,你誤解了。

僅在當前輪詢退出時查詢觸發器(本例中爲PeriodicTrigger,間隔爲50ms)才能計算下一輪詢時間。

只有一個同時運行的輪詢線程。如果沒有消息,則輪詢線程暫停5秒;然後查詢觸發器(t.nextExecutionTime()),並且下一輪投票安排爲+50ms;因此,沒有數據,每個5.05秒就會有一個線程運行。

當消息存在時,如果希望併發性大於1,則可以使用任務執行程序來允許輪詢線程切換到另一個線程,以便在下一輪詢時間立即查詢觸發器。

根據我的經驗

請澄清「你的經驗」,並顯示配置,證據等

如果你有懷疑的線程泄漏的第一步,通常是取一個線程轉儲來弄清楚他們都在做什麼。

編輯 :(回覆您的評論如下)。

在這種情況下,CALLER_RUNS並沒有真正的缺點,因爲雖然當前線程「排在前面」排隊的任務,但它不像這個輪詢比排隊的任務有更新的數據,它只是一個輪詢。但是,輪詢器線程是有限的資源(儘管可以更改限制),因此通常不鼓勵在輪詢器線程上長時間運行的任務。

ABORT可能會在日誌中造成一些噪音;另一種方法是配置PollSkipAdvice,其中建議可以查看任務隊列並默默忽略當前的輪詢。在4.2中,我們有added even more flexibility to the poller

你會在互聯網上發現很多文章說使用RDBMS作爲隊列並不是最好的想法;您可能需要考慮使用JMS或rabbitmq支持的頻道。如果您與JDBC綁定,則應確保使用JdbcChannelMessageStore而不是JdbcMessageStore。前者是支持渠道的首選,因爲它只使用1個表;由於消息組表的爭用,後者在用於備份信道時有一些性能問題。有關更多信息,請參見Backing Message Channels in the JDBC Support chapter

+0

嗨,「基於我的經驗」是關於我之前在舊的Spring論壇發佈的問題,我現在找不到(用戶名我是Tim.Taylor,你最近在Stackoverflow上用另一張海報回答了參考我的職位,你的回答在春季論壇關於MAX-mesaages每民意調查)的一個 – TimTaylor

+0

我的老問題,我可以在任一站點不再發現是關於一個內存泄漏我有,我敢肯定是因爲我已成立的時間間隔觸發比在使用任務收到的​​超時時間:執行併發,也許我missunderstood這個問題的答案,以及 - 或者我錯誤地記住它,要麼如果使用任務執行與POSS是 – TimTaylor

+0

您需要使用有界任務執行程序來限制併發性,例如,使用帶有有界隊列的線程池。當沒有可用的線程和隊列是滿的,執行器可被配置爲中止輪詢,或簡單地運行在輪詢器線程(CALLER_RUNS策略)此投票,從而直到當前投票完成懸浮輪詢。如果您使用無限任務執行程序,那麼是的,您可能會很快耗盡內存。 –