本文主要探讨关于spark streaming集成kafka的容错处理和断点续传操作。
spark streaming有两种容错机制:
- spark自带的checkpoint
- 使用Kafka direct自行维护offset
关于两种方式的具体实现和优缺点下面会详细介绍,这里是建议使用第二种方式更灵活一些。
checkpoint
checkpoint是spark streaming自带的一种检查点机制,可以通过一些特殊配置把输入数据和计算过程中的数据存储在可靠的文件系统中(比如hdfs或s3)。
checkpoint作用
checkpoint主要有两个作用:
- 可以保存计算过程中的状态,在发生失败时可以控制回溯到什么程度,而不用重新进行计算。
- 驱动器容错,在驱动器崩溃重启后,控制从什么位置继续读取数据。
checkpoint存储的数据
checkpoint主要存储三种类型数据:
- 元数据信息,主要包括:
- streaming应用程序的配置
- 计算过程中一系列Dstream操作
- 没有完成的批处理,在运行队列中的批处理但是没有完成
- 消费数据的偏移量
- 编译后的执行程序(jar文件)序列化后的二进制文件
checkpoint的弊端
最开始我也打算使用这种spark自带的checkpoint方式,主要是方便。不过在测试过程中发现,再次启动程序的时候一直报错,上网查了一下,报错原因在上诉提到了,checkpoint会把执行程序的jar文件序列化成二进制文件保存起来。如果涉及到迭代,或是程序代码有变动,checkpoint保存的还是原来的代码,所以就有报错,这也是checkpoint的弊端。
针对这种问题,spark官网给出了2种解决方案:
- 在生产环境代码迭代,旧的不停机,新的程序继续启动。
- 停机的时候记录下最后处理的偏移量,新程序启动的时候从偏移量开始继续工作,从而达到不丢数据。
第一种解决方案,显然不可靠,没法保证数据不丢和数据重复。第二种方式也是下面咱们要谈论的,如何自己维护偏移量。官网只是提供了思路,并没有具体方案。
使用Kafka direct自行维护offset
在这之前先简单介绍一下spark streaming集成kafka的两种方式。
1、基于接收者的方式
streaming中调用方法: KafkaUtils.createStream
方式: 采用push方式,由kafka的topic将数据推向spark
使用API: 使用的是kafka高级消费者API
效果: kafka将数据推到spark执行节点中并储存起来,然后由Spark Streaming启动作业来处理这些程序。
弊端: 因为Spark Streaming的接收数据和数据计算是两个独立的线程来是实现的(这是为什么local[n],n必须大于等于2的原因)。所以没有保障spark接收到kafka的数据全部都被处理成功,失败的数据可能就会丢失。要避免只能通过记录日志。
2、直连方式(direct)
streaming中调用方法: KafkaUtils.createDirectStream
方式: 采用pull方式,由spark向kafka拉取数据
使用API: 使用的是kafka低级消费者API
效果: 这种方式不是使用接收器接收,而是saprk每次拉取数据先去kafka中获取上一次拉取的偏移量。根据偏移量获取数据后,再进行处理。
优势1: 强大的端到端的保障,这种方式内部实现kafka的partition直接对接RDD的partition,就是说kafka里有多少个分区,RDD就有多少个分区,分区直接是一对一的对应关系,从而实现并行读取数据。(官方文档这么介绍的,并且我也验证了确实是分区一一对应)
优势2: 这是方式不会提交偏移量给zookeeper来维护(这里网上道友这么说的,有待考察,我觉得是0.10.x版本之后由kafka来维护偏移量,zookeeper没有偏移量并不是代表没有提交)。而是由Spark Streaming自己来维护偏移量。这也就解决了上面第一种方法提到的,zookeeper偏移量跟Spark Streaming处理的不一致的问题。能够有效的保障数据丢失和重复的问题。
*第二种方式是spark1.3以后引入的,一般情况下都是使用的第二种方式,比较灵活、高效。
kafka高级消费API和低级消费API区别
kafka的consumer有两种消费方式:
- push,采用推的方式将数据推给消费者。优点是延迟小,因为不需要等待consumer处理。缺点是如果消费能力小于生产能力,这种方式会压垮consumer,容易丢数据。
- pull,采用消费者主动去拉数据的方式。优点是可以根据consumer的消费能力去自行控制一次pull多少数据出来。缺点是延迟可能较第一种偏大,但对kafka整体来说,延迟都是毫秒级的,无伤大雅,而且可以通过配置优化去降低其中的延迟,kafka的好处也是非常灵活,可以根据不同的业务场景修改不同的配置,高吞吐和低延迟必然冲突。
高级消费API
可以理解成对低级API的高度封装,采用自动提交偏移量的方式。这种方式代码简洁,管理方便,使用简单。但对kafka的控制和灵活性非常低。有数据丢失和重复可能。
低级消费API
接口代码相对高级消费API复杂,但灵活性比较高。比如可以选择手动提交偏移量来避免数据丢失和重复。手动提交可以选择同步提交、异步提交和同步异步组合提交三种方式,非常灵活,可以根据场景任意选择。不过这块代码逻辑就要自己去实现了。
前面介绍了kafka的消费者情况和spark streaming消费kafka的方式,可以看出使用
Kafka direct更适合spark streaming整和kafka的场景。不过即使采用了direct依然保证不了数据的精准一次处理,因为接收和处理都是单独的线程。所以我们要在spark streaming处理逻辑中加入记录偏移量的程序。
这样在在系统迭代的过程中,或者是服务崩溃的情况下,记录最后一次处理的偏移,当下次重启后,从记录的偏移量继续消费,从而实现断点连续。
自行维护offset要比spark自带的checkpoint更好一些,更加灵活、安全。
更多文章关注公众号
更多:Spark专栏
——————————————————————————————————
作者:桃花惜春风
转载请标明出处,原文地址:
https://blog.csdn.net/xiaoyu_BD/article/details/82897282
如果感觉本文对您有帮助,您的支持是我坚持写作最大的动力,谢谢!