1. 案例分析
有个同学负责的搜索服务经常半夜full gc,经过分析后,定位到具体原因,今天就分享出来
2. 系统介绍
类似今日头条app的搜索引擎。
这种搜索场景,在互联网公司非常普遍存在。
用户先输入关键字,
第一个搜索结果是综合,综合的意思就是所有的意思,包括了视频 咨询 百科等等。
第二个是视频,就是子搜索项
那么,讲到这里,就把简单的业务场景描述了一遍。
即互联网非常常见的搜索场景
3. 数据同步
那这个搜索场景和我们的jvm,有什么关系呢?
和jvm相关的,就是搜索ES index索引库初始化的问题。
用户在搜索之前,要先有数据把。
也就是说,如何把业务数据同步到搜索里面?
业务数据同步到搜索,一般有2种场景:
- 增量同步
- 全量同步
增量同步
全量同步
好,介绍了这么多,终于进入我们的jvm了
jvm的异常,就出现在全量同步的代码上。4. jvm的设置现状
目前的搜索系统,设置了JVM为设置4G
按照默认比例young : old = 1 : 2, eden : s0 : s1 = 8 : 1 : 1
故如下图:5. 这套系统的处理逻辑
采用定时器,夜里1点钟
由搜索服务,连接业务的mysql从库,每次读取2万条数据,
然后把2万条数据写入到es的index库中。
图s03
假设每条业务数据,约10个字段,平均每个字段100字节,大约1KB的数据
每条线程从数据库读取2万条,约20MB,每次花费2秒钟
使用了10条线程并行处理,
10条线程 = 10 20万条,约10 20MB = 200MB,
即, 2秒,处理20万条,200MB
每秒处理数量= 20万/2秒 = 10万条
10亿条耗费的时间 = 10亿 / 10万 = 10000秒 / 60秒 / 60分钟 = 2.7小时
即2.7小时,把10亿条数据同步到ES索引库中
故,理论上夜里1点钟执行,到4点钟就执行完了6. eden区多久被塞满
eden区总共1.1g
10条线程并发,2秒中产生200M对象数据
故,10秒钟,填满1.1g eden区7. 每次ygc 有多少对象还存活?
对象的存活,要先被栈帧引用,而栈帧存储在线程栈中。
我们开了10条线程在并行,就有10个栈帧时刻运行着。
也就是说,每时每刻有10条线程运行,约有200mb的数据被线程栈帧引用。
所以,每10秒触发1此ygc时,就有200mb的数据存活。8. 如何处理存活的200MB数据?
每次ygc后,200mb通过复制算法,复制给survivor区
但是survivor被分割成from区和to区各占100MB
from 100m 放不下200m,只能先把s_from的50m-100m(动态年龄50%)塞满后,剩下的100m-150m复制old区
9. old区多久被填满?
old区有2.7G
每10秒触发一次ygc,就有100m进old区。
我们来模拟这种动作:
第1次10秒,触发ygc,把eden的存活200M,其中100m复制进s_from,100m进old,最后清空eden
第2次10秒,触发ygc,把eden + s_from的存活200M,其中100m复制进s_to,100m进old,最后清空eden和s_from,并且from和to互换。
这里有2个问题?可能有的同学会问
- s_from第一次不是100m存活吗?怎么eden + s_from的存活才200M,不是300M吗
因为第一次的s_fromM经过10秒后,老早就没引用了,变为垃圾对象了,所以eden+s_from其实只有eden 200M存活
……
就这样经过了,2.7G / 100M = 27次ygc后,old区满了
27 * 10秒 = 270秒 / 60 = 4.5分钟
即,每4.5分钟后,触发full gc,这个速度还是比较高的,频繁的full gc会导致系统卡顿,影响性能。
10. jvm的性能分析
上文讲了这么多,我们要来优化jvm了,那该如何优化呢?
先明确一点,该案例有哪些问题?
该案例最大的问题就是经常full gc,导致系统卡顿。
那为什么会full gc呢
是因为每次ygc都有100mb,没地方放,导致进了old区!然后old区过了4.5分钟后触发full gc。
那现在要解决的问题就是100mb没地方放的问题,不要让他们进入old区。
那怎么解决呢?
把survivor_from 和 to区加到大于200M即可。
我们就把survivor设置为250MB吧
一:把堆再加1g,变成5g -Xms=5g -Xmx=5g
二:把年轻代设置为2g,-Xmn=2G
三:把survivor from to设置为256mb
-XX:SurvivorRatio=6;设置年轻代中Eden区和Survivor区的大小比值。
设置为6,则两个survivor区与一个Eden区的比值为2:6,一个survivor区占整个年轻代的1/8
2g的8分之一,就是256