我写了一份火花工作。如下所示:
public class TestClass {
public static void main(String[] args){
String masterIp = args[0];
String appName = args[1];
String inputFile = args[2];
String output = args[3];
SparkConf conf = new SparkConf().setMaster(masterIp).setAppName(appName);
JavaSparkContext sparkContext = new JavaSparkContext(conf);
JavaRDD<String> rdd = sparkContext.textFile(inputFile);
Integer[] keyColumns = new Integer[] {0,1,2};
Broadcast<Integer[]> broadcastJob = sparkContext.broadcast(keyColumns);
Function<Integer,Long> createCombiner = v1 -> Long.valueOf(v1);
Function2<Long, Integer, Long> mergeValue = (v1,v2) -> v1+v2;
Function2<Long, Long, Long> mergeCombiners = (v1,v2) -> v1+v2;
JavaPairRDD<String, Long> pairRDD = rdd.mapToPair(new PairFunction<String, String, Integer>() {
private static final long serialVersionUID = -6293440291696487370L;
@Override
public Tuple2<String, Integer> call(String t) throws Exception {
String[] record = t.split(",");
Integer[] keyColumns = broadcastJob.value();
StringBuilder key = new StringBuilder();
for (int index = 0; index < keyColumns.length; index++) {
key.append(record[keyColumns[index]]);
}
key.append("|id=1");
Integer value = new Integer(record[4]);
return new Tuple2<String, Integer>(key.toString(),value);
}}).combineByKey(createCombiner, mergeValue, mergeCombiners).reduceByKey((v1,v2) -> v1+v2);
pairRDD.saveAsTextFile(output);
}
}
程序计算每个键的值的总和。 根据我的理解,本地组合器应该在每个节点上运行,并为相同的键和值相加 然后在少量数据的情况下进行混洗。 但是在SparkUI上它显示了大量的随机读取和随机写入(几乎58GB)。 我做错了吗? 如何知道本地组合器是否正常工作?
群集详细信息: -
20个节点群
每个节点有80GB HardDisk,8GB RAM,4个核心
Hadoop的2.7.2
Spark-2.0.2(prebuild-with-Hadoop-2.7.x发行版)
输入文件详细信息: -
输入文件存储在hdfs上
输入文件大小:400GB
记录数:16,129,999,990
记录列:String(2 char),int,int,String(2 char),int,int,String(2 char),String(2 char),String(2 char)
注意: 最大不同键数是1081600 在spark日志中,我看到使用localitylevel NODE_LOCAL运行的任务。
答案 0 :(得分:0)
让我们解决这个问题并看看会得到什么。为了简化计算,我们假设:
使用这些值,数据将被分配到~3200个分区(在您的情况下为3125)。这为每个拆分提供了大约51200条记录。此外,如果每个键的值的分布是均匀的,则每个键平均应该有大约160个记录。
如果数据是随机分布的(例如,它没有按键排序),您可以预期每个分区的每个密钥的平均记录数将接近1 *。这基本上是最糟糕的情况,即地图侧组合根本不会减少数据量。
此外,您必须记住,平面文件的大小通常会显着低于序列化对象的大小。
对于现实生活中的数据,您通常可以预期从数据收集过程中出现某种类型的订单,因此事情应该比我们上面计算的更好,但最重要的是,如果数据尚未按分区分组,则地图侧合并可能完全没有改进。
您可以通过使用更大的分割来减少混洗数据的数量(256MB会使每个分区的分数超过100K),但这需要更长的GC暂停和可能的其他GC问题。
*您可以通过更换样品来模拟这个:
import pandas as pd
import numpy as np
(pd
.DataFrame({"x": np.random.choice(np.arange(3200), size=160, replace=True)})
.groupby("x")
.x.count()
.mean())
或者只考虑将160个球随机分配到3200个桶的问题。