1

使用编码器如何比 java 和 kryo 序列化快得多?

4

2 回答 2

3
  • 因为Encoders为了性能牺牲了一般性。这个想法并不新鲜。为什么 Kryo 比 Java 序列化更快?出于同样的原因。考虑这个成绩单:

    scala> val spark = SparkSession.builder.config("spark.serializer", "org.apache.spark.serializer.JavaSerializer").getOrCreate()
    spark: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@1ed28f57
    
    scala> val map = Map[String, Int]("foo" -> 1).withDefaultValue(0)
    map: scala.collection.immutable.Map[String,Int] = Map(foo -> 1)
    
    scala> map("bar")
    res1: Int = 0
    
    scala> val mapSerDe = spark.sparkContext.parallelize(Seq(map)).first
    mapSerDe: scala.collection.immutable.Map[String,Int] = Map(foo -> 1)
    
    scala> mapSerDe("bar")
    res2: Int = 0
    

    相比

    scala> val spark = SparkSession.builder.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer").getOrCreate()
    spark: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@5cef3456
    
    scala>  val map = Map[String, Int]("foo" -> 1).withDefaultValue(0)
    map: scala.collection.immutable.Map[String,Int] = Map(foo -> 1)
    
    scala> map("bar")
    res7: Int = 0
    
    scala>  val mapSerDe = spark.sparkContext.parallelize(Seq(map)).first
    mapSerDe: scala.collection.immutable.Map[String,Int] = Map(foo -> 1)
    
    scala> mapSerDe("bar")
    java.util.NoSuchElementException: key not found: bar
      at scala.collection.MapLike$class.default(MapLike.scala:228)
      at scala.collection.AbstractMap.default(Map.scala:59)
      at scala.collection.MapLike$class.apply(MapLike.scala:141)
      at scala.collection.AbstractMap.apply(Map.scala:59)
      ... 48 elided
    

    (我找不到确切的帖子,但这个例子的想法来自开发者列表)。

    如您所见,Kryo 虽然速度更快,但并不能处理所有可能的情况。它专注于最常见的问题,并且做得对。

    SparkEncoders也这样做,但更不通用。如果你只支持 16 种左右,并且不关心互操作性(必须与真正的序列化库),那么你有很多机会进行优化。

  • 无需互操作性,您可以走得更远。原子类型的编码器只是身份。根本不需要任何转换。

  • 正如hemanshuIIITian所解释的,了解模式是另一个因素。

    为什么这有关系?因为具有明确定义的形状,可以让您优化序列化和存储。如果您知道您的数据是结构化的,您可以切换维度 - 而不是存储和访问昂贵的异构行,您可以使用列式存储。

    一旦数据存储在列中,您就会打开一组全新的优化机会:

    • 固定大小字段的数据访问非常快,因为您可以直接访问特定地址(还记得关于堆外/本机内存/钨的所有兴奋吗?)。
    • 您可以使用广泛的压缩和编码技术来最小化数据的大小。

    这种想法也不新鲜。列式数据库、存储格式(如 Parquet)或为分析设计的现代序列化格式(如 Arrow)使用相同的想法,并且经常将这些想法推得更远(零拷贝数据共享)。

  • 不幸的是,编码器不是灵丹妙药。存储非标准对象是一团糟,集合编码器可能非常低效

于 2018-05-05T12:36:32.567 回答
0

简单 - 编码器知道记录的模式。这就是它们提供显着更快的序列化和反序列化的方式(与默认的 Java 或 Kryo 序列化程序相比)。

供参考 - https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-Encoder.html

于 2018-05-05T08:44:31.927 回答