为了账号安全,请及时绑定邮箱和手机立即绑定

Kafka学习分享(5)

标签:
Java
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 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
6396
获赞与收藏
157

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消