一、Kafka 消费者如何管理 offset
我之前有写一篇kafka Consumer — offset的控制
如果你对于这方面的知识还不太清楚,
建议你去看一下,
毕竟理解了Kafka的消费者,
你才能更好的使用SparkStreaming结合Kafka。
二、Spark Streaming On Kafka 如何管理 offset
1. 自动提交
1.1 使用
这个没什么好讲的,
应该是最简单的方式,
我们只需要在使用的时候,
确保 enable.auto.commit=true
就行,
那么Spark每次拉取到Kafka的数据后,
offset会即刻保存。
1.2 缺点
这种方式的缺点很明显,
当我们拉取到数据之后,
offset就被提交了,
如果后续我们数据处理失败,
下次再去读取,
将会从offset的地方进行读取,
这样失败的数据就会被认为已经成功处理,
也就发生了数据丢失。
不过这种方式在一些对数据要求不是很精准的场景比较好用,
因为使用起来是真的非常简单,
所以如果你不 Care 这一点点的数据丢失,
那就果断用起来吧!!!
2. 手动提交
既然自动提交会造成数据缺失,
那么我们有什么办法不造成数据缺失吗?
那就是手动提交了。
下面我们来聊聊手动提交的一些方式。
2.1 使用
首先确保 enable.auto.commit=false
,
当我们从kafka拉取到数据,
就不会再自动提交offset了,
这时候的offset就可以任由我们自己控制,
一个很典型的方式就是,
当Spark处理完一个批次的数据,
我们把这个offset 提交到 kafka。
2.2 手动提交容易出现的问题
我们可以想象,当我们处理完数据后,
我们才对offset进行了提交,
这也意味着如果数据处理失败,
我们可以选择不提交offset,
下次我们还是可以从kafka读到该批数据,
然后再进行处理,
这时候自然是不会存在数据丢失的,
但是如果我们上次处理的这批数据成功一半,失败一半,
那么成功的那一半数据就会被重复消费了。
2.3 那么我们能否做到 EOS 的处理
使用SparkStreaming想要做到EOS其实还是挺难的,
但是也并非不可以,下面我们来看看如何做到EOS。
首先我们知道,
使用手动消费我们的数据是很容易做到at least once
语义的,
所以要做到 EOS,
我们只需要关注如何做到处理的数据不重复即可。
-
2.3.1 通过事务来实现
很多时候,我们处理完的数据是要放到一些数据库的,
如果这个数据库支持事务,
那么我们可以把输出的结果 和 需要保存的offset 打包,
当成一个事物提交到该数据库,
这样我们就借助了数据库的事务完成了EOS语义。这种方式就比较依赖于第三方数据库了,
如果落地的数据库对事物支持不友好,
那么这种方式就不太行了。 -
2.3.2 通过输出幂等来实现
我们既然已经做到了不丢数据的处理,
那么我们主需要保证输出的数据不重复,
也就可以做到 EOS了,
一个很典型的例子就是通过ID去重,
比如订单数据,我们都有唯一的订单号,
那么输出数据的时候看一下这个订单是否处理过,
处理过则不再处理,
这样也是可以实现的,这种方式在一些线性处理的场景好用,
但是一旦涉及到数据需要聚合,
可能就不是那么好实现了。 -
2.3.3 通过输出文件来实现
我们很多时候的重复可能是来源于Spark的重试机制,
比如Task 重试,那么这个Task的部分数据可能就会重复消费,
但是一般,我们不会关闭这个机制。
那么我们如何来规避这种重复消费呢?其实我们应该可以发现,
Spark是有一些输出幂等的算子的,
比如saveAsTextFile
,
不管过程是否有重试,
其结果数据都是幂等的。
这样也是可以做到EOS,
不过这种方式的限制也很大,
因为既然是实时数据,
这个时间是否能满足也是个问题
基本都是说的一些理论的东西
不过我这些实现起来也都不难,
我也就不多赘述了,
如果有需要代码或者例子的,
可以留言,
后续也许会出一篇关于实现的文章。