在Spark中,如何知道哪些对象在驱动程序上实例化,哪些在executor上实例化,因此如何确定哪些类需要实现Serializable?
答案 0 :(得分:36)
序列化对象意味着将其状态转换为字节流,以便可以将字节流还原为对象的副本。如果Java对象的类或其任何超类实现了java.io.Serializable接口或其子接口java.io.Externalizable,则该对象是可序列化的。
类永远不会序列化,只有类的对象被序列化。如果需要通过网络持久化或传输对象,则需要对象序列化。
Class Component Serialization
instance variable yes
Static instance variable no
methods no
Static methods no
Static inner class no
local variables no
让我们采用示例Spark代码并完成各种场景
public class SparkSample {
public int instanceVariable =10 ;
public static int staticInstanceVariable =20 ;
public int run(){
int localVariable =30;
// create Spark conf
final SparkConf sparkConf = new SparkConf().setAppName(config.get(JOB_NAME).set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
// create spark context
final JavaSparkContext sparkContext = new JavaSparkContext(sparkConf);
// read DATA
JavaRDD<String> lines = spark.read().textFile(args[0]).javaRDD();
// Anonymous class used for lambda implementation
JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String s) {
// How will the listed varibles be accessed in RDD across driver and Executors
System.out.println("Output :" + instanceVariable + " " + staticInstanceVariable + " " + localVariable);
return Arrays.asList(SPACE.split(s)).iterator();
});
// SAVE OUTPUT
words.saveAsTextFile(OUTPUT_PATH));
}
// Inner Static class for the funactional interface which can replace the lambda implementation above
public static class MapClass extends FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String s) {
System.out.println("Output :" + instanceVariable + " " + staticInstanceVariable + " " + localVariable);
return Arrays.asList(SPACE.split(s)).iterator();
});
public static void main(String[] args) throws Exception {
JavaWordCount count = new JavaWordCount();
count.run();
}
}
内部类对象内的外部类的实例变量的可访问性和可序列性
Inner class | Instance Variable (Outer class) | Static Instance Variable (Outer class) | Local Variable (Outer class)
Anonymous class | Accessible And Serialized | Accessible yet not Serialized | Accessible And Serialized
Inner Static class | Not Accessible | Accessible yet not Serialized | Not Accessible
了解Spark工作时的经验法则是:
在RDD中编写的所有lambda函数都在驱动程序上实例化,对象被序列化并发送给执行程序
如果在内部类中访问任何外部类实例变量,编译器会应用不同的逻辑来访问它们,因此外部类是否被序列化取决于您访问的内容。
就Java而言,整个争论是关于外类和内部类以及如何访问外部类引用和变量导致序列化问题。
各种情况:
编译器默认在
的字节代码中插入构造函数引用外类对象的匿名类。
外部类对象用于访问实例变量
匿名级(){
final Outer-class reference;
Anonymous-class( Outer-class outer-reference){
reference = outer-reference;
}
}
外部类被序列化并与之一起发送 内部匿名类的序列化对象
由于静态变量未被序列化,因此外部类 对象仍然插入到Anonymous类构造函数中。
静态变量的值取自类状态
出现在执行人身上。
编译器默认在
的字节代码中插入构造函数匿名类,引用外部类对象和局部变量引用。
外部类对象用于访问实例变量
匿名级(){
final Outer-class reference;
final Local-variable localRefrence ;
Anonymous-class( Outer-class outer-reference, Local-variable localRefrence){
reference = outer-reference;
this.localRefrence = localRefrence;
}
}
外部类是序列化的,局部变量对象也是
序列化并与内部匿名类的序列化对象一起发送
当局部变量成为匿名类中的实例成员时,需要对其进行序列化。从外部角度来看,局部变量永远不能被序列化
无法访问
无法访问
由于静态变量未被序列化,因此没有外部类对象被序列化。
静态变量的值取自类状态
出现在执行人身上。
外部类没有序列化,并与序列化的静态内部类一起发送
要思考的要点:
遵循Java序列化规则来选择需要序列化的类对象。
使用javap -p -c&#34; abc.class&#34;打开字节代码并查看编译器生成的代码
根据您在外部类的内部类中尝试访问的内容,编译器会生成不同的字节代码。
您不需要让类实现序列化,只能在驱动程序上访问。
在RDD中使用的任何匿名/静态类(所有lambda函数都是匿名类)都将在驱动程序上实例化。
RDD中使用的任何类/变量都将在驱动程序上实例化并发送给执行程序。
任何声明为transient的实例变量都不会在驱动程序上序列化。
答案 1 :(得分:3)
有很多写得很好的博客,它们对此进行了很好的解释,例如spark serialization challenges。
但是总之,我们可以得出这样的结论(仅火花,而不是一般的JVM):
object
(又名Scala单例)的引用将不会被序列化(仅对于mapPartition和foreachPartition,UDF始终从驱动程序到执行程序都被序列化)。执行者将直接引用其本地JVM的对象,因为它是一个单例,将存在于执行者JVM上。这意味着,执行者不会看到其本地object
上的Driver突变。