Spark Streaming checkpoint wal

简述

Spark Streaming的应用一般是从上游接到数据,进行处理,然后将结果输出。这是一个流式的过程,持续不断的接收、持续不断的输出,流式过程中的每一个环节(输入、处理、输出)出错,都可能会造成数据的丢失,这在生产中是不能容忍的。

这相当于是一个可靠性的问题,当出错时可以通过上游或者spark streaming自身来保证。

上游一般是kafka、rocketmq等消息队列,队列都有偏移量消费位点类似的概念,我们可以将其重置来保证数据的可靠性。

spark streaming自身提供了checkpoint、wal机制来保证数据的可靠。

checkpoint

checkpoint通过设置检查点,将数据保存到文件系统,在出现出故障的时候进行数据恢复。

spark streaming中有两种检查点:
  • 元数据检查点,主要是Driver的恢复

    保存应用程序的配置、Dstream操作、没有完成的批处理等。这里需要注意的是没有完成的批处理,代表的是生成批处理的元数据(Driver端),并没有具体的存储RDD内容(Executor端),RDD内容需要WAL来持久化。

  • 数据检查点

    主要是将已生成的RDD保存到可靠的存储系统中,在带state操作中是必须的。

checkpoint需要指定一个文件目录,来保存元数据和数据信息;每生成一个batch RDD,就会触发checkpoint操作,进行写。

假如Driver出故障挂掉了,我们再次重启的时候,就会去checkpoint设置的目录去读取一些配置,定位到挂之前的状态,继续进行工作。

WAL

write ahead log预写日志,在数据库中经常被用到,用来在宕机之后根据WAL恢复数据

实现是Executor的receiver在接收到数据时,如果设置了WAL,会将数据写入WAL

checkpoint + WAL

checkpoint 保存着执行进度(比如已生成但未完成的 jobs)

WAL 中保存着 blocks 及 blocks 元数据(比如保存着未完成的 jobs 对应的 blocks 信息及 block 文件)

两者结合就可以保证数据的可靠性。

code

  def main(args: Array[String]): Unit = {
    // checkpoint目录
    val checkpointDir = s"hdfs://*****/user/test"
    val sparkConf = new SparkConf()
    // 创建SparkSession
    val sparkSession = SparkSession
      .builder()
      .appName("checkpoint-wal")
      .config(sparkConf)
      // 设置开启wal
      .config("spark.streaming.receiver.writeAheadLog.enable", "true")
      .getOrCreate()
    val sc = sparkSession.sparkContext
	// StreamingContext.getOrCreate(checkpointDir, creatingFunc)
    // 这个方法表示如果checkpoint目录存在,则从目录读取ssc对象;不存在才调用creatingFunc创建ssc对象  
    val ssc = StreamingContext.getOrCreate(
      checkpointDir,
      () => createStreamingContext(sc, checkpointDir)
    )
    ssc.start()
    ssc.awaitTermination()
  }

  // 创建ssc的func
  def createStreamingContext(sc: SparkContext,
                             checkpointDir: String): StreamingContext = {
    val ssc = new StreamingContext(sc, Seconds(10))
    // 指定checkpoint目录  
    ssc.checkpoint(checkpointDir)
    // 做我们自己的逻辑处理
    val stream = ...
    // do something ...
    // 返回ssc对象
    ssc
  }

以上代码,就是使用checkpoint+wal的方式

存在的坑

  1. 自己的业务逻辑,应该在creatingFunc中,否则首次启动后,将其杀掉,再次启动会报如下异常:org.apache.spark.streaming.dstream.MappedDStream@5a69b104 has not been initialized

  2. streaming程序打包扔到集群正常运行以后,如果我们对代码进行修改,再重新打包;将旧的任务杀掉,用新的代码去跑;可能出现更改不生效,或者报ClassNotFoundException的错。问题就出在checkpoint上,因为checkpoint的元数据会记录jar的序列化的二进制文件,因为你改动过代码,然后重新编译,新的序列化jar文件,在checkpoint的记录中并不存在,所以就导致了上述错误。

    解决方案:删除checkpoint目录下checkpoint开头的的文件即可,再次重启就可以正常工作(这个方法我没有试过)。 我的做法是把目录下所有的文件删掉,然后重启,通过上游来保证可靠。

总结

  • 使用checkpoint+wal,主要用来解决【数据已接收但未处理】的时候,出现宕机的情况。

  • 如果上游可以保证可靠,且不要求至少一次,完全不需要这么做。

  • 开启WAL,对性能的影响较大,生产中使用还需要权衡。

  • 上游是kafka的话,可以自己管理偏移量,而不用采用这种方法

参考

https://cloud.tencent.com/developer/article/1122403

https://zhuanlan.zhihu.com/p/26297594

https://www.waitingforcode.com/apache-spark-streaming/sparkexception-org.apache.spark.streaming.dstream.MappedDStream-has-not-been-initialized/read

https://www.jianshu.com/p/5e096df2618d

个人理解,有偏差的地方欢迎指出。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值