15_日处理上亿数据系统案例
1450字约5分钟
2024-08-10
1、日处理上亿数据的计算系统
为了集中注意力理解这个系统 JVM
相关的东西,简化说明这个系统
系统会不停的从 MySQL
数据库以及其他数据源提取大量数据,加载到 JVM
内存中进行计算,大概每分中需要执行 500
次数据提取和计算任务
这是一套分布式运行的系统,部署了多台机器,每台机器每分中负责执行 100
次数据提取和计算任务
每次提取大概 1
万左右数据到内存中计算,平均每次大概需要耗费 10
秒钟左右的时间
每台机器配置是 4核8G
,JVM
内存配置了 4G
,新生代和老年代分别是 1.5G
内存
2、这个系统新生代多久塞满?
每台机器上部署的实例,每分中执行 100
次数据计算任务,每次计算 1
万条数据需要 10
秒时间,那我们可以看一看每次 1
万条数据大概占用多少内存
可以认为每条数据大小平均在 1KB
左右,那么每次计算任务的 1
万条数据就对应了 10MB
大小
如果新生代按照 8:1:1
的比例来分配 Eden
区和 Survivor
区,那么 Eden
区就是 1.2GB
,每块 Survivor
在 150MB
的样子,如下图
按照上面分析的内存来计算,每次执行一个计算任务,就会在 Eden
区分配 10MB
左右的对象,那么一分钟大概对应 100
次计算任务
基本上一分钟过后,Eden
区里就全是对象,基本了满了
3、触发 Young GC 时会有多少对象进入老年代
1、假设
1
分钟过后新生代塞满了对象,进行Young GC
2、进行
Young GC
之前,判断老年代可用内存空间是否大于新生代全部对象3、此时老年代是空的,大概有
1.5GB
的可用内存空间,新生代就算他有1.2GB
的对象也是可以放下的,直接进行Young GC
4、每分钟执行
100
个计算任务,假设80
个计算任务都执行完毕,那么剩余20
个计算任务,也就是200MB
对象是存活的,不能给垃圾回收掉5、
200MB
是大于Survivor
区的150MB
的,存活对象无法放入Survivor
区,所以这200MB
对象直接进入老年代
4、系统运行多久后老年代被填满
1、按照上述计算,每分钟就是一个轮回,大概每分钟就会把新生代
Eden
区填满,触发一次Young GC
,然后大概200MB
左右数据进入老年代2、第
3
分钟运行后进行Young GC
,此时老年代有400MB
内存占用,只有1.1 GB
内存可用,如果-XX:-HandlePromotionFailure
参数打开了(一般都会打开),就会判断老年代空间是否大于历次Young GC
后进入老年代对象的平均大小3、历次
Young GC
进入老年代的对象平均200MB
,老年代1.1GB
内存是大于的,此时可以放心的执行一次Young GC
4、转折点是大概运行了
7
分钟过后,7
次的Young GC
执行已经让大概1.4G
的对象进入老年代了,老年代剩余空间100MB
的样子
5、这个系统多久触发一次 Full GC
接着上面分析,大概在第 8
分钟运行结束的时候,新生代又满了,执行 Young GC
之前检查,发现老年代只有 100MB
内存可用了,比之前每次 Young GC
后进入老年代的 200MB
对象要小,此时会触发一次 Full GC
假设老年代被占据的 1.4G
内存空间的对象都是可以回收的,那么此时一次性就会把这些对象给回收掉,接着继续执行 Young GC
,200MB
对象再次进入老年代
按照这个运行流程,基本上平均七八分钟触发一次 Full GC
,这个频率相当高了,每次 Full GC
速度都很慢的,严重影响系统性能
6、JVM 优化
按照前面分析的内容,最大的问题是每次 Young GC
,Survivor
区放不下存活对象
我们可以调整新生代的内存比例,3GB
左右的堆内存,可以分配 2GB
给新生代,1GB
留给老年代
这样 Survivor
区大概就是 200MB
,差不多刚好可以放下 Young GC
过后存活对象了
还需要注意一点的就是,动态年龄判断提前进入老年代的规则,如果 Survivor
区中一批对象总大小超过了 Survivor
区内存的一半,就直接进入老年代了
所以这里的优化仅仅是做一个示例说明,意思是要增加 Survivor
区的大小,让 Young GC
后的对象进入 Survivor
区中,避免进入老年代
实际上为了避免动态年龄判定规则把 Survivor
区中的对象直接放到老年代,如果这里新生代内存有限,我们可以调整 -XX:SurvivorRatio=8
这个参数
Eden
区默认比例是 80%
,可以降低 Eden
区的比例,给两块 Survivor
区更多的内存空间,让每次 Young GC
后的对象进入 Survivor
区中,还可以避免动态年龄判断规则直接让对象进入老年代