Spark程序结构:类中的广播变量vs最终静态与外部静态属性

时间:2016-06-06 14:59:07

标签: java apache-spark architecture spark-streaming

我有一个应用程序应该从文件中读取一些行,并将它们作为最终变量,用作参考。
截至目前,在spark上下文开始之前,我在类(称为People)类中启动静态方法

reads the file;
fill a final static HashTable;
static{ hashTable.put(eachline);}

在我的转换代码中,例如:

JavaRDD<String> filteredRDD = anotherRDD.filter( new Function<String,Boolean>(){
    public Boolean call(String s){
        People.hashTable.containsKey(s);
    }
});

怀疑:

  1. 我应该在SparkConf sparkConf = new SparkConf().setAppName("JavaKafkaStream").setMaster("local[2]");声明之后立即使用广播变量吗?
  2. 为什么我要在最后一个选择广播变量?据我所知,决赛在转型流程中顺利通过。
  3. 在SparkStreaming计算开始之前加载某个文件内容是正确/优雅的过程吗?
  4. 如果我有外部类来处理一些计算(主要是为了可读性),我是否愿意以静态方式访问这些方法或在rdd.foreachPartition(....中实例化classe?

1 个答案:

答案 0 :(得分:8)

1)我们应该使用广播变量吗?

YES

2)广播变量与静态初始化变量

不要使用静态变量来传递序列化数据。

一般情况下,当我们将作业扩展到群集中的多台计算机时,数据的静态变量将无法与Spark 一起使用(看起来它不起作用,b / c Spark正在local(2)模式下运行。

静态字段是对象初始化的一部分,不是序列化表单的一部分,因为它们可以/应该在远程处理操作中在接收端重建。请注意,如果对象足够智能以在反序列化时重建其内容,可以工作。

相反,我们可以使用可以序列化的普通实例。 (如mydata = new HashMap<>(); mydata.put(...)

2.1)实例变量与广播变量

假设我们有一个大型数据集,有420个分区和8个执行器节点的集群。在像以下的操作中:

val referenceData = Map(...)
val filtered = rdd.filter(elem => referenceData.get(elem) > 10)

referenceData对象将被序列化420次,或执行转换所需的任务数量。

相反,广播变量:

val referenceDataBC = sparkContext.broadcast(Map(...))
val filtered = rdd.filter(elem => referenceDataBC.value.get(elem) > 10)

将被发送一次给每个遗嘱执行人,或总共8次。因此,通过减少序列化开销来节省大量网络和CPU。

3)在SparkStreaming计算开始之前加载某个文件内容是正确/优雅的过程吗?

我们需要在流式处理开始之前加载外部数据。我们还有其他选择吗?

4)以静态方式使用函数或在rdd.foreachPartition(....)中实例化类

取决于函数是否需要类提供的上下文。 例如需要背景:

rdd.foreachPartition{ iter =>
    val jsonParser = new JsonParser(validation)
    val parsed = iter.map(jsonParser.parse)
    ...
}

e.g。不需要上下文

vectors.foreachPartition{ iter =>
    val magnitudes = iter.map(elem => MyVectorMath.modulus(elem))
}