现象

线上某个服务有接口非常慢,通过监控链路查看发现,中间的 GAP 时间非常大,实际接口并没有消耗很多时间,并且在那段时间里有很多这样的请求。

原因分析

先从监控链路分析了一波,发现请求是已经打到服务上了,处理之前不知道为什么等了 3s,猜测是不是机器当时负载太大了,通过 QPS 监控查看发现,在接口慢的时候 CPU 突然增高,同时也频繁的 GC ,并且时间很长,但是请求量并不大,并且这台机器很快就因为 Heap满了而被下掉了。

去看了下日志,果然有 OOM 的报错,但是从报错信息上并没办法找到 Root Cause。

system error: org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space   at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)   at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)   at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)   at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)   at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)

另外开发同学提供了线索,在发生问题的时候在跑一个大批量的一次性 JOB,怀疑是不是这个 JOB 导致的,马上把 JOB 代码拉下来分析了下,JOB 做了分批处理,代码也没有发现什么问题。

虽然我们系统加了下面的 JVM 参数,但是由于容器部署的原因,这些文件在 pod 被 kill 掉之后没办法保留下来。

-XX:+HeapDumpOnOutOfMemoryError -XX:ErrorFile=/logs/oom_dump/xxx.log -XX:HeapDumpPath=/logs/oom_dump/xxx.hprof

这个现象是最近出现的,猜测是最近提交的代码导致的,于是去分析了最近提交的所有代码,很不幸的都没有发现问题。。。

在分析代码的过程中,该服务又无规律的出现了两次 OOM,只好联系运维同学优先给这个服务加了 EFS (Amazon 文件系统)等待下次出现能抓住这个问题。

刚挂载完 EFS,很幸运的就碰到了系统出现 OOM 的问题。

dump 出来的文件足有 4.8G,话不多说祭出 jvisualvm 进行分析,分析工具都被这个dump文件给搞挂了也报了个java.lang.OutOfMemoryError: Java heap space,加载成功之后就给出了导致OOM的线程。

找到了具体报错的代码行号,翻一下业务代码,竟然是一个查询数据库的count操作,这能有啥问题?

仔细看了下里面有个foreach遍历userId的操作,难道这个userId的数组非常大?

找到class按照大小排序,占用最多的是一个 byte 数组,有 1.07G,char 数组也有1.03G,byte 数组都是数字,直接查看 char 数组吧,点进去查看具体内容,果然是那条count语句,一条 SQL 1.03G 难以想象。。。

这个userId的数据完全是外部传过来的,并没有做什么操作,从监控上看,这个入参有 64M,马上联系对应系统排查为啥会传这么多用户过来查询,经过一番排查确认他们有个bug,会把所有用户都发过来查询。。。到此问题排查清楚。

解决方案

对方系统控制传入userId的数量,我们自己的系统也对userId做一个限制,问题排查过程比较困难,修改方案总是那么的简单。

别急,还有一个

看到这个问题,就想起之前我们还有一个同样类似的问题导致的故障。

也是突然收到很多告警,还有机器 down 机的告警,打开 CAT 监控看的时候,发现内存已经被打满了。

操作和上面的是一样的,拿到 dump 文件之后进行分析,不过这是一个漫长的过程,因为 down了好几台机器,最大的文件有12GB。

通过 MAT 分析 dump 文件发现有几个巨大的 String(熟悉的味道,熟悉的配方)。

接下来就是早具体的代码位置了,去查看了下日志,这台机器已经触发自我保护机制了,把代码的具体位置带了出来。

经过分析代码发现,代码中的逻辑是查询 TIDB(是有同步延迟的),发现在极端情况下会出现将用户表全部数据加载到内存中的现象。

于是找 DBA 拉取了对应时间段 TIDB 的慢查询,果然命中了。

总结

面对 OOM 问题如果代码不是有明显的问题,下面几个JVM参数相当有用,尤其是在容器化之后。

-XX:+HeapDumpOnOutOfMemoryError -XX:ErrorFile=/logs/oom_dump/xxx.log -XX:HeapDumpPath=/logs/oom_dump/xxx.hprof

另外提一个参数也很有用,正常来说如果程序出现 OOM 之后,就是有代码存在内存泄漏的风险,这个时候即使能对外提供服务,其实也是有风险的,可能造成更多的请求有问题,所以该参数非常有必要,可以让 K8S 快速的再拉起来一个实例。

-XX:+ExitOnOutOfMemoryError

另外,针对这两个非常类似的问题,对于 SQL 语句,如果监测到没有where条件的全表查询应该默认增加一个合适的limit作为限制,防止这种问题拖垮整个系统。

一次线上OOM问题分析的更多相关文章

  1. 记一次线上OOM问题分析与解决

    一.问题情况 最近用户反映系统响应越来越慢,而且不是偶发性的慢.根据后台日志,可以看到系统已经有oom现象. 根据jdk自带的jconsole工具,可以监视到系统处于堵塞时期.cup占满,活动线程数持 ...

  2. 一次线上OOM故障排查经过

    转贴:http://my.oschina.net/flashsword/blog/205266 本文是一次线上OOM故障排查的经过,内容比较基础但是真实,主要是记录一下,没有OOM排查经验的同学也可以 ...

  3. 【转】又一次线上 OOM 排查经过

    又一次线上OOM排查经过 最近线上一个服务又出现了频繁Full GC的情况,导致提供的业务经常超时.问题出现非常不稳定,经过两周的时候,终于又捕捉到了一次Full GC,于是联系运维做Heap Dum ...

  4. 火山引擎MARS-APM Plus x 飞书 |降低线上OOM,提高App性能稳定性

    通过使用火山引擎MARS-APM Plus的memory graph功能,飞书研发团队有效分析定位问题线上case多达30例,线上OOM率降低到了0.8‰,降幅达到60%.大幅提升了用户体验,为飞书的 ...

  5. 记一次log4j日志导致线上OOM问题案例

    最近一个服务突然出现 OutOfMemoryError,两台服务因为这个原因挂掉了,一直在full gc.还因为这个问题我们小组吃了一个线上故障.很是纳闷,一直运行的好好的,怎么突然就不行了呢... ...

  6. 记一次ArrayList产生的线上OOM问题

    前言:本以为(OutOfMemoryError)OOM问题会离我们很远,但在一次生产上线灰度的过程中就出现了Java.Lang.OutOfMemoryError:Java heap space异常,通 ...

  7. 记一次线上 OOM 和性能优化

    大家好,我是鸭血粉丝(大家会亲切的喊我 「阿粉」),是一位喜欢吃鸭血粉丝的程序员,回想起之前线上出现 OOM 的场景,毕竟当时是第一次遇到这么 紧脏 的大事,要好好记录下来. 1 事情回顾 在某次周五 ...

  8. 记一次 android 线上 oom 问题

    背景 公司的主打产品是一款跨平台的 App,我的部门负责为它提供底层的 sdk 用于数据传输,我负责的是 Adnroid 端的 sdk 开发. sdk 并不直接加载在 App 主进程,而是隔离在一个单 ...

  9. 【jvm】来自于线上的fullGC分析

    系统最近老年代的内存上升的比较快,三到四天会发生一波fullGC.于是开始对GC的情况做一波分析. 线上老年代2.7G,年轻带1.3G老年代上升较快,3天一波fullGC,并且fullGC会把内存回收 ...

  10. 一次线上OOM过程的排查

    https://blog.csdn.net/qq_16681169/article/details/53296137 一.出现问题 在前一段时间日常环境很不稳定,前端调用mtop接口会出网络异常或服务 ...

随机推荐

  1. Python数据类型+运算符

    Python基础数据类型 上期练习讲解 # 练习一.想办法打印出jason l1 = [11, 22, 'kevin', ['tony', 'jerry', [123, 456, 'jason'] ] ...

  2. flask博客项目之tinymce图片上传

    查看当前的博客发表情况 截图一张立马粘贴进来 点击发表,显示数据太长 不断撤退回到刚刚页面 删除大图,换成小图,上传方式 点击发表可以成功发表 数据库中查看,是把图片生成这种编码后字符串方式存储的了, ...

  3. json提取器和beanshell处理器组合,将提取的所有id以数组返回

    1.添加json提取器 2.添加beanshell处理器,并编写脚本 String str1 = vars.get("buildid_ALL"); log.info(str1); ...

  4. Jmeter 之 If 逻辑控制器

    在Jmeter 中如要在某种场景中才执行特殊请求,此时可用If 逻辑控制器来实现. If 逻辑控制器顾名思义当符合某个条件时则执行,添加路径:测试计划->线程组->逻辑控制器->if ...

  5. vue移动端封装底部导航

    <template> <div class="myfooter flex-betweenCenter"> <router-link tag=" ...

  6. 8、IDEA提交代码出现: Fetch failed fatal: Could not read from remote repository

    转载自 第一步.确认Git公钥/密钥是否生成: 1. 首先查看本地是否生成git密钥,一般在C盘home目录下:[C:你自己的home目录\.ssh] 第二步:添加Git密钥: 右键->Git ...

  7. 什么是Rabbitmq消息队列? (安装Rabbitmq,通过Rabbitmq实现RPC全面了解,从入门到精通)

    目录 Rabbitmq 一: 消息队列介绍 1.介绍 2.MQ解决了什么问题 1.应用的解耦 2.流量削峰 3.消息分发(发布订阅: 观察者模式) 4.异步消息(celery就是对消息队列的封装) 3 ...

  8. ssm——mybatis整理

    目录 1.mybatis框架概述 2.直接使用jdbc连接数据库带来的问题 3.mybatis连接池 3.1.mybatis连接池yml配置 3.2.mybatis连接池xml配置 4.一个简单的my ...

  9. python之路27 单例模式实现方式、pickle模块、选课系统目录搭建

    单例模式实现的多种方式 单例1:(提前定义一个名字) class C1: __instance = None def __init__(self,name,age): self.name = name ...

  10. P7076 [CSP-S2020] 动物园

    题面 动物园里饲养了很多动物,饲养员小 A 会根据饲养动物的情况,按照<饲养指南>购买不同种类的饲料,并将购买清单发给采购员小 B. 具体而言,动物世界里存在 \(2^k\) 种不同的动物 ...