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=>{
//把RDD转为HasOffsetRanges对象
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
rdd.foreachPartition{iter=>
//获取每个分区的 offset信息
val o: OffsetRange = offsetRanges(TaskContext.get.partitionId)
println(s"${o.topic} ${o.partition} ${o.fromOffset} ${o.untilOffset}")
//获取每个分区的数据进行处理
iter.foreach(record=>{
println(record.value())
})
}
//存储offset到kafka本身
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
//参数需要传入fromOffsets
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
后续
Kafka监控的使用
Kafka其他特性的学习
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦