Spark对Kafka两种连接方式的对比——Receiver和Direct

在知乎 Flink 取代 Spark Streaming 的实战之路中,提到Spark对Kafka两种连接方式的对比——Receiver和Direct

因此下面对两种方式进行详细说明一下。


Receiver方式

Receiver:接收器模式是使用Kafka高级Consumer API实现的。与所有接收器一样,从Kafka通过Receiver接收的数据存储在Spark Executor的内存中,然后由Spark Streaming启动的job来处理数据。然而默认配置下,这种方式可能会因为底层的失败而丢失数据(请参阅接收器可靠性)。如果要启用高可靠机制,确保零数据丢失,要启用Spark Streaming的预写日志机制(Write Ahead Log,(已引入)在Spark 1.2)。该机制会同步地将接收到的Kafka数据保存到分布式文件系统(比如HDFS)上的预写日志中,以便底层节点在发生故障时也可以使用预写日志中的数据进行恢复。

单点读数据,读到的数据会缓存到executor的cache里,增大了内存使用的压力。

在Receiver的方式中,使用的是Kafka的高阶API接口从Zookeeper中获取offset值,这也是传统的从Kafka中读取数据的方式,但由于Spark Streaming消费的数据和Zookeeper中记录的offset不同步,这种方式偶尔会造成数据重复消费。

特点

在spark的executor中,启动一个接收器,专门用于读取kafka的数据,然后存入到内存中,供sparkStreaming消费

1、为了保证数据0丢失,WAL,数据会保存2份,有冗余

2、Receiver是单点读数据,如果挂掉,程序不能运行

3、数据读到executor内存中,增大了内存使用的压力,如果消费不及时,会造成数据积压

如下图:

Spark对Kafka两种连接方式的对比——Receiver和Direct

详细图示:

Spark对Kafka两种连接方式的对比——Receiver和Direct

还有几个需要注意的点:

1、Kafka中topic的partition与Spark Streaming中生成的RDD的partition无关,因此,在KafkaUtils.createStream()中,增加某个topic的partition的数量,只会增加单个Receiver消费topic的线程数,也就是读取Kafka中topic partition的线程数量,它不会增加Spark在处理数据时的并行性。

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

3、如果已使用HDFS等复制文件系统启用了“预读日志”,则接收的数据已在日志中复制。因此,输入流的存储级别的存储级别StorageLevel.MEMORY_AND_DISK_SER(即,使用KafkaUtils.createStream(..., StorageLevel.MEMORY_AND_DISK_SER))。


Direct方式

Direct:直连模式,在spark1.3之后,引入了Direct方式。不同于Receiver的方式,Direct方式没有receiver这一层,其会周期性的获取Kafka中每个topic的每个partition中的最新offsets,并且相应的定义要在每个batch中处理偏移范围,当启动处理数据的作业时,kafka的简单的消费者api用于从kafka读取定义的偏移范围 。其形式如下图:

Spark对Kafka两种连接方式的对比——Receiver和Direct

这种方法相较于Receiver方式的优势在于:

1、简化的并行:在Receiver的方式中我们提到创建多个Receiver之后利用union来合并成一个Dstream的方式提高数据传输并行度。而在Direct方式中,Kafka中的partition与RDD中的partition是一一对应的并行读取Kafka数据,这种映射关系也更利于理解和优化。

2、高效:在Receiver的方式中,为了达到0数据丢失需要将数据存入Write Ahead Log中,这样在Kafka和日志中就保存了两份数据,浪费!而第二种方式不存在这个问题,只要我们Kafka的数据保留时间足够长,我们都能够从Kafka进行数据恢复。

3、精确一次:在Receiver的方式中,使用的是Kafka的高阶API接口从Zookeeper中获取offset值,这也是传统的从Kafka中读取数据的方式,但由于Spark Streaming消费的数据和Zookeeper中记录的offset不同步,这种方式偶尔会造成数据重复消费。而第二种方式,直接使用了简单的低阶Kafka API,Offsets则利用Spark Streaming的checkpoints进行记录,消除了这种不一致性。

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

直连模式特点:tatch time 每隔一段时间,去kafka读取一批数据,然后消费

         简化并行度,rdd的分区数量=topic的分区数量

         数据存储于kafka中,没有数据冗余

         不存在单点问题

         效率高

         可以实现仅消费一次的语义 exactly-once语义

详细图示:

Spark对Kafka两种连接方式的对比——Receiver和Direct