Loading

Spark-Streaming和Kafka集成指南

Kafka是一个消息发布-订阅系统。Spark-Streaming是spark核心API的扩展,它可以采集Kafka, Flume, Twitter, ZeroMQ, Kinesis, 或TCP sockets等多种数据源进行处理,是一个高可用可伸缩高通量的实时数据计算工具。

Spark Streaming对接Kafka有两种方式:老方法使用接收器和Kafka的API,新方法(spark1.3以后加入)不使用接收器直接从Kafka接收数据,它们有不同的变成模型、性能特性、语法规则。

方法1:基于接收器的方式(Receiver-based Approach)

这种方法使用一个接收器接收数据。接收方使用Kafka高级消费者API实现。通过接收器从Kafka接收到的数据存储在Spark executors中,然后Spark Streaming启动jobs处理数据。然而在默认配置的情况下这种方法可能丢失数据。为了防止数据丢失,必须另外启用Spark Streaming写日志记录,在分布式文件系统(如HDFS)上同步保存所有Kafka接收到的数据记录已便在故障时恢复数据。

接下来讨论如何在你的spark streaming程序中使用这种方式。

1.链接:如果使用Maven/SBT开发java/scala项目需要把下面的链接加到streaming项目中:

1  groupId = org.apache.spark
2  artifactId = spark-streaming-kafka_2.10
3  version = 1.6.3

2.程序设计:在streaming程序代码中,导入kafkaUtils并创建输入流Dstream:

//java

import org.apache.spark.streaming.kafka.*; JavaPairReceiverInputDStream<String, String> kafkaStream = KafkaUtils.createStream(streamingContext, [ZK quorum], [consumer group id], [per-topic number of Kafka partitions to consume]); //scala import org.apache.spark.streaming.kafka._

val kafkaStream
= KafkaUtils.createStream(streamingContext,
[ZK quorum], [consumer group id], [per
-topic number of Kafka partitions to consume])

要记住:

  • Kafka中的主题分区与Spark Streaming中生成的RDD分区不相关。因此,增加主题专用分区KafkaUtils.createStream()的数量仅增加了使用单个接收器内消耗的主题的线程数。它不会增加Spark在处理数据时的并行性。有关更多信息,请参阅主文档。

  • 可以创建多个Kafka输入DStream,具有不同的组和主题,用于使用多个接收器并行接收数据。

  • 如果已使用像HDFS这样的复制文件系统启用了“写入前端日志”,则所接收的数据已被复制到日志中。因此,输入流的存储级别的存储级别StorageLevel.MEMORY_AND_DISK_SER(即使用 KafkaUtils.createStream(..., StorageLevel.MEMORY_AND_DISK_SER))。

3.部署:和其它spark程序一样,使用spark-submit来提交任务。在scala/java程序中如果使用SBT/Maven创建的项目需要确保spark-streaming-kafka_2.10和你是用的依赖都打在jar包中。

方法2:直连方式(Direct Approach)

spark1.3引入了这种直连的方式,确保更强的端到端的保证。这种方式不使用接收器,而是定期查询Kafka在每个topic+partition中的最新偏移量,并相应的定义在每个批处理中要处理的偏移范围。当处理数据的任务被启动时,kafka消费者API就去读取kafka定义的偏移范围。

这种方法比基于接收器的方法具有以下优点(即方法1)

  • 简化并行度:无需创建多个输入kafka stream并联合它们。随着directStream,Spark Streaming将创建尽可能多的RDD分区,因为有Kafka分区要消耗,这将分别从Kafka读取数据并行。所以在Kafka和RDD分区之间存在一对一的映射,这更容易理解和调整。

  • 效率:在第一种方法中实现零数据丢失需要将数据存储在写入前端日志中,进一步复制数据。这实际上是低效的,因为数据有效地被复制了两次 - 一次是由卡夫卡(Kafka),另一次是通过写入前端日志。第二种方法消除了问题,因为没有接收器,因此不需要写入前端日志。只要您有足够的卡夫卡保留,可以从卡夫卡恢复邮件。

  • 完全一次的语义:第一种方法使用Kafka的高级API在Zookeeper中存储消耗的偏移量。这通常是从卡夫卡消费数据的方式。虽然这种方法(结合写入日志)可以确保零数据丢失(即至少一次语义),但是在某些故障下,一些记录可能会被消耗两次的可能性很小。这是因为Spark Streaming可靠接收的数据与Zookeeper跟踪的偏移量之间的不一致。因此,在第二种方法中,我们使用不使用Zookeeper的简单Kafka API。Spark Streaming在其检查点内跟踪偏移量。这消除了Spark Streaming和Zookeeper / Kafka之间的不一致,因此,尽管出现故障,每个记录都有效地被Spark Streaming收到。

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

1.链接:仅在Scala / Java应用程序中支持此方法。将SBT / Maven项目与以下工件链接

 groupId = org.apache.spark
 artifactId = spark-streaming-kafka_2.10
 version = 1.6.3

2.编程:在streaming程序代码中,导入KafkaUtils并创建输入流DStream,如下所示:

//java

 import org.apache.spark.streaming.kafka.*;

 JavaPairReceiverInputDStream<String, String> directKafkaStream = KafkaUtils.createDirectStream(streamingContext,
         [key class], [value class], [key decoder class], [value decoder class],
         [map of Kafka parameters], [set of topics to consume]);

//scala

 import org.apache.spark.streaming.kafka._

 val directKafkaStream = KafkaUtils.createDirectStream[
     [key class], [value class], [key decoder class], [value decoder class] ](
     streamingContext, [map of Kafka parameters], [set of topics to consume])

在Kafka参数中,必须指定metadata.broker.list或者bootstrap.servers。默认情况下,它将从每个Kafka分区的最新偏移开始消耗。如果将auto.offset.resetKafka参数中的配置设置为smallest,那么它将从最小的偏移量开始消耗。

3.部署:和方法1相同。

posted @ 2017-08-02 17:06  fuos  阅读(511)  评论(0编辑  收藏  举报