最近在考虑Spark在消费Kafka 分区数据的过程中究竟反生了什么? 因为比较疑惑现有系统架构会不会遭遇这方面的瓶颈,遂决定去搞一把,一探究竟.
关于Kafka做一下简短的总结,Kafka可参考附件1:
- 多个TOPIC分布在多个Broker中
- 每个TOPIC的数据以分区的方式分布在多个Broker中
- 一个分区同时只能被一个Consumer消费
- 同一个TOPIC允许被不同的Group重复消费,Group内不允许重复消费
Spark接入Kafka数据的两种方式Receiver-based && Direct Approach. 各有特点.
Receiver-based,基于接收器的kafka数据消费,
- API示例如下
val kafkaStream = KafkaUtils.createStream(streamingContext, [ZK quorum], [consumer group id], [per-topic number of Kafka partitions to consume])
- 概述
- KAFKA高阶API实现,因而编程实现简单.
- 接收器接负责收数据存储到Sparnk 执行器,可能是内存或者磁盘
- 默认配置下潜在的数据丢失风险,可以启用客户端日志特性,该操作将对消费的数据进行以日志文件形式进行存储进而避免依赖于ZK的数据消费异常
- 点晴
- 基于接收器的Kafka数据消费Kafka分区与RDD分区之间没有关联,进而参数[per-topic number of Kafka partitions to consume] ,实际上只是增加了接收器接收数据的并行度而并没有提高Saprk 处理数据的并行度.
- 可以使用多个Reciver来并行消费不同Topic 及不同Group下的数据
- 启用日志特性需要指定数据的存储级别,KafkaUtils.createStream(..., StorageLevel.MEMORY_AND_DISK_SER)
Direct Approach,直接获取数据
- 概述
- 一种端对端的数据消费策略,一个Kafka分区对应一个RDD分区.
- 定期的快速扫描Kafka中每个Partion 及Topic 的最新Offsets以确定当前批次的数据偏移范围,该过程使用低阶API来实现
- 优势
- 简化的并行度,基于DirectStream SparkStream将创建多个RDD分区去消费Kafka分区数据
- 效率上的提升,客户端Offsets不再依赖于ZK存储的Offsets而改由Spark checkPoint 进行跟踪,每次取数据直接使用偏移获取
- 一次消费保证, Offsets 不在依赖于ZK ,排除了ZK Offsets可能不同步的情况,消除了 Spark和Kafka之间的不一致性,意味着数据的消费由Spark掌控,只要数据存在于Kafka即可.
- 弊端
- offsets由Spark在checkpoint中维护不自动更新ZK中的Offsets,导致一些依赖于ZKOffsets监控的工具失效.
- 配置项目
- auto.offset.reset 消费者首次连接时offsets的生成策略,largest/smallest,分别代表当前最新消息位置/最早消息位置.
- spark.streaming.kafka.* 其它可配置的参数
- spark.streaming.kafka.maxRetries 最大重试次数
- spark.streaming.kafka.maxRatePerPartition 每秒中消费的最大条数 ,该参数对于从数据积压中进行恢复有显著调节作用.
附件1:kafka 知识图解