您当前的位置:首页 > 电脑百科 > 数据库 > 百科

亿级流量的数据清洗系统OOM排查实战

时间:2022-02-03 11:54:07  来源:  作者:JavaEdge

每天亿级数据量的日志清洗系统,从Kafka不停消费各种日志数据,然后对日志格式进行各种清洗,如对敏感信息字段(姓名、手机号、身份证号)进行脱敏,再把清洗后数据给其它系统,如推荐系统、广告系统、分析系统都会去使用这些清洗好的数据。

OOM 现场

某天我们也是突然收到线上的报警,发现日志清洗系统发生OOM。第一时间登录到线上机器,查看日志,经典日志

 JAVA.lang.OutOfMemoryError: java heap space

内存溢出。套路应该很熟了。

先看异常日志,定位啥导致的问题,日志里看到了:

 java.lang.OutOfMemoryError: java heap space xx.xx.xx.log.clean.XXClass.process() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.process() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.process() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.xx()

似乎同样的一个方法(XXClass.process())反复出现,最终导致堆内存溢出。

再仔细分析日志,代码出现大量递归操作,正是这大量递归,导致堆内存溢出。接着自然就是MAT分析内存快照。

初步分析内存快照

虽然日志能看到哪个方法导致内存溢出,但不知道到底哪个方法调用创建的大量对象。因此还得用MAT分析。

因大量XXClass.process()递归执行,每个XXClass.process()中都创建了大量char数组,最后因XXClass.process()又多次递归调用,也就导致大量的char[]数组耗尽内存:

亿级流量的数据清洗系统OOM排查实战

 

JVM参数问题?

基本定位出问题了,但先别急直接去代码检查问题,因为发现了比较大问题。

虽然XXClass.process()递归调用多次,但实际上我们在MAT中发现递归调用的次数也不多,最多几十次。所有递归调用加起来创建的char[]数组对象总和其实也最多1G。

可能这次OOM发生不一定是代码写的烂,可能就是JVM 内存参数不对,给堆内存分配太少。

分析GC日志

要知道堆内存是不是设小了,就得分析JVM运行时的内存使用模型。

现在宕机了,唯一能看到的,就是当时在JVM启动参数中加入的自动记录的GC日志。

从GC日志中,可见JVM启动时的完整参数设置:

 -Xmx1024m
 -Xms1024m
 -XX:+PrintGCDetails
 -XX:+PrintGC()
 -XX:+HeapDumpOnOutOfMemoryError
 -Xloggc:/opt/logs/gc.log 
 -XX:HeapDumpPath=/opt/logs/dump

这里主要是把gc日志详细记录在了一个日志文件,另外指定OOM时要导出内存快照,堆内存1G,但这台机器可是4核8G!

记录下来的gc.log日志:

 [Full GC (Allocation Failure) 866M->654M(1024M)]
 [Full GC (Allocation Failure) 843M->633M(1024M)] 
 [Full GC (Allocation Failure) 855M->621M(1024M)] 
 [Full GC (Allocation Failure) 878M->612M(1024M)]

因Allocation Failure触发的Full GC很多,即堆内存无法创建新对象,然后触发GC,结果触发时肯定先触发Full GC了。发现每次Full GC都只回收一点点对象,堆内存几乎都占满的。

日志显示的是每s都会执行一次Full GC,这就绝了。应该是在系统运行时,因为XXClass.process()不停递归创建大量char[]数组,导致堆内存几乎满。

然后导致连续一段时间,每s触发一次Full GC,因为内存都满了,特别是Old可能几乎都满了,所以可能每s执行YGC前,发现Old可用空间不足,就会提前触发Full GC。

亿级流量的数据清洗系统OOM排查实战

 

也可能YGC后,存活对象太多无法放入Survivor,而都要进入Old,也放不下了,只能Full GC。但每次full gc只能回收少量对象,直到最后可能某次full gc回收不掉任何对象了,然后新的对象无法放入堆内存了,就触发OOM了:

亿级流量的数据清洗系统OOM排查实战

 

明显就是堆内存偏小了,导致频繁full gc。

分析一下JVM运行时内存使用模型

接着jstat分析当时JVM运行时的内存模型,当时重启系统,每s打印一次:

 S0 S1 E O YGC FGC
 
 0 100 57 69 36 0
 
 0 100 57 69 36 0
 
 0 100 65 69 37 0
 
 0 100 0 99 37 0
 
 0 100 0 87 37 1

我就给出部分信息大家就可以看出来问题所在了,刚开始都是Eden在涨,接着YGC从36到37,发生了一次YGC,Old直接从69%到99%。

why?

YGC后存活对象太多,Survivor放不下,直接进了Old!接着Old都占99%了,直接触发一次Full GC,但也仅让Old从99%到87%,只回收少量对象。

该过程反复循环了几次,年轻代对象反复进入老年代,不停触发Full GC,但是还回收不了多少对象,几次循环过后,老年代满了,可能Full GC没回收多少对象,新的对象一大批放不下了,就触发OOM了。

优化第一步:加大堆内存

所以这OOM,不能一口说是代码问题,从JVM运行情况及内存大小来看,其实是内存分配不足问题。

第一步,直接在4核8G的机器上,加大堆内存,直接给堆5G

接着运行系统,jstat发现,每次YGC过后存活对象都落入Survivor区域了,不会随便进入老年代,而且因为堆内存很大,基本上运行一段时间不会发生OOM问题了。

优化第二步:改写代码

让他不要占用过多内存。代码之所以递归,是因为在一条日志中,可能出现很多用户的信息,一条日志也许会合并包含了十几个到几十个用户的信息。

这时代码中就是会递归处理日志,每次递归都会产生大量char[]数组,是切割了日志用来处理的。

这代码写的完全没必要,因为对每一条日志,若发现包含多个用户的信息,就对这一条日志切割出来进行处理,没必要递归调用,每次调用都切割一次日志,生成大量char[]数组。

该步代码优化后,线上系统的内存使用情况降低10倍以上。

总结

先通过OOM的排查方法去分析,发现主要是内存太小导致的问题然后用gc日志和jstat分析,明显发现是内存不够用了,最后加大系统内存,并优化代码即可。



Tags:数据清洗   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
每天亿级数据量的日志清洗系统,从Kafka不停消费各种日志数据,然后对日志格式进行各种清洗,如对敏感信息字段(姓名、手机号、身份证号)进行脱敏,再把清洗后数据给其它系统,如推荐系...【详细内容】
2022-02-03  Tags: 数据清洗  点击:(10)  评论:(0)  加入收藏
随着大数据时代的发展,越来越多的人开始投身于大数据分析行业。当我们进行大数据分析时,我们经常听到熟悉的行业词,如数据分析、数据挖掘、数据可视化等。然而,虽然一个行业词的...【详细内容】
2021-10-20  Tags: 数据清洗  点击:(97)  评论:(0)  加入收藏
获取数据后,对数据的清洗工作必不可少,常用的数据清洗方法主要有缺失值填充、数值替换、数据类型转换、数据分列、重复值处理等,清洗的数据结果直接影响最后数据分析的结果,一个...【详细内容】
2021-05-12  Tags: 数据清洗  点击:(202)  评论:(0)  加入收藏
日常工作中,分析师会接到一些专项分析的需求,首先会搜索脑中的分析体系,根据业务需求构建相应的分析模型(不只是机器学习模型),根据模型填充相应维度表,这些维度特征表能够被使用的...【详细内容】
2020-10-28  Tags: 数据清洗  点击:(146)  评论:(0)  加入收藏
▌简易百科推荐
作者:Python进阶者来源:Python爬虫与数据挖掘一、思路很多网站都对requests反爬了,这种时候,一般有两个选择,要不就找js接口,要不就用requests_html等其他工具,这里他使用了后者req...【详细内容】
2022-02-08  CDA数据分析师    Tags:requests   点击:(6)  评论:(0)  加入收藏
一、摘要本文主要以 Mysql 数据库为基础,对常用 SQL 语句进行一次深度总结,由于篇幅较长,难免会有些遗漏的地方,欢迎网友批评指出!具体内容主要有以下几个部分: 库操作 表操作 数...【详细内容】
2022-02-05  DNF搬砖摸金达人    Tags:SQL语句   点击:(13)  评论:(0)  加入收藏
每天亿级数据量的日志清洗系统,从Kafka不停消费各种日志数据,然后对日志格式进行各种清洗,如对敏感信息字段(姓名、手机号、身份证号)进行脱敏,再把清洗后数据给其它系统,如推荐系...【详细内容】
2022-02-03  JavaEdge    Tags:数据清洗   点击:(10)  评论:(0)  加入收藏
1. 请简洁描述 MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?SQL 标准定义的四个隔离级别为:read uncommited :读到未提交数据read committed:脏读,不可重复读...【详细内容】
2022-01-27  源鲲    Tags:数据库   点击:(19)  评论:(0)  加入收藏
基本上明白了这个小伙伴的意思,于是我自己也写了个测试案例,重新整理了今天这篇文章,希望和小伙伴们一起探讨这个问题,也欢迎小伙伴们提出更好的方案。1. 思路分析批量插入这个...【详细内容】
2022-01-24  Java技术那些事    Tags:数据   点击:(16)  评论:(0)  加入收藏
ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。来自于2011 年在纳斯达克上市的俄罗斯本土搜索引擎企业Yandex公司,诞生之初就是为了服务Yandex公司自家的W...【详细内容】
2022-01-18  软件架构    Tags:IDEA   点击:(14)  评论:(0)  加入收藏
1.ExecutorExecutor 是 MyBatis 的核心接口之一,其中定义了数据库操作的基本方法。在实际应用中经常涉及的 SqISession 接口的功能,都是基于 Executor 接口实现的。 BaseExec...【详细内容】
2022-01-13  java成神之路    Tags:MyBatis   点击:(20)  评论:(0)  加入收藏
一个挺着啤酒肚,身穿格子衫,发际线严重后移的中年男子,手拿着保温杯,胳膊夹着MacBook向你走来,看样子是架构师级别。面试开始,直入正题。面试官:小伙子,看到你的简历上面写了项目中...【详细内容】
2022-01-12  一灯架构    Tags:分库分表   点击:(39)  评论:(0)  加入收藏
TeamDesigner,一款免费在线的数据库表设计工具,适合后端程序员。类似PownerDesigner的功能,可用于设计mysql,oracle的表结构。地址:http://101.200.59.11/主要功能1、支持Mysql,Or...【详细内容】
2022-01-11  互联网前行者90    Tags:数据库   点击:(39)  评论:(0)  加入收藏
前言上篇文章简单介绍canal概念,本文结合常见的缓存业务去讲解canal使用。在实际开发过程中,通常都会把数据往redis缓存中保存一份,做下简单的查询优化。如果这时候数据库数据...【详细内容】
2022-01-04  仰望四十五度的光    Tags:数据同步   点击:(38)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条