SparkStreaming + Kafka集成,创建DStream以kafka作为数据源

本文介绍了Spark Streaming与Kafka的两种整合方式:基于Receiver和Direct。基于Receiver的方式操作简单但可能丢失数据;Direct方式简化了数据拉取过程,自带容错机制,适合高并发场景。文中还详细介绍了如何在Spark项目中引入Maven依赖并实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SparkStreaming和Kafka的整合分为两种方式

第一种是基于Receiver的方式

Receiver的结构:

为了保证并行获取数据,对应每一个外部数据源的分区,所以Receiver也要是分布式的,主要分为三个部分

  1. Receiver是一个对象,是可以有用户自定义的获取逻辑对象,表示了如何获取数据
  2. Receiver Tracker是Receiver的协调和调度者,其运行在Driver上
  3. Receiver Supervisor被Receiver Tracker调度到不同的分布式上运行,其会拿到用户自定义的Receiver对象,使用这个对象来获取外部数据

在这里插入图片描述

Receiver的执行过程:

  1. 在SparkStreaming程序开启的时候,Receiver Tracker使用JobScheduler分发Job到不同的节点,每个Job包含一个Task,这个Task就是Receiver Supervisor,这个部分其实是复用了通用的调度逻辑;
  2. Receiver Supervisor启动后进行Receiver实例;
  3. Receiver启动后,就将持续不断地接收外界数据,并持续交给Receiver Supervisor进行数据存储;
  4. Receiver Supervisor持续不断地接收到Receiver转来地数据,并通过BlockManager来存储数据;
  5. 获取地数据存储完成后发送元数据给Driver端的Receiver Tracker,包含数据块的id、位置、数量、大小等信息。

特点:操作简单,使用方便

弊端:可能会丢失数据

第二种是基于Direct的方式

Direct的执行过程:
在这里插入图片描述

从kafka下面的topic里面拿数据,kafka有几个partition,那么SparkStreaming程序生成的RDD就有几个partition,这是对并行度的一个限制,为了提高并行度,必须repartition

优点:简化了从kafka拉去数据的过程,不需要Receiver;自带容错的,不需要使用预写日志机制,因为拉取数据和处理数据并没有被分割开来(kafka本身也是一个可靠的数据源,不会有丢失数据的风险,如果失败了,可以通过这个偏移量直接从kafka中恢复数据);另外batch任务堆积时,也不会影响数据堆积

Direct的连接方式

偏移量是由Driver端来维度的;处理偏移量保存到哪里 有两种思路:

  1. checkpoint,自动保存到checkpoint里面
  2. 使用zookeeper的API,读zookeeper

SparkStreaming +Kafka集成

Apache Kafka is publish-subscribe messaging rethought as a distributed, partitioned, replicated commit log service. Please read the Kafka documentation thoroughly before starting an integration using Spark.

Apache Kafka将发布-订阅消息传递重新考虑为分布式、分区、复制的提交日志服务。在使用Spark开始集成之前,请仔细阅读Kafka文档。

The Kafka project introduced a new consumer api between versions 0.8 and 0.10, so there are 2 separate corresponding Spark Streaming packages available. Please choose the correct package for your brokers and desired features; note that the 0.8 integration is compatible with later 0.9 and 0.10 brokers, but the 0.10 integration is not compatible with earlier brokers.

Kafka项目在版本0.8和0.10之间引入了一个新的消费者api,因此有两个单独的相应的Spark流包可用。请为您的经纪人选择正确的软件包和所需的功能;注意,0.8集成与后来的0.9和0.10代理兼容,但是0.10集成与以前的代理不兼容。

在这里插入图片描述

在工程中需要引入Maven工件 spark-streaming-kafka-0-10spark-streaming-kafka-0-8来使用它。包内提供的KafkaUtils对象可以在StreamingContext和JavaStreamingContext中以你的Kafka消息创建出DStream。由于KafkaUtils可以订阅多个主题,因此它创建出的DStream由成对的主题和消息组成。要创建出一个流数据,需要使用StreamingContext实例、一个由逗号隔开的ZooKeeper主机列表字符串、消费者组的名字(唯一名字),以及一个从主题到针对这个主题的接收器线程数的映射表来调用createStream()方法。

spark-streaming-kafka-0-10版本

导入依赖

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>0.11.0.2</version>
</dependency>

编写代码

package com.spark.kafka

import org.apache.kafka.clients.consumer.ConsumerConfig
import org.apache.log4j.{Level, Logger}
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.kafka10.KafkaUtils

object KafkaDirect {
  def main(args: Array[String]): Unit = {
    Logger.getLogger("org").setLevel(Level.ERROR)

    // 1.初始化Spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")

    // 2.初始化SparkStreamingContext
    val ssc = new StreamingContext(conf, Seconds(5))

    // 3.定义kafka参数
    val brokers = "node7-1:9092, node7-2:9092, node7-3:9092, node7-4:9092"
    val topic = Set("source")
    val consumerGroup = "spark"

    // 4.将kafka参数映射为map
    val kafkaParam: Map[String, String] = Map(
      ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG -> "org.apache.kafka.common.serialization.StringDeserializer",
      ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG -> "org.apache.kafka.common.serialization.StringDeserializer",
      ConsumerConfig.GROUP_ID_CONFIG -> consumerGroup,
      ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG -> brokers
    )

    // 5.通过kafkaUtil创建kafkaDStream
    val kafkaDStream = KafkaUtils.createDirectStream(
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String,String](topics,kafkaParams)
    )
    
    // 6.对kafkaDStream做计算(wordCount)
    kafkaDStream.map(record => {
      record.value().toString
    }).flatMap(_.split(" ")).map((_, 1)).reduceByKey(_+_).print()
    
    // 7.启动SparkStreaming
    ssc.start()
    ssc.awaitTermination()

  }
}
spark-streaming-kafka-0-8版本

导入依赖

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-streaming-kafka-0-8_2.11</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>0.11.0.2</version>
</dependency>

编写代码

package com.spark.kafka

import org.apache.kafka.clients.consumer.ConsumerConfig
import org.apache.log4j.{Level, Logger}
import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.dstream.ReceiverInputDStream
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
 * 通过SparkStreaming从Kafka读取数据,并将读取过来的数据做简单计算,最终打印到控制台
 */
object KafkaReceiver {
  def main(args: Array[String]): Unit = {
    Logger.getLogger("org").setLevel(Level.ERROR)

    // 1.初始化Spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")

    // 2.初始化SparkStreamingContext
    val ssc = new StreamingContext(conf, Seconds(5))

    // 3.定义kafka参数
    val brokers = "node7-1:9092, node7-2:9092, node7-3:9092, node7-4:9092"
    val topic = Map(("source", 1))
    val consumerGroup = "spark"

    // 4.将kafka参数映射为map
    val kafkaParam: Map[String, String] = Map[String, String](
      ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG -> "org.apache.kafka.common.serialization.StringDeserializer",
      ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG -> "org.apache.kafka.common.serialization.StringDeserializer",
      ConsumerConfig.GROUP_ID_CONFIG -> consumerGroup,
      ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG -> brokers
    )

    // 5.通过kafkaUtil创建kafkaDStream
    val kafkaDStream: ReceiverInputDStream[(String, String)] = KafkaUtils.createStream(ssc, kafkaParam, topic, StorageLevel.MEMORY_ONLY)

    // 6.对kafkaDStream做计算(wordCount)
    kafkaDStream.foreachRDD(rdd => {
      val word: RDD[String] = rdd.flatMap(_._2.split(" "))
      val wordAndOne: RDD[(String, Int)] = word.map((_, 1))
      val wordAndCount: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
      wordAndCount.collect().foreach(println)
    })

    // 7.启动SparkStreaming
    ssc.start()
    ssc.awaitTermination()

  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值