Spark Streaming 解决这 4 个问题的不同 focus,可以将 Spark Streaming 划分为四个大的模块:
模块 1:DAG 静态定义
模块 2:Job 动态生成
模块 3:数据产生与导入
模块 4:长时容错
模块 1:DAG 静态定义
2.2 模块 2:Job 动态生成
现在有了DStreamGraph和DStream,也就是静态定义了的计算逻辑,下面我们来看 Spark Streaming 是如何将其动态调度的。
在 Spark Streaming 程序的入口,我们都会定义一个 batchDuration,就是需要每隔多长时间就比照静态的DStreamGraph来动态生成一个 RDD DAG 实例。在 Spark Streaming 里,总体负责动态作业调度的具体类是JobScheduler,在 Spark Streaming 程序开始运行的时候,会生成一个JobScheduler的实例,并被 start() 运行起来。
JobScheduler有两个非常重要的成员:JobGenerator和ReceiverTracker。JobScheduler将每个 batch 的 RDD DAG 具体生成工作委托给JobGenerator,而将源头输入数据的记录工作委托给ReceiverTracker。
JobGenerator维护了一个定时器,周期就是我们刚刚提到的 batchDuration,定时为每个 batch 生成 RDD DAG 的实例。具体的,每次 RDD DAG 实际生成包含 5 个步骤:
(1)要求ReceiverTracker将目前已收到的数据进行一次 allocate,即将上次 batch 切分后的数据切分到到本次新的 batch 里;
(2)要求DStreamGraph复制出一套新的 RDD DAG 的实例,具体过程是:DStreamGraph将要求图里的尾DStream节点生成具体的 RDD 实例,并递归的调用尾DStream的上游DStream节点……以此遍历整个DStreamGraph,遍历结束也就正好生成了 RDD DAG 的实例;
(3)获取第 1 步ReceiverTracker分配到本 batch 的源头数据的 meta 信息;
(4) 将第 2 步生成的本 batch 的 RDD DAG,和第 3 步获取到的 meta 信息,一同提交给JobScheduler异步执行;
(5) 只要提交结束(不管是否已开始异步执行),就马上对整个系统的当前运行状态做一个 checkpoint。
DStream有一个重要而特殊的子类ReceiverInputDStream:它除了需要像其它DStream那样在某个 batch 里实例化RDD以外,还需要额外的Receiver为这个RDD生产数据!
具体的,Spark Streaming 在程序刚开始运行时:
(1) 由Receiver的总指挥ReceiverTracker分发多个 job(每个 job 有 1 个 task),到多个 executor 上分别启动ReceiverSupervisor实例;
(2) 每个ReceiverSupervisor启动后将马上生成一个用户提供的Receiver实现的实例 —— 该Receiver实现可以持续产生或者持续接收系统外数据,比如TwitterReceiver可以实时爬取 twitter 数据 —— 并在Receiver实例生成后调用Receiver.onStart();
注意到这里采用的是完整 checkpoint 的方式,和之前的 WAL 的方式都不一样。Checkpoint通常也是落地到可靠存储如 HDFS。Checkpoint发起的间隔默认的是和batchDuration 一致;即每次 batch 发起、提交了需要运行的 job 后就做Checkpoint,另外在 job 完成了更新任务状态的时候再次做一下Checkpoint。
这样一来,在 driver 失效并恢复后,可以读取最近一次的Checkpoint来恢复作业的DStreamGraph和 job 的运行及完成状态。
模块长时容错保障方式
模块 1-DAG 静态定义driver 端定时对 DStreamGraph 做 Checkpoint,来记录整个 DStreamGraph 的变化
模块 2-job 动态生成driver 端定时对 JobScheduler 做 Checkpoint,来记录每个 batch 的 job 的完成情况
模块 3-数据产生与导入driver 端源头块数据的 meta 信息上报 ReceiverTracker 时,写入 WAL
模块 3-数据产生与导入executor 端对源头块数据的保障:(1) 热备;(2) 冷备;(3) 重放;(4) 忽略
总结一下“模块4:长时容错”的内容为上述表格,可以看到,Spark Streaming 的长时容错特性,能够提供不重、不丢,exactly-once 的处理语义。