使用Kryo序列化时为什么Spark表现更差?

时间:2017-01-09 17:05:17

标签: performance scala apache-spark avro

我为我的Spark作业启用了Kryo序列化,启用了设置以要求注册,并确保我的所有类型都已注册。

val conf = new SparkConf()
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
conf.set("spark.kryo.registrationRequired", "true")
conf.registerKryoClasses(classes)
conf.registerAvroSchemas(avroSchemas: _*)

作业的Wallclock-time性能恶化了大约20%,并且洗牌的字节数增加了近400%。

考虑到Spark documentation建议Kryo应该更好,这对我来说真的很令人惊讶。

  

Kryo比Java序列化(通常高达10倍)显着更快,更紧凑

我手动调用了Spark的serializeorg.apache.spark.serializer.KryoSerializer实例上的org.apache.spark.serializer.JavaSerializer方法,并附有我的数据示例。结果与Spark文档中的建议一致:Kryo生成了98个字节; Java产生了993个字节。这确实提高了10倍。

一个可能令人困惑的因素是被序列化和混洗的对象实现了Avro GenericRecord接口。我尝试在SparkConf中注册Avro架构,但没有显示出任何改进。

我尝试使用新的类来改组简单的Scala case class es,而不包括任何Avro机器。它没有改善shuffle性能或交换的字节数。

Spark代码最终沸腾到以下:

case class A(
    f1: Long,
    f2: Option[Long],
    f3: Int,
    f4: Int,
    f5: Option[String],
    f6: Option[Int],
    f7: Option[String],
    f8: Option[Int],
    f9: Option[Int],
    f10: Option[Int],
    f11: Option[Int],
    f12: String,
    f13: Option[Double],
    f14: Option[Int],
    f15: Option[Double],
    f16: Option[Double],
    f17: List[String],
    f18: String) extends org.apache.avro.specific.SpecificRecordBase {
  def get(f: Int) : AnyRef = ???
  def put(f: Int, value: Any) : Unit = ???
  def getSchema(): org.apache.avro.Schema = A.SCHEMA$
}
object A extends AnyRef with Serializable {
  val SCHEMA$: org.apache.avro.Schema = ???
}

case class B(
    f1: Long
    f2: Long
    f3: String
    f4: String) extends org.apache.avro.specific.SpecificRecordBase {
  def get(field$ : Int) : AnyRef = ???
  def getSchema() : org.apache.avro.Schema = B.SCHEMA$
  def put(field$ : Int, value : Any) : Unit = ???
}
object B extends AnyRef with Serializable {
  val SCHEMA$ : org.apache.avro.Schema = ???
}

def join(as: RDD[A], bs: RDD[B]): (Iterable[A], Iterable[B]) = {
  val joined = as.map(a => a.f1 -> a) cogroup bs.map(b => b.f1 -> b)
  joined.map { case (_, asAndBs) => asAndBs }
}

您是否知道可能会发生什么或如何获得Kryo应该提供的更好的性能?

2 个答案:

答案 0 :(得分:2)

如果您的单个记录大小太小而且记录数量太多可能会使您的工作变慢。请尝试增加缓冲区大小,看看它是否有任何改进。

如果没有完成,请尝试下面的那个..

val conf = new SparkConf()
  .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
  // Now it's 24 Mb of buffer by default instead of 0.064 Mb
  .set("spark.kryoserializer.buffer.mb","24") 

价:https://ogirardot.wordpress.com/2015/01/09/changing-sparks-default-java-serialization-to-kryo/

答案 1 :(得分:0)

由于您拥有高基数的RDD,不幸的是,广播/广播哈希加入似乎不受限制。

在加入之前,最好的是coalesce()您的RDD。您是否在洗牌时看到高度偏差?如果是这样,您可能希望与shuffle = true合并。

最后,如果你有嵌套结构的RDD(例如JSON),那么有时候你可以绕过shuffle。查看幻灯片和/或视频here以获取更详细的说明。