1. 介绍

spark streaming去消费kafka消息相信是一种比较常见的情景。一般来说获取kafka消息的spark streaming流有以下两种:

  1. 基于Receiver的流(传统老方法)
  2. Direct Stream(推荐的新方法)

本文主要参考官方文档Spark Streaming + Kafka Integration Guide (Kafka broker version 0.8.2.1 or higher)Spark Streaming + Kafka Integration Guide (Kafka broker version 0.10.0 or higher)来比较下这两种流。另外也顺便提提支持kafka 0.10的新API有何不同。

2. Receiver-based Approach

Receiver是利用kafka的high-level consumer API来实现的。接收器接受的kafka数据会存放到spark executors当中。然后spark streaming会处理这些数据。

2.1 两种接收器

接收器根据是否需要返回消息接受确认,可以分为以下两种:

  1. Reliable Receiver : 例如kafka和flume都需要消费后的ack信息
  2. Unreliable Receiver : spark streaming处理kafka消息的API采用这种接收器,会导致消息丢失。

在Spark streaming中使用的是第二种接收器,为了防止消息丢失,可以开启Write Ahead Logs,然后异步保存kafka数据到这个写前日志中。这个Write Ahead Logs可以持久化存储到HDFS这种分布式存储上。通过这种方式可以避免数据丢失。

2.2 其他注意点

  1. topic partitions: kafka分区和RDD的分区没关系。KafkaUtils.createStream() 中增加topic相关联的分区只能增加一个receiver当中的消费者线程。并不能提升SPARK 并行处理RDD的效率。
  2. 通过多个接收器可以,可以创建一个跨group接受多个topic数据的DStream

3. Direct Approach (No Receivers)

这种方式按照batch来读取一定间隔的offset之间的所有消息(按我的理解,也就是Dstream是offset一个一个移动的,频繁的修改offset)。和前一种方法最大的区别,就是少了一个中间环节——receiver

这种方式主要有以下好处:

  1. 简化并行的问题:现在不用像第一种方法以后来合并多喝kafka stream流了。现在RDD的分区数和需要消费的分区数保持一致。方便调优了。也就是说提升并发消费的线程,也可以同时提升RDD处理能力。增加分区数和提升RDD并行处理能力、并发消费能力目标一致了。
  2. 高效: 现在的消息可靠性,可以利用kafka本身的能力来恢复,因为已经没有中间环节——接收器了。这样也就不需要做两次持久化,也不需要Write Ahead logs了,性能好了不少。
  3. Exactly-once semantics: Spark streaming和Zookeeper都会记录offset。但是这两者可能保持不一致,从而导致没法做到有且仅有一次的语义。现在这种“直接流”的方式直接不使用ZK来管理offset,而只交给SS来管理,这样避免不一致的问题。当然这样也会有缺点,如果你是监控ZK上的offset来了解消费情况的,那么现在就没法获取到了。当然解决办法也有,就是你SS处理好了,提交OFFSET的同时,也去写一下ZK。这个官网有例子,可以自己看。

4. 支持kafka0.10.x的Spark Streaming API

KAFKA0.10因为使用了新的CONSUMER API,所以这个新的Spark Streaming API自然是不向下兼容的。kafka 0.10.x和消费者关联的最重要改动之一就是不再采用ZK来管理offset了。

4.1 LocationStrategies

提供了一些消费的定位策略,其中还有预取数据的功能。

4.2 ConsumerStrategies

  1. 对消费者做了些抽象,方便spark重启之后根据check point信息获取一个配置好的消费者。
  2. 在主题订阅上,提供了更加细致的管理。比如从指定分区的指定OFFSET消费。

4.3 支持 SSL /TLS

做了些安全上的支持。确保SPARK 和 KAFKA通信的安全。