Spark读取kafka数据的方式——Receiver和Direct

  spark Streaming从kafka中读取数据的方式分有两种,Receiver读取和Direct读取。

Receiver方式
​   Receiver是使用kafka的高层次Consumer API来实现的,Receiver从kafka中获取数据存储在Spark Executor的内存之中,当Spark Streaming启动job时,job会去处理那些数据。由于它是依靠底层来实现的,数据写在缓存中,在默认配置的情况下,可能会因为底层发生故障从而导致数据的丢失。

​   因此,要想保证数据可靠性,实现数据的零丢失,就需要启动高可用机制。首先在启动高可用之前,必须要启用Spark Streaming的预写日志机制(Write Ahead Log,简称WAL),该机制会同步地将接受到的kafka数据写入到分布式文件系统HDFS上的预写日志中。所以,即使底层节点出现了问题,也可以使用预写日志中的数据进行恢复。

注意点
​  1、kafka中topic的partition与Spark中RDD的partition没有关系,在使用KafkaUtils.createStream()中,提高partition的数据只会增加Receiver。也就是说,读取kafka中的topic partition的线程数量,不会增加Spark处理数据的并行度。

  ​2、可以创建多个kafka输入DStream,使用不同的consumer group和topic,来通过多个receiver并行接收数据。

  ​3、如果基于容错的文件系统,比如HDFS启用了预写入日志机制,接收到的数据都会被复制一份到预写入日志中。所以在kafkaUtils.createStream()中,设置的持久化级别是StorageLevel.MEMORY_DISK_SER.

Direct方式
​   Receiver是在Spark1.3以后的版本引入的,这种机制可以确保更加健壮的机制。这种方式会周期性地查询kafka,来获得每个topic的最新的offset,从而定义每个batch的offset的范围。当处理数据的job启动时,就会使用kafka的简单consumer api来获取kafka指定offset。
Direct的优点

  读取速度快:直接到kafka拿数据消费,不会存到内存再消费。
  简单并行读取:如果要读取多个partition,不需要创建多个输入kafka流并将其合并。使用directStream,Spark Streaming将创建于使用kafka分区一样多的RDD分区,这些分区将全部从kafka并行读取数据。所以在kafka和RDD分区之间有一对一的映射关系。

  ​ 高性能:如果要保证零数据丢失,在基于receiver的方式中,需要开启WAL机制,由于数据需要被复制两份(kafka自己本身的可靠机制会复制一份数据,还有一份需要复制到WAL中),所以效率比较底下。而基于Direct的方式,不依赖Receiver,也不需要开启WAL机制,只要kafka中做了数据的复制,就可以通过kafka的副本进行恢复,可以减少复制次数提高性能。

​   正好一次语义(一次且仅一次事务机制):Receiver中使用kafka的高级API在Zookeeper中存储消耗过的偏移量(offset),这是kafka传统的消费数据的方式。这种方法(结合提前写入日志)虽然可以保证数据的零丢失(即至少一次语义),但是在有些情况下可能导致有些记录被消费两次。出现这种情况的原因是Spark Streaming可靠接收到的数据与Zookeeper跟踪的偏移之间不一致。
  基于direct的方式,使用kafka的简单API,Spark Streaming自己就负责追踪消费的offset,并保存到checkpoint中,Spark Streaming自己跟踪偏移量,这样就消除了Spark Streaming与Zookeeper与kafka之间数据的不一致性。因此,Spark Streaming每次记录都会在发生故障的情况下有效地收到一次。spark自己一定是同步的,因此可以保证数据是消费一次且仅一次消费。为了实现输出结果的一次语义,将数据保存到外部数据存储区的输出操作必须是等幂的,或者是保存结果和偏移量的原子事物。由于数据消费偏移量是保存在checkpoint中,因此,后续想使用kafka高级API消费数据,需要手动更新zookeeper中的偏移量。

你可能感兴趣的:(Spark)