近期接业务线反馈,在线运行的Spark Streaming流任务有gc告警,如果不处理任务就会挂掉,且之前也经常出现隔一段时间任务就失败退出的情况,需要综合排查。
业务背景
- 业务代码本身是没有致命逻辑错误的,程序可以正常的启动和运行较长一段时间,如一周两周;
- 流计算任务,从kafka读取数据计算后写;
- 没有使用第三方缓存承接中间数据;
- 业务数据量大小中等,没有显著流量洪峰
技术背景
- Spark版本2.3
- HBase版本2.0
- Kafka版本1.1
- 没有采用第三方缓存,如
Redis
来承接中间数据 - 每个executor分配了60GB内存,20个cpu核心,一共有6个executor
- 垃圾回收使用G1GC
- 环境开启了Kerberos
排查与优化
日志分析
先前已建议开启
debug
级别日志,这也导致运行一段时间的日志量能达到50GB之多,正常运行时应调到info
级别合适。
一般来说,性能问题在日志中的表现十分隐蔽难寻,或者干脆没有特定表征,除非累计之后引起了程序错误(ERROR),抛了异常。
GC细节
开启Spark的GC详情日志,在spark-env.sh
文件中的SPARK_JAVA_OPTS
参数上追加-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
,或者在spark-submit
的任务提交命令上使用--conf spark.executor.extraJavaOptions
来追加上述参数,随后在spark运行后的worker端日志中可以看到GC发生时打印的信息。
当给spark任务分配的内存不足时,会频繁发生minor gc(年轻代gc),如果存活时间长的对象特别多,就会发生full gc(老年代gc)。
当频繁的new对象时,导致很快进入老年代,这样也可能发生full gc。
GC选择上建议CMS,在JDK1.8之后的,也可以尝试G1GC,具体以在自己生产环境的效果对比为准。
资源侧调参
-
资源上,当前任务每个
executor
的核心数是20个,每个线程内存偏小,建议增加内存或降低核心数(因为该业务的计算量不大,cpu核不需要太多,这里给了20核已经足够多了)。 -
单个
executor
分配的内存超过了32GB,建议用户指定--conf spark.executor.extraJavaOptions
="-XX:+UseNUMA -XX:+UseCompressedOops"来开启压缩指针。但据查,jvm的属性
-XX:+UseCompressedOops
在JDK 1.6和之后的版本都默认开启了,目前大部分使用jdk1.8或更新版本,所以上述操作可忽略。 -
如果可能的情况下,将executor的数量增大一倍,分配的内存减半(核数也减半),在流计算任务里往往受Kafka分区数的限制无法自由调整executor数量。
-
可选地,禁用JVM内存swap,可以添加启动参数
-XX:+AlwaysPreTouch
,执行sysctl -w vm.swappiness=0
禁用swap -
为了降低GC时间长造成进程挂掉,可以加大executor的心跳超时时间,
spark.executor.heartbeatInterval
默认值10秒,可以调整到60秒(酌情)。
程序侧建议
- 设置较大的批处理的时间间隔。在业务允许的情况下,
batchDuration
大一些可以减少一些上下文创建销毁的消耗,降低任务挤压的可能性。 - 增大机器级别的分散度,也就是上面提到了资源一定的情况下,分多个executor使其分散到多台机器上去执行的效果更好。
- 非常重要!缓存多次使用的数据,尤其是参与Join计算的维度表数据,往往是从RDBMS等远程读取而来的,缓存起来能节省大量的时间。
- 强烈建议Streaming程序使用第三方的缓存库,如Redis来存储中间数据,否则日积月累下来可用内存会消耗殆尽。
- 使用可序列化的持久化策略(比如
MEMORY_ONLY_SER
或MEMORY_DISK_SER
),使对象占用内存空间更小。 - Spark默认的是使用Java内置的系列化类,可以使用
Kryo
序列化类库,进行序列化,因为kryo
序列化方法可以进一步的降低RDD的partition的内存占用量。 - 还有一种表现是一个应用越跑越慢,可能的原因是在driver端存储了一个resultRDD,并在每批计算时更新,此时建议采用
checkpoint
来解决。 - 流任务的并发度可增大,当executor的数量超过kafka分区数的时候有用,多余的executor可以承担一些Task。
参考链接
- spark调优-GC - DavidZuo 提供了一些编码层面序列化的建议;
- Configuration - Spark 3.3.0 Documentation列出了spark环境变量相关参数
- Spark Streaming 流计算优化记录GC优化与shuffle service介绍了使用CMS回收器的实践