没有碰到过 GC 问题的人生对写 Java 的人来说是不完整的。大数据生态圈的框架大都以 JVM 系语言开发(Java Scala 为主),毕竟生态成熟嘛要啥有啥。
HDFS 作为大数据领域的默认分布式文件系统,其运作方式导致了非常容易碰到 GC 问题:
大量的元数据需要保存在内存中,使得很容易就需要几十 G 甚至 100 多 G 的堆
大量且高并发的文件读写操作使得频繁地产生新对象
下面就举两个例子,简单分享下我们做的一些调优。
案例一
有业务同事反馈任务跑的慢,虽然后来确认是其他原因导致的,但在分析过程中,我们从监控观察到 RPC 排队时间和处理时间不是很稳定,有时会出现几秒甚至10多秒的的毛刺,进而注意到 GC。
一分钟一个点,大概每分钟有 2、3秒花在 GC 上。我们用的是经典的 ParNew + CMS 的组合,查看 GC 日志发现大部分都是新生代的 GC,也就意味着有 3% - 5%的时间是 STW 的。这个比例看着不大,但在 NameNode 每秒几 K 甚至几十 K 的事务的压力下,绝对数值和对具体业务的影响还是不能忽视的。
知道了原因,调整就很简单了。从 NameNode 的工作原理分析,大量文件的读写确实会创建很多临时对象,调大新生代就是很自然也很正确的办法。一方面,更大的新生代能减少 minor gc 的次数;另一方面,更多临时对象在