spring?batch線上異常定位記錄
前言
最近線上spring batch的一個(gè)問(wèn)題圍繞博主近兩周時(shí)間,甚是擾神。具體現(xiàn)象為,spring batch執(zhí)行中莫名其妙線程就卡住了,不往下走了。下面會(huì)詳細(xì)描述整個(gè)問(wèn)題的排查過(guò)程
環(huán)境說(shuō)明
spring batch分區(qū)環(huán)境,共6個(gè)分片,兩臺(tái)實(shí)例,分別6個(gè)線程處理,由xxljob任務(wù)調(diào)度觸發(fā)日切job,配置由apollo管理。
排查過(guò)程
1.xxljob長(zhǎng)連接導(dǎo)致
why?因?yàn)槲覀冇许?xiàng)目是老項(xiàng)目,任務(wù)調(diào)度使用的quartz,原來(lái)的批處理沒(méi)啥毛病。
然后修改了dayEndjob的觸發(fā)執(zhí)行改為異步,發(fā)現(xiàn)問(wèn)題依舊。
2.定位JpaPagingItemReader的問(wèn)題
盯著B(niǎo)ATCH_STEP_EXECUTION看了很久,發(fā)現(xiàn)其他的step_execution都是啟動(dòng)中的狀態(tài),其中兩個(gè)step_execution是讀取中,并且和其他step_execution明顯區(qū)別version版本一直在增加,初步判斷有線程一直在修改.但是日志一點(diǎn)動(dòng)靜都沒(méi)有,如果是線程阻塞了,肯定也不存在線程修改數(shù)據(jù)庫(kù)數(shù)據(jù)。然后在apollo把日志級(jí)別調(diào)整成DEBUG級(jí)別(spring boot線上日志級(jí)別動(dòng)態(tài)調(diào)整),發(fā)現(xiàn)輸出大量的如下日志信息
java.lang.IllegalStateException: Transaction already active at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:42) at org.springframework.batch.item.database.JpaPagingItemReader.doReadPage(JpaPagingItemReader.java:197) at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108) at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:88) at org.springframework.batch.item.support.SynchronizedItemStreamReader.read(SynchronizedItemStreamReader.java:55) at sun.reflect.GeneratedMethodAccessor71.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133) at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy126.read(Unknown Source) at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:91) at org.springframework.batch.core.step.item.FaultTolerantChunkProvider.read(FaultTolerantChunkProvider.java:87) at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:116) at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374) at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144) at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:110) at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:69) at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406) at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330) at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:272) at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81) at org.springframework.batch.repeat.support.TaskExecutorRepeatTemplate$ExecutingRunnable.run(TaskExecutorRepeatTemplate.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
3.確定JpaPagingItemReader的問(wèn)題
因?yàn)轫?xiàng)目使用了jpa。故而數(shù)據(jù)讀取器用用了JpaPagingItemReader,從異常信息找到JpaPagingItemReader文件后發(fā)現(xiàn),JpaPagingItemReader根據(jù)配置的transacted=true,編程式的開(kāi)啟了事務(wù),而提交事務(wù)和回滾事務(wù)并沒(méi)有作try,catch處理,而一旦拋出了如上事務(wù)異常,因?yàn)镕aultTolerantChunkProvider 讀取數(shù)據(jù)實(shí)現(xiàn)如下
就會(huì)進(jìn)入一個(gè)一直拋異常的死循環(huán),至此所有問(wèn)題都清晰明了了。
解決問(wèn)題
參照J(rèn)paPagingItemReader既有的實(shí)現(xiàn),自定義一個(gè)CustomJpaPagingItemReader閱讀器,去掉事務(wù)部分代碼,或者實(shí)例化JpaPagingItemReader的時(shí)候設(shè)置transacted為false。這個(gè)參數(shù)主要用途我猜測(cè)是為了讓用戶(hù)自己選擇查詢(xún)出來(lái)的對(duì)象是否為entityManager管理的游離態(tài)。我們項(xiàng)目用不著,就直接去掉事務(wù)部分了。一般如果查詢(xún)沒(méi)問(wèn)題,不會(huì)有如上情況,這個(gè)bug也是隱藏的深,死循環(huán)后info日志級(jí)別下沒(méi)有任何輸出,就和線程阻塞似的。解決這個(gè)問(wèn)題后感覺(jué)神清氣爽啊
以上就是spring batch線上異常定位記錄的詳細(xì)內(nèi)容,更多關(guān)于spring batch線上異常定位的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 如何使用Spring Batch進(jìn)行批處理任務(wù)管理
- 使用Spring?Batch實(shí)現(xiàn)大數(shù)據(jù)處理的操作方法
- 使用Spring Batch實(shí)現(xiàn)批處理任務(wù)的詳細(xì)教程
- SpringBoot整合Spring Batch示例代碼
- SpringBatch結(jié)合SpringBoot簡(jiǎn)單使用實(shí)現(xiàn)工資發(fā)放批處理操作方式
- Spring?Batch實(shí)現(xiàn)批量處理
- Spring?Batch批處理框架操作指南
- SpringBatch數(shù)據(jù)寫(xiě)入實(shí)現(xiàn)
相關(guān)文章
SpringBoot讀取properties或者application.yml配置文件中的數(shù)據(jù)
這篇文章主要介紹了SpringBoot讀取properties或者application.yml配置文件中的數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Spring Boot 排除某個(gè)類(lèi)加載注入IOC的操作
這篇文章主要介紹了Spring Boot 排除某個(gè)類(lèi)加載注入IOC的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java線程池ThreadPoolExecutor源碼深入分析
ThreadPoolExecutor作為java.util.concurrent包對(duì)外提供基礎(chǔ)實(shí)現(xiàn),以?xún)?nèi)部線程池的形式對(duì)外提供管理任務(wù)執(zhí)行,線程調(diào)度,線程池管理等等服務(wù)2022-08-08實(shí)現(xiàn)quartz定時(shí)器及quartz定時(shí)器原理介紹
Quartz是一個(gè)大名鼎鼎的Java版開(kāi)源定時(shí)調(diào)度器,功能強(qiáng)悍,使用方便,下面我們看看如何使用它2013-12-12解決org.apache.ibatis.binding.BindingException:?Invalid?boun
這篇文章主要介紹了解決org.apache.ibatis.binding.BindingException:?Invalid?bound?statement?(not?found)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05java實(shí)現(xiàn)字符串和日期類(lèi)型相互轉(zhuǎn)換的方法
這篇文章主要介紹了java實(shí)現(xiàn)字符串和日期類(lèi)型相互轉(zhuǎn)換的方法,涉及java針對(duì)日期與字符串的轉(zhuǎn)換與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-02-02java實(shí)現(xiàn)圖書(shū)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖書(shū)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03