文章目录
官方文档:
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整合前置条件:
- 启动zk
- 启动kafka
- 创建topic
- 通过控制台测试本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界面。