方法一 createStream基于Receiver
这种方法基于Receiver来接收数据,使用kafka高级自定义API实现。和所有的receivers一样,这种接收方式通过Receiver从kafka接收数据存储到Spark executors节点,然后运行job通过Spark Streaming处理数据
然而,默认配置下,这种方法在执行失败时会丢失数据(查看Receiver可靠性)。为保证零数据丢失,你必须在SparkStreaming中额外启用Write Ahead Logs,同步地把所有接收到的kafka数据存储到位于分布式系统(e.g HDFS)上的Write Ahead Log里面, 来保证所有的数据在失败后能够恢复,可以在streaming程序指导开发模块中查看更多关于Write Ahead Log的细节
接下来,我们讨论如何使用:
链接:在使用SBT/Maven项目的scala/java应用程序中引入包
groupId = org.apache.spark
artifactId = spark-streaming-kafka_2.10
version = 1.3.1程序:在streaming应用程序代码中,像下面一样导入KafkaUtils和创建一个输入流DStream
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 中Topic分区和Spark Streaming中RDDS分区没有任何关系,所以在KafkaUtils.createStream() 中增加分区数仅仅只是增加一个Receiver里该topic下消费数据的线程数,而不会增加Spark处理数据的并行数。
能够用不同的group和topic来创建多个Kafka输入流DStream,用多个Receiver并行的接收数据
如果你已经启用Write Ahead Log(e.g HDFS上),接收的数据已经被复制到log中。此后,输入流以StoragelLevel.MEMORY_AND_DISK_SER的优先级来存储
开发:所有的Spark应用程序中,spark-submit被用来提交运行你的程序。然而,有一些小细节会不同于Scala/Java/Python程序
在Scala和Java程序中,如果你使用SBT或者Maven来管理项目。确保spark-streaming-kafka_2.10 和它的依赖包,spark-core_2.10 以及 spark-streaming_2.10已经添加到了程序JAR包中。然后可以使用spark-streaming_2.10来运行程序
方法二 creatDirectStream直接访问 (No Receivers)
在Spark1.3中介绍了一种新的不用Receiver的直接访问方法来保证端到端的数据可靠性。不使用Receiver来接收数据,这种方法会定期的查询Kafka上每个topic和partition最近的offsets,根据自定义的offset范围来分批处理数据。当jobs处理程序运行,会调用Kafka的用来读取自定义offset范围的API。这个新特性仅仅在Spark1.3的Scala和Java及以后版本支持。
这个方法相比基于Receiver的方法一有以下优点:
简化并行:不需要创建多个kafka输入流然后union他们。在直接访问方法中,Spark Streaming会创建和Kafka分区一样多的RDD分区,实现并行从Kafka读取数据。在Kafka和RDD分区实现一对一映射,有助于理解和一致性
效率更高:前一种方法中为了防止数据丢失,会请求将数据存储到Write Ahead Log当中,会产生数据复制。实际上,当数据复制两次,一次是Kafka,一次是Write Ahead Log是相当无效率的。第二种方法因为没有Receiver,因此也不需要Write Ahead Logs,解决了这个问题。
一次语义:第一种方法中使用Kafka的高级API来存储在Zookerper里定义的offsets。这种方式在失败后有可能会重复读取数据。这是由于Spark Streaming实际接收的数据和通过Zookeeper追踪的offsets不一致。因此,第二种方法中,我们使用简单的Kafka API而没有使用Zookeeper和offsets追踪,这样消除了Spark Streaming和Zookeeper/Kafka之间的不连续。每条记录,即使是失败后也只能被读取一次。
如何使用:
链接:这个方法现在仅仅只支持Scala/Java程序。在你的SBT/Maven项目配置文件中,引入如下包
groupId = org.apache.spark
artifactId = spark-streaming-kafka_2.10
version = 1.3.1编码:在代码中导入KafkaUtils,创建一个DStream如下
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 parameters,你需要指定metadata.broker.list 或bootstrap.servers。默认情况下,会从每个Kafka分区最近的offset开始读取,如果你在Kafka parameter中设置 auto.offset.reset=smallest,就会从最小的offset开始读取
你也可以向KafkaUtils.createDirectStream传入其他参数,来从任意的offset开始读取。而且,如果你想自定义消费的offsets,你可以如下:
directKafkaStream.foreachRDD { rdd =>
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges]
// offsetRanges.length = # of Kafka partitions being consumed
…
}开发: 和前一种方法一样
更多Spark知识分享请关注我的新blog
https://hywelzhang.github.io/