我有一个困扰我几天的问题,而且我的想法很不错。
我构建了一个Spark docker容器,Spark在独立模式下运行。主人和工人都在那里开始。这是在Azure中运行的计算机。
现在我尝试将Spark Scala应用程序部署在一个单独的容器(同一台机器)中,在那里我传递Spark主URL和我需要连接到Spark的其他东西。连接是无缝的。
我遇到的第一个问题是:
Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 4 times, most recent failure: Lost task 0.3 in stage 0.0 (TID 3, 10.1.0.4): java.lang.ClassNotFoundException: org.apache.spark.streaming.kafka.KafkaRDDPartition
然后我创建了一个除Spark之外的依赖项文件夹,将它们放在我的应用程序JAR文件旁边的文件夹中,并使用SparkConf.setJars
将它们添加到SparkConf,
现在奇怪的事情发生了:
Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 4 times, most recent failure: Lost task 0.3 in stage 0.0 (TID 3, 10.1.0.4): java.lang.ClassCastException: cannot assign instance of scala.collection.immutable.List$SerializationProxy to field org.apache.spark.rdd.RDD.org$apache$spark$rdd$RDD$$dependencies_ of type scala.collection.Seq in instance of org.apache.spark.rdd.MapPartitionsRDD
除此之外,如果我只使用java -cp <dependencies(including spark jars) cp> myApp.jar
从本地计算机运行scala应用程序,它运行正常,作业运行正常。
我本地没有SPARK_HOME
,而setJars
基本上是一个空列表,好像我不会使用它,它仍然有效。
我想它在运行我的应用程序时使用类路径中提供的jar,我不需要提供任何其他内容。
如果你们中的任何人有任何想法我会很感激,我真的无法解释自己为什么这不起作用我直到现在才做任何Spark部署。我主要使用嵌入式Spark。
Spark在我的应用程序依赖项(2.0.0)中与在docker容器中运行的版本相同。
我用过:
Scala 2.11.7 for my app
两个容器上的Java 1.8(app,spark)
这里要求的是我的应用程序的代码
val jars = Option(new File(Properties.spark_jars_path).listFiles()).toList.flatten.map(_.getAbsolutePath)
val conf = new SparkConf()
.setMaster(RunUtils.determineMasterUrl(Properties.mode))
.setAppName(RunUtils.SPARK_APP_NAME)
.setJars(jars)
.set("spark.cassandra.connection.host", Properties.cassandra_connection_host)
val ssc = new StreamingContext(conf, Seconds(1))
case class Result(buyDate: Timestamp, endDate: Timestamp, maxDate: Timestamp, buyAmount: Double, buyRate: Double)
def main(args: Array[String]): Unit = {
val DateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd")
val kafkaParams = Map("metadata.broker.list" -> Properties.kafka_brokers, "auto.offset.reset" -> Properties.kafka_auto_reset_offset)
//
// BITSTAMP
//
val bitstampTopic = Set("bitstamp_trades")
val bitstampStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, bitstampTopic)
val bitstampTradeStream = bitstampStream.map(_._2).map { trade =>
val jsonNode = JsonMapper.readTree(trade)
Trade(
"BITSTAMP",
"BTC_USD",
if(jsonNode.get("type").asInt() == 1) "SELL" else "BUY",
DateFormatter.format(new Date(jsonNode.get("timestamp").asLong() * 1000)),
new Date(jsonNode.get("timestamp").asLong() * 1000),
jsonNode.get("amount").asDouble(),
jsonNode.get("price").asDouble()
)
}
bitstampTradeStream.saveToCassandra("coin_master", "trades", SomeColumns(
"exchange_house",
"exchange_currencies",
"exchange_type",
"date",
"trade_time",
"amount",
"price")
)
ssc.start()
ssc.awaitTermination()
}
答案 0 :(得分:0)
好的,问题是我的地图功能。
更具体地说,这一行是问题所在:
val jsonNode = JsonMapper.readTree(trade)
JsonMapper实际上是一个来自Jackson库的已配置的ObjectMapper,为了使它工作,我应该使用sparkContext.broadcast
,因为必须在每个执行器上调用一些方法。
您可以在此处详细了解原因: Spark: broadcasting jackson ObjectMapper
因此,在将我的代码更改为类似的内容之后,它起作用了:
val broadcastValue = ssc.sparkContext.broadcast(JsonMapper)
val kafkaParams = Map("metadata.broker.list" -> Properties.kafka_brokers, "auto.offset.reset" -> Properties.kafka_auto_reset_offset)
//
// BITSTAMP
//
val bitstampTopic = Set("bitstamp_trades")
val bitstampStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, bitstampTopic)
val bitstampTradeStream = bitstampStream.map(_._2).map { trade =>
broadcastValue.value.registerModule(new DefaultScalaModule with RequiredPropertiesSchemaModule)
val jsonNode = broadcastValue.value.readTree(trade)
Trade(
"BITSTAMP",
"BTC_USD",
if(jsonNode.get("type").asInt() == 1) "SELL" else "BUY",
DateFormatter.format(new Date(jsonNode.get("timestamp").asLong() * 1000)),
new Date(jsonNode.get("timestamp").asLong() * 1000),
jsonNode.get("amount").asDouble(),
jsonNode.get("price").asDouble()
)
}