Direct方法与Receiver方法对比及优势
1 简化并行度:简化并行度不需要创建多个输入流然后再进行合并。使用Direct方法Spark Streaming创建的RDD分区数与Kafka的分区一样多,这些RDD分区都从Kafka并行读取数据。因此,Kafka分区和RDD分区存在存在一对一的映射关系,这更已于理解和调整
2 提升效率:Receiver方法为了实现数据零丢失,需要将数据存储在预写日志中,然后再进一步复制数据。这样做会导致效率很低,因为数据被复制了两次,第一次是通过Kafka复制,第二次是通过“预写日志”复制。Direct方法就没有这方面的问题,因为Direct方法没有接收器,所以不需要预写日志。只需要Kafka的保留数据时间足够长,就可以从Kafka中恢复数据。
3 恰好一次语义:Receiver方法使用Kafka的高级API将消耗的偏移量存储在Zookeeper中。这个方法与预写日志结合使用可以确保数据零丢失(即至少一次语义),但遇到故障的时候有可能导致数据被消费两次。发生这种情况是因为Spark Streaming接收的数据与Zookeeper跟踪的偏移量之间存在不一致。所以在Direct方法中,我们不使用Zookeeper保存偏移量,而是使用简单的Kafka API。Spark Streaming在检查点内跟踪偏移量,这样可以消除Spark Streaming、Zookeeper和Kafka之间的偏移量不一致问题。所以就算是出现了故障,Spark Streaming也会有效地恰好一次接收数据。为了实现一次性语义,结果保存到外部存储的操作必须是幂等的,或者是保存结果和偏移量的原子事务。
注意:Direct方法的缺点是它不会更新Zookeepr中的偏移量,所以基于Zookeeper的Kafka监视工具不会显示进度。但是我们可以在每个批次中访问Direct方法的偏移量,并更新Zookeeper。
Spark Streaming 整合 Kafka Receiver 方法,工作中用得比较多
1 启动zookeeper
2 启动Kafa
3 创建kafka topic
4 通过控制台测试本kafka topic是否能够正常的生产和消费信息
5 写Spark Streaming代码
6 本地:运行Spark Streaming程序(需要传入brokers和topics参数)
6 集群:运行mvn命令打包,把jar包上传到集群中,运行spark-submit命令
7 通过kafka-console-producer生产数据
8 查看是否能正常处理数据
1 启动zookeeper
zkServer.sh start
2 启动Kafa
$KAFKA_HOME/bin/kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties
3 创建kafka topic
$KAFKA_HOME/bin/kafka-topic.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic kafka_streaming_topic
4 通过控制台测试本kafka topic是否能够正常的生产和消费信息
// kafka消费端6 集群:运行mvn命令打包,把jar包上传到集群中,运行spark-submit命令
$KAFKA_HOME/bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic kafka_streaming_topic
// kafka生产端
$KAFKA_HOME/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic kafka_streaming_topic
// 向生产端发送数据查看消费端是否能够接收,如果能接收证明kafka调通了
5 本地:写Spark Streaming代码
// 依赖
groupId = org.apache.spark
artifactId = spark-streaming-kafka-0-8_2.11
version = 2.2.0
// Spark Streaming 代码
package com.imooc.spark
import kafka.serializer.StringDecoder
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
/*
Spark Streaming 整合 Kafka Receiver 方法,工作中用得比较多
1 启动zookeeper
2 启动Kafa
3 创建kafka topic
4 通过控制台测试本kafka topic是否能够正常的生产和消费信息
5 写Spark Streaming代码
6 运行Spark Streaming程序(需要传入brokers和topics参数)
7 通过kafka-console-producer生产数据
8 查看idea是否能正常处理数据
*/
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)
// Spark Streaming对接Kafka需要ssc,zookeeper,组,topic
val messages = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](
ssc,kafkaParams,topicsSet
)
// 自己去测试为什么要取第二个
messages.map(_._2).flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()
ssc.start()
ssc.awaitTermination()
}
}
5 集群:写Spark Streaming代码
// 依赖
groupId = org.apache.spark
artifactId = spark-streaming-kafka-0-8_2.11
version = 2.2.0
// Spark Streaming 代码
package com.imooc.spark
import kafka.serializer.StringDecoder
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
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)
// Spark Streaming对接Kafka需要ssc,zookeeper,组,topic
val messages = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](
ssc,kafkaParams,topicsSet
)
// 自己去测试为什么要取第二个
messages.map(_._2).flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()
ssc.start()
ssc.awaitTermination()
}
}
6 本地:运行Spark Streaming程序(需要传入brokers和topics参数)
// 运行一次后设置传入参数
hadoop000:9092 kafka_streaming_topic
6 集群:运行mvn命令打包,把jar包上传到集群中,运行spark-submit命令
// mvn打包命令
mvn clean package -DskipTests
// spark-submit命令
spark-submit \
--class com.imooc.spark.KafkaDirectWordCount \
--master local[2] \
--name KafkaDirectWordCount \
--jars /home/hadoop/lib/smj/spark-streaming-kafka-0-8-assembly_2.11-2.2.0.jar \
/home/hadoop/lib/smj/sparktrain-1.0.jar hadoop000:9092 kafka_streaming_topic
7 通过kafka-console-producer生产数据
$KAFKA_HOME/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic kafka_streaming_topic