对于Spark Streaming程序而言,一旦运行起来后,就会不断的从数据流中消费数据,按照Batch间隔生成BatchRDD进行处理,即处于7*24小时运行的状态,除非我们主动将其停止或者遇到异常退出。所谓Graceful Shutdown,即优雅的将Spark Streaming程序停止,本文将重点探讨三点(写作背景:Spark 2.2):
- 为什么需要Graceful Shutdown?
- 如何触发Graceful Shutdown?
- Graceful Shutdown过程是怎样的?
为什么需要Graceful Shutdown
考虑使用Graceful Shutdown的前提是,业务对数据的准确性要求很高,不允许数据丢失。如果这个前提不成立,其实可以不使用Graceful Shutdown,直接采用"yarn -kill application_id"即可。
Spark Streaming是基于micro-batch机制工作的,程序在运行中,由Receiver负责从Stream中不断读取数据(比如1秒读取一次),当Batch Interval到达时,会将收下来的数据组合成一个新的BatchRDD来处理。在这个过程中,如果程序出现异常退出,可能会导致正在处理的BatchRDD中的数据或者已经接收下来但是还没有生成BatchRDD的数据丢失。为了避免数据丢失,Spark Streaming引入了Checkpoint和WAL机制,将程序运行的上下文信息和接收的数据持久化到磁盘,从而可以在异常退出后能恢复到上次继续处理。

Checkpoint机制保证了数据不丢失,但是为程序更新带来了隐患。因为保存下来的数据中包含了当前程序运行的上下文信息,将程序停止、更换新的代码、再重新启动起来时,轻则更新的代码没有生效,重则程序报错无法运行。因此,更新Spark Streaming程序代码时,必须将Checkpoint清除掉,可是这样又引入了数据丢失的问题。
Graceful Shutdown便是为解决这样的问题而生。通过Graceful Shutdown,首先将Reciever关闭,不再接收新数据,然后将已经收下来的数据都处理完,最后再退出。这样一来,Checkpoint就可以被安全删除了。
如何触发Graceful Shutdown
关于如何触发Graceful Shutdown,Spark官方文档并没有给出具体的方法。从代码来看,是通过Hadoop的ShutdownHook来实现的,StreamingContext在初始化时会注册一个Hook函数。因此,理论上一切可以触发Shutdown Hook的方法都可以触发Spar