Spark Streaming+kafka的简单使用
环境依赖
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
简单使用
在一些流处理的时候,Spark Streaming + Kafka 是比较常见的。
val kafkaParams = Map[String, Object](
"bootstrap.servers" -> "localhost:9092,anotherhost:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "use_a_separate_group_id_for_each_stream",
"auto.offset.reset" -> "latest",
"enable.auto.commit" -> (false: java.lang.Boolean)
)
val topics = Array("topicA", "topicB")
val stream = KafkaUtils.createDirectStream[String, String](
streamingContext,
PreferConsistent,
Subscribe[String, String](topics, kafkaParams)
)
stream.map(record => (record.key, record.value))
上面的代码就可以让我们简单的使用起来,但是如果Spark Streaming应用挂掉之后是不能从正确的
位置读取数据的。
因此我们必须自己 管理Kafka Offsets保证 Spark Streaming应用挂掉之后仍然能够正确地读取
数据。
这里我们把offset存储到kafka本身。
stream.foreachRDD(rdd=>{
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
rdd.foreachPartition{iter=>
val o: OffsetRange = offsetRanges(TaskContext.get.partitionId)
println(s"${o.topic} ${o.partition} ${o.fromOffset} ${o.untilOffset}")
iter.foreach(record=>{
println(record.value())
})
}
stream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)
})
当然我们也可以把消费位移信息保存到外部系统,比如数据库或者zk.
这样在启动Spark Streaming的时候再去读取起始的位移信息。当消费完成一批消息后在保存消费
位移到外部系统。
比如:
val fromOffsets = selectOffsetsFromYourDatabase.map { resultSet =>
new TopicPartition(resultSet.string("topic"), resultSet.int("partition")) -> resultSet.long("offset")
}.toMap
val stream = KafkaUtils.createDirectStream[String, String](
streamingContext,
PreferConsistent,
Assign[String, String](fromOffsets.keys.toList, kafkaParams, fromOffsets)
)
stream.foreachRDD { rdd =>
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
val results = yourCalculation(rdd)
......
}
其实我们可以去看KafkaUtils.createDirectStream的源码,里面用到了我们之前所说的
seek(TopicPartition,offset)方法。
它会根据是否有fromOffsets来判断,如果存在就会调用下面的方法。
consumer.seek(topicPartition, offset)
然后会开始进行消费消息。
总结
在做kafka和一些其他组件的整合时候,还是需要先更多了解kafka自身的使用,包括生产者和消费者
api的使用和相关概念。
我们也可以直接到spark的官网查找相应的资
料:http://spark.apache.org/docs/latest/streaming-kafka-0-10-integration.html
后续
打开App,阅读手记