Spark Streaming + Kafka(Kafka broker version 0.10.0)

1 概述

本文对于Kafka对接Spark Streaming进行学习。
官方地址,但是需要注意的是:Kafka项目在版本0.8和0.10之间引入了新的消费者API,因此有两个独立的相应Spark Streaming软件包可用。所以使用的时候要注意版本的问题。如下图所示版本选择:
这里写图片描述

作者使用版本介绍(伪分布式):


kafka_2.11-0.10.0.1.tgz
scala-2.11.8.tgz
zookeeper-3.4.5-cdh5.7.0.tar.gz 

kafka下载地址
scala下载地址
zookeeper下载地址

2 安装部署

  • zookeeper-3.4.5-cdh5.7.0.tar.gz
1.下载解压zookeeper-3.4.5-cdh5.7.0.tar.gz 
tar -xzvf zookeeper-3.4.5-cdh5.7.0.tar.gz 

2.修改权限
chown -R hadoop;hadoop zookeeper-3.4.5-cdh5.7.0

3.修改配置
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg 
修改目录
dataDir=/opt/software/zookeeper-3.4.5-cdh5.7.0/data
mkdir data

4.启动
./zkServer.sh start

5.查看状态
./zkServer.sh status
  • kafka_2.11-0.10.0.1.tgz
1.解压
tar -xzvf kafka_2.11-0.10.0.1.tgz
2.创建日志目录
cd kafka
mkdir logs
3.修改配置文件
vi server.properties
port=9092
host.name=192.168.137.141
log.dirs=/opt/software/kafka/logs
4.后台启动
./kafka-server-start.sh -daemon /opt/software/kafka_2.11-0.10.0.1/config/server.properties
  • 检验kafka是否安装成功
创建topic
./kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic streaming_topic

创建生产者
[hadoop@hadoop bin]$ ./kafka-console-producer.sh --broker-list localhost:9092 --topic streaming_topic                    

创建消费者
./kafka-console-consumer.sh --zookeeper localhost:2181 --topic streaming_topic 

在生产者端发送消息看看消费者能否接受到

3 Spark Streaming + Kafka

Kafka 0.10的Spark Streaming集成设计与0.8 Direct Stream方法类似。 它提供了简单的并行性,Kafka分区和Spark分区之间的1:1对应关系,以及对偏移量和元数据的访问。 但是,由于较新的集成使用新的Kafka消费者API而不是简单的API,因此在使用方面存在显着差异。 此版本的集成标记为实验性,因此API可能会发生变化。

  • maven中添加的gav
groupId = org.apache.spark
artifactId = spark-streaming-kafka-0-10_2.11
version = 2.3.0
  • 生产者
./kafka-console-producer.sh --broker-list 192.168.137.130:9092 --topic streaming_topic  
  • 消费者
./kafka-console-consumer.sh --zookeeper 192.168.137.130:2181 --topic streaming_topic
  • 代码
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}


object KafkaStreaming {
  def main(args: Array[String]): Unit = {
    //创建StreamingContext
    val sparkConf=new SparkConf().setAppName("KafkaStreaming").setMaster("local[2]")
    val ssc=new StreamingContext(sparkConf,Seconds(10))

    //准备参数
    val kafkaParams = Map[String, Object](
      "bootstrap.servers" -> "192.168.137.130:9092",
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "use_a_separate_group_id_for_each_stream",
      //Kafka提供的有api,可以将offset提交到指定的kafkatopic或者选择checkpoint的方式,下面会说
      "auto.offset.reset" -> "latest",
      "enable.auto.commit" -> (false: java.lang.Boolean)
    )
    //上面通过Kafka提供的有api设置过offset
   // ssc.checkpoint("/flume_streaming/data")

    //topics(注意这里是复数哦)
    val topics = Array("streaming_topic")
    //通过KafkaUtils放回一个DStream
    val stream = KafkaUtils.createDirectStream[String, String](
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](topics, kafkaParams)
    )

    //stream.map(record => (record.key, record.value)).print()

    //wc
    val lines=stream.map(_.value)
    val word=lines.flatMap(_.split(",")).map(x=>(x,1)).reduceByKey(_+_).print


    ssc.start()
    ssc.awaitTermination()
  }

}
  • 实验
在生产者中输入:
a,a,a,b,b,b,c,c,c,d,d,e,e,r,f,g

结果:
(d,2)
(b,3)
(f,1)
(r,1)
(e,2)
(a,3)
(g,1)
(c,3)

**注意:***kafka的参数,请参考kafka官网。如果,你的spark批次时间超过了kafka的心跳时间(30s),需要增加heartbeat.interval.ms和session.timeout.ms。例如,批处理时间是5min,那么就需要调整group.max.session.timeout.ms。注意,例子中是将enable.auto.commit设置为了false,enable.auto.commit参数值是true,含义是当数据被消费完之后会,如果spark streaming的程序由于某种原因停止之后再启动,下次不会重复消费之前消费过的数据。

4 本地策略(LocationStrategies)

新版本的消费者API会预取消息入buffer。因此,为了提升性能,在Executor端缓存消费者(而不是每个批次重新创建)是非常有必要的,优先调度那些分区到已经有了合适消费者主机上。

在很多情况下,你需要像上文一样使用LocationStrategies.PreferConsistent,这个参数会将分区尽量均匀地分配到所有的可以Executor上去。如果,你的Executor和kafka broker在同一台机器上,可以用PreferBrokers,这将优先将分区调度到kafka分区leader所在的主机上。最后,分区间负荷有明显的倾斜,可以用PreferFixed。这个允许你指定一个明确的分区到主机的映射(没有指定的分区将会使用连续的地址)。

消费者缓存的数目默认最大值是64。如果你希望处理超过(64*excutor数目)kafka分区,spark.streaming.kafka.consumer.cache.maxCapacity这个参数可以帮助你修改这个值。

如果你想禁止kafka消费者缓存,可以将spark.streaming.kafka.consumer.cache.enabled修改为false。禁止缓存缓存可能需要解决SPARK-19185描述的问题。一旦这个bug解决,这个属性将会在后期的spark版本中移除。

Cache是按照topicpartition和groupid进行分组的,所以每次调用creaDirectStream的时候要单独设置group.id。

5 存储偏移

Kafka在有可能存在任务失败的情况下的从消息传输语义(至少一次,最多一次,恰好一次)是取决于何时存储offset。Spark输出操作是至少一次传输语义。所以,如果你想实现仅仅一次的消费语义,你必须要么在密等输出后存储offset,要么就是offset的存储和结果输出是一次事务。

1, Checkpoint

如果使能了Checkpoint,offset被存储到Checkpoint。这个虽然很容易做到,但是也有一些缺点。由于会多次输出结果,所以结果输出必须是满足幂等性。同时事务性不可选。另外,如果代码变更,你是不可以从Checkpoint恢复的。针对代码升级更新操作,你可以同时运行你的新任务和旧任务(因为你的输出结果是幂等性)。对于以外的故障,并且同时代码变更了,肯定会丢失数据的,除非另有方式来识别启动消费的偏移。

2, Kafka自身

Kafka提供的有api,可以将offset提交到指定的kafkatopic。默认情况下,新的消费者会周期性的自动提交offset到kafka。但是有些情况下,这也会有些问题,因为消息可能已经被消费者从kafka拉去出来,但是spark还没处理,这种情况下会导致一些错误。这也是为什么例子中stream将enable.auto.commit设置为了false。然而在已经提交spark输出结果之后,你可以手动提交偏移到kafka。相对于Checkpoint,offset存储到kafka的好处是:kafka既是一个容错的存储系统,也是可以避免代码变更带来的麻烦。提交offset到kafka和结果输出也不是一次事务,所以也要求你的输出结果是满足幂等性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值