spring batch线上异常定位记录

目录
  • 前言
  • 环境说明
  • 排查过程
    • 1.xxljob长连接导致
    • 2.定位JpaPagingItemReader的问题
    • 3.确定JpaPagingItemReader的问题
  • 解决问题

前言

最近线上spring batch的一个问题围绕博主近两周时间,甚是扰神。具体现象为,spring batch执行中莫名其妙线程就卡住了,不往下走了。下面会详细描述整个问题的排查过程

环境说明

spring batch分区环境,共6个分片,两台实例,分别6个线程处理,由xxljob任务调度触发日切job,配置由apollo管理。

排查过程

1.xxljob长连接导致

why?因为我们有项目是老项目,任务调度使用的quartz,原来的批处理没啥毛病。

然后修改了dayEndjob的触发执行改为异步,发现问题依旧。

2.定位JpaPagingItemReader的问题

盯着BATCH_STEP_EXECUTION看了很久,发现其他的step_execution都是启动中的状态,其中两个step_execution是读取中,并且和其他step_execution明显区别version版本一直在增加,初步判断有线程一直在修改.但是日志一点动静都没有,如果是线程阻塞了,肯定也不存在线程修改数据库数据。然后在apollo把日志级别调整成DEBUG级别(spring boot线上日志级别动态调整),发现输出大量的如下日志信息

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的问题

因为项目使用了jpa。故而数据读取器用用了JpaPagingItemReader,从异常信息找到JpaPagingItemReader文件后发现,JpaPagingItemReader根据配置的transacted=true,编程式的开启了事务,而提交事务和回滚事务并没有作try,catch处理,而一旦抛出了如上事务异常,因为FaultTolerantChunkProvider 读取数据实现如下

就会进入一个一直抛异常的死循环,至此所有问题都清晰明了了。

解决问题

参照JpaPagingItemReader既有的实现,自定义一个CustomJpaPagingItemReader阅读器,去掉事务部分代码,或者实例化JpaPagingItemReader的时候设置transacted为false。这个参数主要用途我猜测是为了让用户自己选择查询出来的对象是否为entityManager管理的游离态。我们项目用不着,就直接去掉事务部分了。一般如果查询没问题,不会有如上情况,这个bug也是隐藏的深,死循环后info日志级别下没有任何输出,就和线程阻塞似的。解决这个问题后感觉神清气爽啊

以上就是spring batch线上异常定位记录的详细内容,更多关于spring batch线上异常定位的资料请关注我们其它相关文章!

(0)

相关推荐

  • 浅谈Spring Batch在大型企业中的最佳实践

    在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后进行一系列的后续处理.这样的过程就是"批处理". 批处理应用通常有以下特点: 数据量大,从数万到数百万甚至上亿不等: 整个过程全部自动化,并预留一定接口进行自定义配置: 这样的应用通常是周期性运行,比如按日.周.月运行: 对数据处理的准确性要求高,并且需要容错机制.回滚机制.完善的日志监控等. 什么是Spring batch Sprin

  • Springboot启动报错时实现异常定位

    首先大家了解什么是Spring Boot?Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.用我的话来理解,就是spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架.Spring Boot作为Spring MVC的升级版,但是却没有太多的联系,换句话说你学

  • springbatch的封装与使用实例详解

    Spring Batch官网介绍: A lightweight, comprehensive batch framework designed to enable the development of robust batch applications vital for the daily operations of enterprise systems.(一款轻量的.全面的批处理框架,用于开发强大的日常运营的企业级批处理应用程序.) springbatch 主要实现批量数据的处理,我对bat

  • 详解Spring Batch 轻量级批处理框架实践

    实践内容 从 MariaDB 一张表内读 10 万条记录,经处理后写到 MongoDB . 具体实现 1.新建 Spring Boot 应用,依赖如下: <!-- Web 应用 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> &

  • Java中批处理框架spring batch详细介绍

    spring batch简介 spring batch是spring提供的一个数据处理框架.企业域中的许多应用程序需要批量处理才能在关键任务环境中执行业务操作. 这些业务运营包括: 无需用户交互即可最有效地处理大量信息的自动化,复杂处理. 这些操作通常包括基于时间的事件(例如月末计算,通知或通信). 在非常大的数据集中重复处理复杂业务规则的定期应用(例如,保险利益确定或费率调整). 集成从内部和外部系统接收的信息,这些信息通常需要以事务方式格式化,验证和处理到记录系统中. 批处理用于每天为企业处

  • spring batch线上异常定位记录

    目录 前言 环境说明 排查过程 1.xxljob长连接导致 2.定位JpaPagingItemReader的问题 3.确定JpaPagingItemReader的问题 解决问题 前言 最近线上spring batch的一个问题围绕博主近两周时间,甚是扰神.具体现象为,spring batch执行中莫名其妙线程就卡住了,不往下走了.下面会详细描述整个问题的排查过程 环境说明 spring batch分区环境,共6个分片,两台实例,分别6个线程处理,由xxljob任务调度触发日切job,配置由apo

  • j2Cache线上异常排查问题解决记录分析

    目录 问题背景 问题分析 假设问题 小心求证 问题重现 问题解决 问题后记-下面才是真正的原因 重新假设 最终解决 问题背景 开发反馈,线上有个服务在运行一段时间后,就会抛异常导致redis缓存不可用.项目使用了j2Caceh,异常是j2Cache的RedisCacheProvider抛出来的,如: Exception in thread "main" redis.clients.jedis.exceptions.JedisException: Could not get a reso

  • 阿里Druid数据连接池引发的线上异常解决

    目录 前言 过程一:定位工作流 过程二:定位JPA的OpenEntityManagerInViewInterceptor 过程三:定位Druid,真正的罪魁祸首 后记: 前言 事件起因:项目使用了activiti工作流,系统是由老的spring mvc项目改造成的spring boot项目,数据库链接池从dbcp切换到druid,新系统上线后,同事多次系统隔一段时间后数据查询就很慢,基本出不来. 由此开始了线上bug排查之路.这个问题从一开始就模糊定位到数据库层面的问题,因为只有和数据相关的操作

  • spring boot线上日志级别动态调整的配置步骤

    目录 前言 正文 springboot版本:1.5.7 配置 文末结语 前言 日志模块是每个项目中必须的,用来记录程序运行中的相关信息.一般在开发环境下使用DEBUG级别的日志输出,为了方便查看问题,而在线上一般都使用INFO级别的日志,主要记录业务操作的日志.那么问题来了,当线上环境出现问题希望输出DEBUG日志信息辅助排查的时候怎么办呢?修改配置文件,重新打包然后上传重启线上环境,之前确实是这么做的.下面会介绍使用动态调整线上日志级别来解决这个问题. 正文 spring boot版本:1.5

  • java == 引发的线上异常详解

    今天分享遇到的一个线上的 bug,线上代码: class Scratch { public static void main(String[] args) { JSONArray arrays = JSONUtil.parseArray("[{'type':1},{},{'type':2},{'type':2}" + ",{'name':'zhangsan'},{'type':1},{'type':1},{'type':1}]"); List<User>

  • 线上dubbo线程池耗尽CyclicBarrier线程屏障异常解决记录

    目录 事件背景 问题定位 解决问题 文末结语 事件背景 系统相关使用人员反馈系统故障,日志显示从ams系统服务提示dubbo处理线程不足,具体异常信息如下: 问题定位 从上图可知,dubbo的处理线程池满了,默认200个线程,活动线程也是200个.这个现象非常不正常,我们的应用并发还没有到这个程度能同时占用200个线程处理请求.然后去读了下dubbo源码,发现dubbo也认为这种情况不正常,然后帮我们记录了应用的线程堆栈信息,这个非常赞.代码如下: 上面这段代码,在线程池不够用时,会每隔十分钟输

  • 线上Spring CPU 高负载解决思路详解

    目录 引言 定位问题 日志搜索 监控看板 ThreadDump 优化 事后反思 引言 背景: 在某一天,运营同事突然发现运营看板好几天没有更新数据了, 然后找了过来?! 这里看似抛出了一个问题 ? 但细想一下, 同时暴露了我们对于线上服务的监控未完全覆盖到!!! 这是致命的!!! 当然, 这篇文章先不讨论监控的问题, 后面会推出完善的监控方案 定位问题 问题抛过来了, 那么我们第一步要怎样做呢? 拿到问题的第一步, 先理解题意, 这里有几个关键的信息点 第一 : 好几天, 具体哪一天, 这个后面

  • 一次线上mongo慢查询问题排查处理记录

    目录 一.简单介绍 二.事件脉络 1.起因 2.排查处理 3.问题分析 4.回顾 三.总结 一.简单介绍 mongo语句查询条件中出现null或空串,可能会导致索引失效,查询优化器无法选择正确的查询计划,出现慢查询引起服务异常 mongo查询的执行计划使用了LRU缓存,在很多种情况下会失效,导致重新选择执行计划并缓存,供后续同类查询直接使用: 服务开始时一直运行正常,当执行计划失效后,恰好出现null值的查询导致选择了错误的执行计划并缓存,后续正常的查询也会出现异常. 二.事件脉络 1.起因 用

  • 一次线上websocket返回400问题排查的实战记录

    目录 现象 抓包排查 问题定位 解决方案1 解决方案2 原因探讨 总结 现象 生产环境websocket无法正常连接,服务端返回400 bad request,开发及测试环境均正常. 抓包排查 src:nginx服务器 172.16.177.193 dst:imp应用服务器 172.16.177.218 问题定位 观察到header中的host值带有下划线,在一些中间件(如kafka.hadoop)中,对host中的特殊字符也有限制.由此猜测是header问题. 经排查,此header来自ngi

  • thinkPHP线上自动加载异常与修复方法实例分析

    本文实例讲述了thinkPHP线上自动加载异常与修复方法.分享给大家供大家参考,具体如下: 项目遇到一个奇怪的问题,本地代码正常,服务器上却不正常. 经过测试,应该是自动加载出了问题,尝试了各种方法, 1.手动加载,发现好麻烦,没完没了. 2.自己写自动加载,写不出来,尴尬. 3.修改配置,使其支持自动加载,发现还是不行. 后来进行调试, 发现本地支持 import('@.ORG.OSS\OssClient'); import('@.ORG.OSS\Core\OssUtil'); 而服务器上,不

随机推荐