Spark streaming 和kafka 处理确保消息不丢失的总结redis
咱们前面的1到4 都在说 spark streaming 接入 kafka 消息的事情。讲了两种接入方式,以及spark streaming 如何和kafka协做接收数据,处理数据生成rdd的数据库
主要有以下两种方式缓存
基于receiver的方法采用Kafka的高级消费者API,每一个executor进程都不断拉取消息,并同时保存在executor内存与HDFS上的预写日志(write-ahead log/WAL)。当消息写入WAL后,自动更新ZooKeeper中的offset。
它能够保证at least once语义,但没法保证exactly once语义。缘由是虽然引入了WAL来确保消息不会丢失,但有可能会出现消息已写入WAL,但更新comsuer 的offset到zk时失败的状况,此时consumer就会按上一次的offset从新发送消息到kafka从新获取一次已保存到WAL的数据。这种方式还会形成数据冗余(WAL中一份,blockmanager中一份,其中blockmanager可能会作StorageLevel.MEMORY_AND_DISK_SER_2,即内存中一份,磁盘上两份),大大下降了吞吐量和内存磁盘的利用率。如今基本都使用下面基于direct stream的方法了。分布式
基于direct stream的方法采用Kafka的简单消费者API,大大简化了获取message 的流程。executor再也不从Kafka中连续读取消息,也消除了receiver和WAL。还有一个改进就是Kafka分区与RDD分区是一一对应的,容许用户控制topic-partition 的offset,程序变得更加可控。
driver进程只须要每次从Kafka得到批次消息的offset range,而后executor进程根据offset range去读取该批次对应的消息便可。因为offset在Kafka中能惟一肯定一条消息,且在外部只能被Streaming程序自己感知到,所以消除了不一致性,保证了exactly once语义。不过,因为它采用了简单消费者API,咱们就须要本身来管理offset。不然一旦程序崩溃,整个流只能从earliest或者latest点恢复,这确定是不稳妥的。源码分析
主要有两种方案:spa
2.1. 主要是 经过设计幂等性操做,在 at least once 的语义之上,确保数据不丢失设计
2.2. 在一些shuffle或者是集合计算的结果集中, 在 exactly-once 的基础上,同时更新 处理结果和 offset,这种状况下,通常都是使用事务来作。日志
现有的支持事务的,也就是传统的数据库了,对于一些缓存系统为了更简单更高效的访问,即便有事务机制,也设计的很是简单,或是只实现了部分功能,例如 redis 的事务是不能支持回滚的。须要咱们在代码中作相应的设计,来确保事务的正确执行。blog
即分布式RDD计算是如何和确保计算刚好计算一次的呢?后续会出一系列源码分析,分析 spark 是如何作分布式计算的。进程