Entender la serialización de Spark

En Spark, ¿cómo se sabe qué objetos se crean instancias en el controlador y cuáles se crean instancias en el ejecutor y, por lo tanto, cómo se determina qué clases necesitan implementar Serializable?

Para serializar un objeto significa convertir su estado a una secuencia de bytes para que la secuencia de bytes pueda revertirse a una copia del objeto. Un objeto Java es serializable si su clase o cualquiera de sus superclases implementa la interfaz java.io.Serializable o su subinterfaz, java.io.Externalizable.

Una clase nunca se serializa, solo el objeto de una clase se serializa. La serialización de objetos es necesaria si el objeto necesita persistir o transmitirse a través de la red.

Class Component Serialization instance variable yes Static instance variable no methods no Static methods no Static inner class no local variables no 

Tomemos un código de Spark de muestra y pasemos por varios escenarios

 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 lines = spark.read().textFile(args[0]).javaRDD(); // Anonymous class used for lambda implementation JavaRDD words = lines.flatMap(new FlatMapFunction() { @Override public Iterator 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() { @Override public Iterator 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(); } } 

Accesibilidad y serialización de variable de instancia de clase externa dentro de objetos de clase interna

  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 

La regla de oro para entender el trabajo de Spark es:

  1. Todas las funciones lambda escritas dentro del RDD se instancian en el controlador y los objetos se serializan y se envían a los ejecutores

  2. Si se accede a cualquier variable de instancia de clase externa dentro de la clase interna, el comstackdor aplica una lógica diferente para acceder a ellas, por lo tanto, la clase externa se serializa o no depende de a qué se accede.

  3. En términos de Java, todo el debate es acerca de la clase externa frente a la clase interna y cómo el acceso a las referencias y variables de la clase externa conduce a problemas de serialización.

Varios escenarios:

Clase externa Variables variables a las que se accede dentro de la clase Anónima:


Variable de instancia (clase externa)

El comstackdor inserta por defecto el constructor en el código de bytes del

Clase anónima con referencia al objeto de la clase Exterior.

El objeto de la clase externa se usa para acceder a la variable de instancia

Clase anónima () {

  final Outer-class reference; Anonymous-class( Outer-class outer-reference){ reference = outer-reference; } 

}

La clase externa se serializa y se envía junto con el objeto serializado de la clase anónima interna


Variable de instancia estática (clase externa)

Como las variables estáticas no están serializadas, el objeto de la clase externa aún se inserta en el constructor de la clase Anónimo.

El valor de la variable estática se toma del estado de clase

presente en ese ejecutor.


Variable local (clase externa)

El comstackdor inserta por defecto el constructor en el código de bytes del

Clase anónima con referencia al objeto de la clase externa Y a la refrencia de la variable local.

El objeto de la clase externa se usa para acceder a la variable de instancia

Clase anónima () {

  final Outer-class reference; final Local-variable localRefrence ; Anonymous-class( Outer-class outer-reference, Local-variable localRefrence){ reference = outer-reference; this.localRefrence = localRefrence; } 

}

La clase externa está serializada, y el objeto variable local también es

serializado y enviado junto con el objeto serializado de la clase anónima interna

A medida que la variable local se convierte en un miembro de instancia dentro de la clase anónima, debe ser serializada. Desde la perspectiva de la clase externa, la variable local nunca se puede serializar

———-

Variables de clase externa a las que se accede con clase interna estática.

Variable de instancia (clase externa)

no se puede acceder


Variable local (clase externa)

no se puede acceder


Variable de instancia estática (clase externa)

Como las variables estáticas no están serializadas, ningún objeto de la clase externa se serializa.

El valor de la variable estática se toma del estado de clase

presente en ese ejecutor.

La clase externa no se serializa y se envía junto con la clase interna estática serializada


Puntos para pensar:

  1. Se siguen las reglas de serialización de Java para seleccionar qué objeto de clase necesita ser serializado.

  2. Use javap -p -c “abc.class” para desenvolver el código de bytes y ver el código generado por el comstackdor

  3. Dependiendo de lo que intente acceder dentro de la clase interna de la clase externa, el comstackdor genera un código de bytes diferente.

  4. No es necesario que las clases implementen Serialización a las que solo se accede desde el controlador.

  5. Cualquier clase anónima / estática (todas las funciones lambda son clases anónimas) utilizadas en RDD se crearán instancias en el controlador.

  6. Cualquier clase / variable utilizada dentro de RDD se instanciará en el controlador y se enviará a los ejecutores.

  7. Cualquier variable de instancia declarada transitoria no se serializará en el controlador.

    1. Por defecto, las clases anónimas te obligarán a hacer que la clase externa se pueda serializar.
    2. Cualquier variable / objeto local no necesita ser serializable.
    3. Solo si se usa una variable local dentro de la clase Anonima necesita ser serializada
    4. Se puede crear singleton dentro del método call () del par, función mapToPair, asegurándose así de que nunca se inicialice en el controlador
    5. las variables estáticas nunca se serializan, por lo tanto, nunca se envían desde el controlador a los ejecutores
  8. si necesita que se ejecute algún servicio solo en el ejecutor, conviértalos en campos estáticos dentro de la función lambda, o póngalos transitorios y singelton y verifique la condición nula para instanciarlos.