(一)过大的结果集导致Driver端OOM错误
很早之前🔗《从零开始学习大数据平台》就提到了这个问题。
通过collect()
返回结果集,数据量太大就会报driver端内存错误。
比如我这里,返回千万数据,就导致Out of memory,或者GC overhead limit exceeded。
Spark的核心弹性分布式数据集,对于rdd.collect()
是这么描述的:
java.util.List collect() //Python版本差不多的
返回一个数组包含RDD中所有的元素
.
备注
.
这个方法只能在结果集较小的情况下使用,因为所有的数据都会加载到driver的内存中。
(二)各种解决方案
如果结果集大怎能办?
网上查了一圈,大家的说法有:
- 大的数据集用rdd写入HDFS文件的方法,比如
rdd.saveAsTextFile
,rdd.saveAsNewAPIHadoopFile
各个节点将结果写入到HDFS的目录中(一大堆文件)。 - 不传到driver上而是
rdd.foreach
,rdd.foreachPartition
打印到屏幕上。 - 通过可序列化的类型,发送到数据库等等。
(三)分批返回结果集
不过我比较懒,希望整个流程和以前无缝切换,
所以我采用了collectPartitions
,分批返回数据。
Java代码如下:
...
if (ColBatch < out_2.getNumPartitions()) {//如果设置了批量值,并小于分区数,则分批collect
int[] Par = new int[ColBatch];
for (int i = 0; i < out_2.getNumPartitions(); i += Par.length) {
int ParLen = 0;
for (int j = 0; j < Par.length; j++) {
if (i + j < out_2.getNumPartitions()) {
Par[j] = i + j;
ParLen++;
}
}
TmpLine = String.format("当前: %d - %d\n", i, i + ParLen - 1);
System.out.print(TmpLine);
List<Tuple2<String, String>>[] output2 = out_2.collectPartitions(Par);
for (int j = 0; j < ParLen; j++) {
for (Tuple2<String, String> tuple : output2[j]) {
oF002.write(String.format("%s|%s\n", tuple._1(), tuple._2()));
g002++;
}
}
}
} else {
List<Tuple2<String, String>> output1 = out_2.collect();
for (Tuple2<String, String> tuple : output1) {
oF002.write(String.format("%s|%s\n", tuple._1(), tuple._2()));
g002++;
}
}
...
PS:但Python中没有找到collectPartitions
方法啊???肿么办!!! 💔 😫。