2012-11-17 66 views
1

我們已經建立了一個春天一批又一批電子郵件發件人作業執行以下操作:從JMS隊列Spring Batch的內存泄漏FlowJob,重複步驟

  1. 閱讀收到的電子郵件的詳細信息。
  2. 不要做任何處理,只是通過它們傳遞...
  3. 打開細節到電子郵件和「寫」他們SMTP
  4. 重複循環往復

這通常工作正常,但我們發現了大量的內存泄漏。在9個小時左右之後,可以看到單個FlowJob,但是748個JobExecution(全部爲「開始」),每個都持有778個(!)StepExecution個實例。總而言之,900 MB的東西。

下面是Spring配置(春季3.1,Spring Batch的2.1.9):

<bean id="jobRepository" 
    class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" /> 

<bean id="jobLauncher" 
    class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> 
    <property name="jobRepository" ref="jobRepository" /> 
    <property name="taskExecutor"> 
     <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/> 
    </property> 
</bean> 

<bean id="jmsEmailFetcher" class="org.springframework.batch.item.jms.JmsItemReader"> 
    <property name="jmsTemplate" ref="batchEmailJmsTemplate" /> 
</bean> 

<bean id="passthroughProcessor" class="org.springframework.batch.item.support.PassThroughItemProcessor" /> 

<bean id="transactionManager" 
    class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /> 

<!-- The Spring Batch *Limiter/Decider* --> 

<bean id="ourLimitDecider" class="our.special.InfiniteThrottledExecutionDecider" /> 

<!-- The Spring Batch *Job* --> 

<batch:job id="fetchEmailsJobBatch" restartable="true"> 
    <batch:step id="fetchEmailsStep" next="limitDecision"> 
     <batch:tasklet throttle-limit="10"> 
      <batch:chunk reader="jmsEmailFetcher" processor="passthroughProcessor" 
         writer="batchEmailService.javaMailItemWriter" commit-interval="100" skip-limit="999999999"> <!-- Might gets *lots* of MQ-not-up-yet fails --> 
       <batch:skippable-exception-classes> 
        <batch:include class="org.springframework.jms.JmsException" />  <!-- Generally MQ-not-up-yet ConnectionException, or Session-closed (in tests) --> 
        <batch:include class="java.lang.IllegalStateException" />   <!-- Yuk, usually/presumably a test SMTP server isn't yet connected --> 
        <batch:include class="org.springframework.mail.MailSendException" /> <!-- SMTP down... --> 
       </batch:skippable-exception-classes> 
      </batch:chunk> 
     </batch:tasklet> 
    </batch:step> 
    <batch:decision id="limitDecision" decider="ourLimitDecider"> 
     <batch:next on="CONTINUE" to="fetchEmailsStep" /> 
     <batch:end on="COMPLETED" /> 
    </batch:decision> 
</batch:job> 

我們InfiniteThrottledExecutionDecider基本上返回new FlowExecutionStatus("CONTINUE")每一次,以確保fetchEmailsStep被在流結束時執行,而工作永遠不會完成 - 至少直到我們準備好自己阻止它。

我們使用一個數據庫,因此我們預計在內存中保存的一些東西,但不是完整的記錄是以往任何時候都運行一切的 ...

有什麼錯我們的配置?或者我們的方法?


這是我們從日誌文件中有些什麼,我們被告知是步驟#778,什麼應該是獨一無二的工作實例。

23:58:18,782 - INFO (org.springframework.batch.core.job.SimpleStepHandler) - Duplicate step [fetchEmailsStep] detected in execution of job=[fetchEmailsJobBatch]. If either step fails, both will be executed again on restart. 
23:59:52,257 - INFO (org.springframework.batch.core.job.SimpleStepHandler) - Executing step: [fetchEmailsStep] 
23:59:52,257 - DEBUG (org.springframework.batch.core.step.AbstractStep) - Executing: id=778 
23:59:52,259 - DEBUG (org.springframework.batch.repeat.support.RepeatTemplate) - Starting repeat context. 
23:59:52,259 - DEBUG (org.springframework.batch.repeat.support.RepeatTemplate) - Repeat operation about to start at count=1 
23:59:52,259 - DEBUG (org.springframework.batch.core.scope.context.StepContextRepeatCallback) - Preparing chunk execution for StepContext: [email protected] 
23:59:52,259 - DEBUG (org.springframework.batch.core.scope.context.StepContextRepeatCallback) - Chunk execution starting: queue size=0 
23:59:52,259 - DEBUG (org.springframework.batch.repeat.support.RepeatTemplate) - Starting repeat context. 
23:59:52,259 - DEBUG (org.springframework.batch.repeat.support.RepeatTemplate) - Repeat operation about to start at count=1 
... 5 second JMS timeout ... 
23:59:57,716 - DEBUG (org.springframework.batch.repeat.support.RepeatTemplate) - Repeat is complete according to policy and result value. 
23:59:57,716 - DEBUG (org.springframework.batch.core.step.item.ChunkOrientedTasklet) - Inputs not busy, ended: true 
23:59:57,716 - DEBUG (org.springframework.batch.core.step.tasklet.TaskletStep) - Applying contribution: [StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 
23:59:57,719 - DEBUG (org.springframework.batch.core.step.tasklet.TaskletStep) - Saving step execution before commit: StepExecution: id=778, version=1, name=fetchEmailsStep, status=STARTED, exitStatus=EXECUTING, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 
23:59:57,721 - DEBUG (org.springframework.batch.repeat.support.RepeatTemplate) - Repeat is complete according to policy and result value. 
23:59:57,721 - DEBUG (org.springframework.batch.core.step.AbstractStep) - Step execution success: id=778 
23:59:57,722 - DEBUG (org.springframework.batch.core.step.AbstractStep) - Step execution complete: StepExecution: id=778, version=3, name=fetchEmailsStep, status=COMPLETED, exitStatus=COMPLETED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0 
23:59:57,723 - DEBUG (org.springframework.batch.core.job.flow.support.SimpleFlow) - Completed state=fetchEmailsJobBatch.fetchEmailsStep with status=COMPLETED 
23:59:57,723 - DEBUG (org.springframework.batch.core.job.flow.support.SimpleFlow) - Handling state=fetchEmailsJobBatch.limitDecision100 
23:59:57,723 - DEBUG (org.springframework.batch.core.job.flow.support.SimpleFlow) - Completed state=fetchEmailsJobBatch.limitDecision100 with status=CONTINUE 
23:59:57,723 - DEBUG (org.springframework.batch.core.job.flow.support.SimpleFlow) - Handling state=fetchEmailsJobBatch.fetchEmailsStep 

問題是,堆轉儲顯示748個JobExecution s和581911 StepExecution秒。他們都來自哪裏?

回答

1

好的,回答我的問題,解決方案是放棄步驟流程並使「fetchEmailsS​​tep」永遠運行。

我們實現了通過去除我們的JmsTemplate(「batchEmailJmsTemplate」)的‘readTimeout’,子類org.springframework.batch.item.jms.JmsItemReader刪除檢查它阻止你使用無限JmsTemplate秒 - 並添加額外的日誌記錄。如果你不想覆蓋,你可以將「readTimeout」設置爲一個很大的數字。

更多的討論在這裏:http://forum.springsource.org/showthread.php?132468-Massive-memory-use-with-FlowJob-repeating-Steps&p=431279

我仍然不知道爲什麼內存使用量是相當巨大的,因爲它是...


[編輯]我也使用JobExecutionDecider(「our.special.InfiniteThrottledExecutionDecider」)來實現節流(基於<StepExecution>.writeCount),但這不得不去。我們現在使用延伸StepExecutionListenerSupport(或者您可以實施StepExecutionListener)的新類實現相同的結果。此豆的一個實例作爲<batch:listener>添加到我們的單一<batch:step>