一.背景
线上项目运行时间比之前增加了10倍
二.分析
通过sparkHistory 观察到个别task执行较慢引起的,怀疑以下原因
1.数据倾斜,通过观察input size排除
2.上游数据问题,经沟通排除
3.磁盘问题,检查后排除
4.反序列化问题(项目正常运行了很久了都没问题,日志也没有错误)
三.原因
val visitRDD: RDD[String] = sc.sequenceFile(input, classOf[BytesWritable], classOf[BytesWritable])
.map(x =>new String(x._2.getBytes()))
其实这种方式一直有问题,只是反序列化慢的不明显,而且反序列化错误的字段我们没用使用,所以开始的时候没发现
当把byte[]数据保存为BytesWritable后,通过BytesWritable.getBytes()再获取到的数据不一定是原数据,
可能变长了很多(偶尔变长),因为BytesWritable采用自动内存增长算法,当你数据长度为size时,它可能将数据加载
到了长度为capacity>size的buffer中。所以通过BytesWritable.getBytes()得到的数据最后一些字符是多余的。
四.解决方案
去掉多余的字符
1.
val visitRDD: RDD[String] = sc.sequenceFile(input, classOf[BytesWritable], classOf[BytesWritable])
.map(x =>new String(x._2.getBytes(),0,x._2.getLength))
2.
val visitRDD: RDD[String] = sc.sequenceFile(inputPath, classOf[BytesWritable], classOf[BytesWritable]).map(x =>{
val value = x._2
value.setCapacity(value.getLength)
new String(value.getBytes)
})