Spark学习(拾贰)- Spark Streaming整合Kafka

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bingdianone/article/details/84880926


官方文档:
http://spark.apache.org/docs/2.2.0/streaming-kafka-integration.html

Spark Streaming整合Kafka的版本选择详解

在spark2.2之前建议选择spark-streaming-kafka-0-8版本;虽然spark-streaming-kafka-0-10是优化更好的;但是2.2之前的相关api还不稳定
在这里插入图片描述
在spark2.3之后建议选择spark-streaming-kafka-0-10版本;spark-streaming-kafka-0-8已经是官方弃用的。
在这里插入图片描述

以下是基于spark2.2的测试:

Receiver方式整合之概述

这种方法使用一个接收器来接收数据。接收器是使用Kafka高级消费者API(高级api就是offset偏移量是自动完成控制;手动控制offset的就是低级api)实现的。与所有接收方一样,通过接收方从Kafka接收到的数据存储在Spark执行器中,然后由Spark流启动的作业处理这些数据。

但是,在默认配置下,这种方法在失败时可能会丢失数据(参见接收方可靠性)。为了确保零数据丢失,您必须在Sparkstreaming中(在Spark 1.2中引入)另外启用WAL机制。这将同步地将所有接收到的Kafka数据保存到分布式文件系统(比如HDFS),以便在故障时可以恢复所有数据。有关写前日志的详细信息,请参阅流编程指南中的部署部分

Receiver方式整合之Kafka测试

Receiver整合前置条件:

  1. 启动zk
  2. 启动kafka
  3. 创建topic
    在这里插入图片描述
  4. 通过控制台测试本topic是否能够正常的生产和消费信息

Receiver方式整合之Spark Streaming应用开发

添加pom文件中的依赖

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-streaming-kafka-0-8_2.11</artifactId>
    <version>${spark.version}</version>
</dependency>
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
  * Spark Streaming对接Kafka的方式一
  */
object KafkaReceiverWordCount {

  def main(args: Array[String]): Unit = {

    if(args.length != 4) {
      System.err.println("Usage: KafkaReceiverWordCount <zkQuorum> <group> <topics> <numThreads>")
    }

    val Array(zkQuorum, group, topics, numThreads) = args

    val sparkConf = new SparkConf() //.setAppName("KafkaReceiverWordCount")
      //.setMaster("local[2]")

    val ssc = new StreamingContext(sparkConf, Seconds(5))

    val topicMap = topics.split(",").map((_, numThreads.toInt)).toMap

    // TODO... Spark Streaming如何对接Kafka
    val messages = KafkaUtils.createStream(ssc, zkQuorum, group,topicMap)

    // TODO... 自己去测试为什么要取第二个
    messages.map(_._2).flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()

    ssc.start()
    ssc.awaitTermination()
  }
}

Receiver方式整合之本地环境联调

1、启动IDEA应用程序:
在这里插入图片描述
2、从kafka生产者端输入消息
在这里插入图片描述
观察本地IDEA控制台可以看到计算结果
同时kafka消费端也有消息输出
在这里插入图片描述

Receiver方式整合之服务器环境联调及Streaming UI讲解

1、将本地IDEA的应用程序打包:mvn clean package -DskipTests
2、将jar包上传到spark服务器上
3、提交应用程序

spark-submit \
--class com.imooc.spark.KafkaReceiverWordCount \
--master local[2] \
--name KafkaReceiverWordCount \
--packages org.apache.spark:spark-streaming-kafka-0-8_2.11:2.2.0 \
/home/hadoop/lib/sparktrain-1.0.jar  hadoop000:2181 test kafka_streaming_topic 1

4、向kafka输入数据进行测试

Spark UI界面
下图有一个receiver;如果停掉就没有线程接受数据了。Directed模式不会有这个东西。
在这里插入图片描述
环境:
在这里插入图片描述
下图界面对于调优有用。当前5s一个批次;运行了3分钟11s
在这里插入图片描述

Direct方式整合之概述(推荐)

Spark 1.3中引入了这种新的无接收方“直接”方法,以确保更强的端到端保证。这种方法不使用接收者来接收数据,而是定期查询Kafka以获取每个主题+分区中的最新偏移量,并相应地定义每个批处理中的偏移量范围。启动处理数据的作业时,Kafka的简单消费者API用于从Kafka读取已定义的偏移量范围(类似于从文件系统读取文件)。请注意,这个特性是在针对Scala和Java API的Spark 1.3和针对Python API的Spark 1.4中引入的。

与基于接收者的方法(receive)相比,这种方法具有以下优点:

  • 简化并行性:不需要创建多个输入Kafka流并将它们合并。使用directStream, Sparkstreaming将创建尽可能多的RDD分区,因为有Kafka分区要使用,这些分区将并行地从Kafka读取数据。因此Kafka和RDD分区之间存在一对一的映射,这更容易理解和优化。
  • 效率:在receive方法中实现零数据丢失需要将数据存储在WAL机制的日志中,这样可以进一步复制数据。这实际上是低效的,因为数据被有效地复制了两次——一次由Kafka复制,另一次由Write Ahead日志复制。direct方法消除了这个问题,因为没有接收方,因此不需要提前写日志。只要保留了足够的Kafka,就可以从Kafka恢复消息。
  • 精确的一次性语义:receive方法使用Kafka的高级API在Zookeeper中存储消耗的偏移量。这是传统上使用Kafka数据的方式。虽然这种方法(与写前日志相结合)可以确保零数据丢失(即至少一次语义),但是在某些失败情况下,一些记录可能被使用两次的可能性很小。这是因为火花流可靠接收的数据与Zookeeper跟踪的偏移量之间的不一致。因此,在direct种方法中,我们使用不使用Zookeeper的简单Kafka API。偏移量通过其检查点内的Spark流进行跟踪。这消除了Sparkstreaming和Zookeeper/Kafka之间的不一致性,因此尽管出现了故障,Sparkstreaming仍然可以有效地接收每条记录一次。为了精确地实现结果输出的一次性语义,将数据保存到外部数据存储的输出操作必须是幂等的,或者是保存结果和偏移量的原子事务(更多信息请参阅主编程指南中的输出操作语义)。

注意,这种方法的一个缺点是它不更新Zookeeper中的偏移量,因此基于Zookeeper的Kafka监控工具不会显示进度。但是,您可以在每个批处理中访问这种方法处理的偏移量,并自己更新Zookeeper。

Direct方式整合之Spark Streaming应用开发及本地环境测试

import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
import kafka.serializer.StringDecoder
/**
  * Spark Streaming对接Kafka的方式二
  */
object KafkaDirectWordCount {

  def main(args: Array[String]): Unit = {

    if(args.length != 2) {
      System.err.println("Usage: KafkaDirectWordCount <brokers> <topics>")
      System.exit(1)
    }

    val Array(brokers, topics) = args

    val sparkConf = new SparkConf() //.setAppName("KafkaReceiverWordCount")
      //.setMaster("local[2]")

    val ssc = new StreamingContext(sparkConf, Seconds(5))

    val topicsSet = topics.split(",").toSet
    val kafkaParams = Map[String,String]("metadata.broker.list"-> brokers)

    // TODO... Spark Streaming如何对接Kafka
    val messages = KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder](
    ssc,kafkaParams,topicsSet
    )

    // TODO... 自己去测试为什么要取第二个
    messages.map(_._2).flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()

    ssc.start()
    ssc.awaitTermination()
  }
}

运行
在这里插入图片描述
测试数据的方式和receive一样。生产端输入数据;查看本地IDEA控制台。

Direct方式整合之服务器环境联调

1、将本地IDEA的应用程序打包:mvn clean package -DskipTests
2、将jar包上传到spark服务器上
3、提交应用程序

spark-submit \
--class com.imooc.spark.KafkaDirectWordCount \
--master local[2] \
--name KafkaDirectWordCount \
--packages org.apache.spark:spark-streaming-kafka-0-8_2.11:2.2.0 \
/home/hadoop/lib/sparktrain-1.0.jar  hadoop000:9092 kafka_streaming_topic

查看UI界面发现没有receive这个东西了
在这里插入图片描述
输入一些测试数据;同时查看其他UI界面。

猜你喜欢

转载自blog.csdn.net/bingdianone/article/details/84880926