Spring Boot假死诊断实战记录

这两天遇到一个服务假死的问题,具体现象就是服务不再接收任何请求,客户端会抛出Broken Pipe。

检查系统状态

执行top,发现CPU和内存占用都不高,但是通过命令

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

发现有大量的CLOSE_WAIT端口占用,继续调用该服务的api,等待超时之后发现CLOSE_WAIT的数量也没有上升,也就是说服务几乎完全僵死。

检查JVM情况

怀疑可能是线程有死锁,决定先dump一下线程情况,执行

jstack <pid> > /tmp/thread.hump

发现tomcat线程基本也正常,都是parking状态。

这就比较奇怪了,继续想是不是GC导致了STW,使用jstat查看垃圾回收情况

app@server:/tmp$ jstat -gcutil 1 2000 10
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 27.79 65.01 15.30 94.75 92.23 1338 44.375 1881 475.064 519.439

一看吓一跳,FGC的次数居然超过了YGC,时长有475s。一定是有什么原因触发了FGC,好在我们打开了GC log。

发现一段时间内频繁发生Allocation Failure引起的Full GC。而且eden区的使用占比也很大,考虑有频繁新建对象逃逸到老年代造成问题。询问了一下业务的开发,确认有一个外部对接API没有分页,查询后可能会产生大量对象。

由于外部API暂时无法联系对方修改,所以为了先解决问题,对原有的MaxNewSize进扩容,从192MB扩容到一倍。经过几天的观察,发现gc基本趋于正常

S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 3.37 60.55 8.60 95.08 92.98 87 2.421 0 0.000 2.421

扩容之前对heap进行了dump

jmap -dump:format=b,file=heapDump <PID>

通过MAT分析内存泄露,居然疑似是jdbc中的一个类,但其实整体占用堆容量并不多。

分析了线程数量,大约是240多条,与正常时也并没有很大的出入。而且大量的是在sleep的定时线程。

总结

本次排查其实并未找到真正的原因,间接表象是FGC频繁导致服务假死。而且acturator端口是正常工作的,导致health check进程误认为服务正常,没有触发告警。如果你也遇到类似的情况欢迎一起讨论。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • Spring Boot假死诊断实战记录

    这两天遇到一个服务假死的问题,具体现象就是服务不再接收任何请求,客户端会抛出Broken Pipe. 检查系统状态 执行top,发现CPU和内存占用都不高,但是通过命令 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 发现有大量的CLOSE_WAIT端口占用,继续调用该服务的api,等待超时之后发现CLOSE_WAIT的数量也没有上升,也就是说服务几乎完全僵死. 检查JVM情况 怀疑可能是线程有死锁,决定先

  • Spring Boot集成Swagger2项目实战

    一.Swagger简介 上一篇文章中我们介绍了Spring Boot对Restful的支持,这篇文章我们继续讨论这个话题,不过,我们这里不再讨论Restful API如何实现,而是讨论Restful API文档的维护问题. 在日常的工作中,我们往往需要给前端(WEB端.IOS.Android)或者第三方提供接口,这个时候我们就需要给他们提供一份详细的API说明文档.但维护一份详细的文档可不是一件简单的事情.首先,编写一份详细的文档本身就是一件很费时费力的事情,另一方面,由于代码和文档是分离的,所

  • Spring Boot应用监控的实战教程

    概述 Spring Boot 监控核心是 spring-boot-starter-actuator 依赖,增加依赖后, Spring Boot 会默认配置一些通用的监控,比如 jvm 监控.类加载.健康监控等. 我们之前讲过Docker容器的可视化监控,即监控容器的运行情况,包括 CPU使用率.内存占用.网络状况以及磁盘空间等等一系列信息.同样利用SpringBoot作为微服务单元的实例化技术选型时,我们不可避免的要面对的一个问题就是如何实时监控应用的运行状况数据,比如:健康度.运行指标.日志信

  • 详解spring boot实现多数据源代码实战

    之前在介绍使用JdbcTemplate和Spring-data-jpa时,都使用了单数据源.在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.properties文件中配置连接参数即可.但是往往随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,下面基于之前的JdbcTemplate和Spring-data-jpa例子分别介绍两种多数据源的配置方式. 多数据源配置 创建一个Spring配置类,定义两个DataSource

  • Spring Boot整合RabbitMQ开发实战详解

    这篇文章主要讲基本的整合.先把代码跑起来,再说什么高级特性. RabbitMQ 中的一些术语 如果你打开 RabbitMQ web 控制台,你会发现其中有一个 Exhanges 不好理解.下面简单说明一下. 交换器(Exchange) 交换器就像路由器,我们先是把消息发到交换器,然后交换器再根据路由键(routingKey)把消息投递到对应的队列.(明白这个概念很重要,后面的代码里面充分体现了这一点) 队列(Queue) 队列很好理解,就不用解释了. 绑定(Binding) 交换器怎么知道把这条

  • 关于Spring Boot内存泄露排查的记录

    目录 背景 排查过程 1.使用Java层面的工具定位内存区域 2. 使用系统层面的工具定位堆外内存 3. 为什么堆外内存没有释放掉呢? 总结 在项目迁移到Spring Boot之后,发生内存使用量过高的问题.本文介绍了整个排查过程以及使用到的工具,也非常适用于其他堆外内存排查. 背景 为了更好地实现对项目的管理,我们将组内一个项目迁移到MDP框架(基于Spring Boot),随后我们就发现系统会频繁报出Swap区域使用量过高的异常.笔者被叫去帮忙查看原因,发现配置了4G堆内内存,但是实际使用的

  • Spring Boot外部化配置实战解析

    一.流程分析 1.1 入口程序 在 SpringApplication#run(String... args) 方法中,外部化配置关键流程分为以下四步 public ConfigurableApplicationContext run(String... args) { ... SpringApplicationRunListeners listeners = getRunListeners(args); // 1 listeners.starting(); try { ApplicationA

  • Spring Boot Web 开发注解篇

    一.spring-boot-starter-web 依赖概述 在 Spring Boot 快速入门中,只要在 pom.xml 加入了 spring-boot-starter-web 依赖,即可快速开发 web 应用.可见,Spring Boot 极大地简化了 Spring 应用从搭建到开发的过程,做到了「开箱即用」的方式.Spring Boot 已经提供很多「开箱即用」的依赖,如上面开发 web 应用使用的 spring-boot-starter-web ,都是以 spring-boot-sta

  • Spring Boot 项目中使用Swagger2的示例

    本文介绍了Spring Boot 项目中使用Swagger2的示例,分享给大家,具体如下: 添加Swagger2依赖 在pom.xml中加入Swagger2的依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.2.2</version> </dependency&g

  • Spring Boot中使用RabbitMQ的示例代码

    很久没有写Spring Boot的内容了,正好最近在写Spring Cloud Bus的内容,因为内容会有一些相关性,所以先补一篇关于AMQP的整合. Message Broker与AMQP简介 Message Broker是一种消息验证.传输.路由的架构模式,其设计目标主要应用于下面这些场景: 消息路由到一个或多个目的地 消息转化为其他的表现方式 执行消息的聚集.消息的分解,并将结果发送到他们的目的地,然后重新组合相应返回给消息用户 调用Web服务来检索数据 响应事件或错误 使用发布-订阅模式

随机推荐