版本号:

spark 2.3

structured streaming代码

异常信息

KafkaSource[Subscribe[test]]
at org.apache.spark.sql.execution.streaming.StreamExecution.org$apache$spark$sql$execution$streaming$StreamExecution$$runStream(StreamExecution.scala:295)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anon$1.run(StreamExecution.scala:189)
Caused by: java.lang.AssertionError: assertion failed: Concurrent update to the log. Multiple streaming jobs detected for 1470
at scala.Predef$.assert(Predef.scala:170)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$org$apache$spark$sql$execution$streaming$MicroBatchExecution$$constructNextBatch$1.apply$mcV$sp(MicroBatchExecution.scala:339)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$org$apache$spark$sql$execution$streaming$MicroBatchExecution$$constructNextBatch$1.apply(MicroBatchExecution.scala:338)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$org$apache$spark$sql$execution$streaming$MicroBatchExecution$$constructNextBatch$1.apply(MicroBatchExecution.scala:338)
at org.apache.spark.sql.execution.streaming.ProgressReporter$class.reportTimeTaken(ProgressReporter.scala:271)
at org.apache.spark.sql.execution.streaming.StreamExecution.reportTimeTaken(StreamExecution.scala:58)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution.org$apache$spark$sql$execution$streaming$MicroBatchExecution$$constructNextBatch(MicroBatchExecution.scala:338)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$runActivatedStream$1$$anonfun$apply$mcZ$sp$1.apply$mcV$sp(MicroBatchExecution.scala:128)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$runActivatedStream$1$$anonfun$apply$mcZ$sp$1.apply(MicroBatchExecution.scala:121)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$runActivatedStream$1$$anonfun$apply$mcZ$sp$1.apply(MicroBatchExecution.scala:121)
at org.apache.spark.sql.execution.streaming.ProgressReporter$class.reportTimeTaken(ProgressReporter.scala:271)
at org.apache.spark.sql.execution.streaming.StreamExecution.reportTimeTaken(StreamExecution.scala:58)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution$$anonfun$runActivatedStream$1.apply$mcZ$sp(MicroBatchExecution.scala:121)
at org.apache.spark.sql.execution.streaming.ProcessingTimeExecutor.execute(TriggerExecutor.scala:56)
at org.apache.spark.sql.execution.streaming.MicroBatchExecution.runActivatedStream(MicroBatchExecution.scala:117)
at org.apache.spark.sql.execution.streaming.StreamExecution.org$apache$spark$sql$execution$streaming$StreamExecution$$runStream(StreamExecution.scala:279)
... 1 more

一.异常表象原因

1.异常源码:

          currentBatchId,
availableOffsets.toOffsetSeq(sources, offsetSeqMetadata)),
s"Concurrent update to the log. Multiple streaming jobs detected for $currentBatchId")
logInfo(s"Committed offsets for batch $currentBatchId. " +
s"Metadata ${offsetSeqMetadata.toString}")

这是一个断言,assert,其中

          currentBatchId,
availableOffsets.toOffsetSeq(sources, offsetSeqMetadata))

这个函数返回一个布尔值,如果返回为false将抛出目前这样的异常。

那么,这个函数是干嘛的?

    require(metadata != null, "'null' metadata cannot written to a metadata log")
get(batchId).map(_ => false).getOrElse {
// Only write metadata when the batch has not yet been written
writeBatch(batchId, metadata)
true
}
}

从注释中可以看出,当一个structured streaming程序启动时,会去判断当前batch批次是否已经store。如果当前批次的元存储信息已经被存储,那么将返回false,程序将异常退出。

/**

  • Store the metadata for the specified batchId and return true if successful. If the batchId's
  • metadata has already been stored, this method will return false.

    */

2.打个断点

通过断点可以看到:

1.当前batchId = 1470

2.当前kafka里的最新offset是41

然后查看本地checkpoint里的消息

通过checkpoint可以看到

1.在offset文件里,确实存在1470的批次。表面当前批次的元信息已经被存储了。

2.打开1470文件可以看到,里面的最新消息offset为36

二.解决方案

最简单粗暴的就是直接删除checkpoint文件夹。但这样的话,会丢失中间部份数据。即36到41这向条数据。

Current Committed Offsets: {KafkaSource[Subscribe[test]]: {"test":{"0":36}}}

Current Available Offsets: {KafkaSource[Subscribe[test]]: {"test":{"0":41}}}

然后可以指定开始offset.

1.可以通过代码指定各分区的开始offset

.option("startingOffsets", """{"test":{"0":36,"1":-2},"topic2":{"0":-2}}""")

这种方式需要改代码,不推荐。

2.不删除而是更改checkpoint offset下的批次文件

如本例中,删除1470,并将1470里的信息复制到1469.用1470替代前一个批次1469的信息。

三.异常背后的原因

目前只是解决了这个问题。但背后的原因呢?

首先是什么情况导致的?

根据字面意思【Concurrent update to the log. Multiple streaming jobs detected】,在写checkpoint日志时,系统认为有多个streaming程序在写。系统认为不行。不管是不是有多个streaming任务在执行,既然系统有这么判断,那就去看checkpoint日志。

在这之前,先弄清structured streaming的checkpoint机制。

1). StreamExecution 通过 Source.getOffset() 获取最新的 offsets,即最新的数据进度;

2). StreamExecution 将 offsets 等写入到 offsetLog 里, 这里的 offsetLog 是一个持久化的 WAL (Write-Ahead-Log),是将来可用作故障恢复;

3). StreamExecution 构造本次执行的 LogicalPlan

(3a) 将预先定义好的逻辑(即 StreamExecution 里的 logicalPlan 成员变量)制作一个副本出来

(3b) 给定刚刚取到的 offsets,通过 Source.getBatch(offsets) 获取本执行新收到的数据的 Dataset/DataFrame 表示,并替换到 (3a) 中的副本里

经过 (3a), (3b) 两步,构造完成的 LogicalPlan 就是针对本执行新收到的数据的 Dataset/DataFrame 变换(即整个处理逻辑)了

4). 触发对本次执行的 LogicalPlan 的优化,得到 IncrementalExecution

逻辑计划的优化:通过 Catalyst 优化器完成

物理计划的生成与选择:结果是可以直接用于执行的 RDD DAG

逻辑计划、优化的逻辑计划、物理计划、及最后结果 RDD DAG,合并起来就是 IncrementalExecution

5). 将表示计算结果的 Dataset/DataFrame (包含 IncrementalExecution) 交给 Sink,即调用 Sink.add(ds/df)

6). 计算完成后的 commit

(6a) 通过 Source.commit() 告知 Source 数据已经完整处理结束;Source 可按需完成数据的 garbage-collection

(6b) 将本次执行的批次 id 写入到 batchCommitLog 里

注意2和6。前面我们知道,checkpoint下面的有三个文件commit,offset,source。在2的步骤,接收到kafka消息时,会将当前Batch的信息写入offset。直到当前batch处理完毕,再通过6的步骤commit到检查点。

如果2->6正常执行,这是一种正常情况,offset.maxBatchid>commit.maxBatchid。不做讨论。

如果2和6的步骤之间出现异常,执行了2,而没有执行6呢?

这种情况下又分为二种情况:

1.offset.maxBatchid>commit.maxBatchid 这种情况最为常见。表示接收到了kafka消息,但处理过程中异常退出。那么下次重启时,首先从offset.maxBatchId作为开始offset.

2.offset.maxBatchid>commit.maxBatchid 如果仅有一个strutured streaming任务在写checkpoint目录的话,永远不可能出现这种情况。因为2->6顺序执行的。如果出现了这种情况,那么系统就认为有多个任务使用了同一个检查点。这种情况是不被允许的,直接抛出异常。

所以,之所以出现这种异常,就是上述第2种情况。

四验证

反向验证上述猜测。

在检查点目录下,手动保留一个commit/1679的文件,手动删除offset/1679文件,这样offset下最大的batchid将小于commit下的最大batchid.

具体验证程序就不放上来了。有兴趣的可以自行测试一下。

结果是成功复现此异常。

spark官方为什么这样设计?

首先这肯定不是一个BUG。spark问题链接

我的猜测,这是官方的一种保护机制。多个任务使用同一个检查点,相当于多个spark streaming设置了同一个group.id,将会造成kafka数据源混乱。

五后续

同样的代码,保留同一样的checkpoint结构,即commit.maxBatchid>offset.maxBatchid,将系统升级到2.4版本,然后异常消失了!

所以这是打脸了吗?

加了断点,看了一下。

关键代码在

MicroBatchExecution.class line 547

commitLog.add(currentBatchId, CommitMetadata(watermarkTracker.currentWatermark))

在这里和2.3版本一样,调用了这段代码,检查了commit offset目录。

/**
* Store the metadata for the specified batchId and return `true` if successful. If the batchId's
* metadata has already been stored, this method will return `false`.
*/
override def add(batchId: Long, metadata: T): Boolean = {
require(metadata != null, "'null' metadata cannot written to a metadata log")
get(batchId).map(_ => false).getOrElse {
// Only write metadata when the batch has not yet been written
writeBatchToFile(metadata, batchIdToPath(batchId))
true
}
}

只不过,当文件存在时,并没有抛出异常,放过了,过了,了。。。。。。

Structured Streaming 的异常处理 【Concurrent update to the log. Multiple streaming jobs detected】的更多相关文章

  1. InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's

    InvalidOperationException: Operations that change non-concurrent collections must have exclusive acc ...

  2. abap异常处理 , update module

    1:异常 https://www.cnblogs.com/rainysblog/p/6665455.html 2:update module https://www.cnblogs.com/cindy ...

  3. Team Foundation Server 2013 with Update 3 Install LOG

    [Info   @10:14:58.155] ====================================================================[Info   @ ...

  4. 用ASP.NET Core 2.0 建立规范的 REST API -- DELETE, UPDATE, PATCH 和 Log

    本文所需的一些预备知识可以看这里: http://www.cnblogs.com/cgzl/p/9010978.html 和 http://www.cnblogs.com/cgzl/p/9019314 ...

  5. 论文阅读计划1(Benchmarking Streaming Computation Engines: Storm, Flink and Spark Streaming & An Enforcement of Real Time Scheduling in Spark Streaming & StyleBank: An Explicit Representation for Neural Ima)

    Benchmarking Streaming Computation Engines: Storm, Flink and Spark Streaming[1] 简介:雅虎发布的一份各种流处理引擎的基准 ...

  6. 大batch任务对structured streaming任务影响

    信念,你拿它没办法,但是没有它你什么也做不成.—— 撒姆尔巴特勒 前言 对于spark streaming而言,大的batch任务会导致后续batch任务积压,对于structured streami ...

  7. Structured Streaming Programming Guide结构化流编程指南

    目录 Overview Quick Example Programming Model Basic Concepts Handling Event-time and Late Data Fault T ...

  8. Structured Streaming教程(2) —— 常用输入与输出

    上篇了解了一些基本的Structured Streaming的概念,知道了Structured Streaming其实是一个无下界的无限递增的DataFrame.基于这个DataFrame,我们可以做 ...

  9. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十六)Structured Streaming中ForeachSink的用法

    Structured Streaming默认支持的sink类型有File sink,Foreach sink,Console sink,Memory sink. ForeachWriter实现: 以写 ...

  10. Apache Spark 2.2.0 中文文档 - Structured Streaming 编程指南 | ApacheCN

    Structured Streaming 编程指南 概述 快速示例 Programming Model (编程模型) 基本概念 处理 Event-time 和延迟数据 容错语义 API 使用 Data ...

随机推荐

  1. Hadoop-HA节点介绍

    设计思想 hadoop2.x启用了主备节点切换模式(1主1备) 当主节点出现异常的时候,集群直接将备用节点切换成主节点 要求备用节点马上就要工作 主备节点内存几乎同步 有独立的线程对主备节点进行监控健 ...

  2. 使用sync.Once实现高效的单例模式

    1. 简介 本文介绍使用sync.Once来实现单例模式,包括单例模式的定义,以及使用sync.Once实现单例模式的示例,同时也比较了其他单例模式的实现.最后以一个开源框架中使用sync.Once实 ...

  3. 重学c#系列—— explicit、implicit与operator[三十四]

    前言 我们都知道operator 可以对我们的操作符进行重写,那么explicit 和 implicit 就是对转换的重写. 正文 explicit 就是强制转换,然后implicit 就是隐式转换. ...

  4. Three.js 进阶之旅:物理效果-3D乒乓球小游戏 🏓

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 摘要 本文在专栏上一篇内容<Three.js 进阶之旅:物理效果-碰撞和声 ...

  5. Cesium 后处理(Post Process)

    原文地址:https://blog.csdn.net/ls870061011/article/details/123910821 作者:GIS李胜 为实现三维模型的更炫.更酷.更美观,Cesium在1 ...

  6. StyleGAN 调整面部表情,让虚拟人脸更生动

    目录 人脸表情 调整步骤 调整结果 人脸表情 通过上一篇文章 StyleGAN 生成的人脸:https://www.cnblogs.com/tinygeeker/p/17236264.html 人脸图 ...

  7. Unity绘制圆和缓动雷达图

    Unity绘制圆和缓动雷达图 之前在做UI模块的时候遇到过需要做雷达图的效果,所以简单复习了一下 关于网格绘制 我们都知道Unity绘制图形是通过Mesh网格添加顶点进行绘制,那么知道顶点信息后如何实 ...

  8. 分布式事务组件Seata

    ‌介绍 一阶段:事务协调者通知每一个服务处理本地事务,每个服务开始处理但是不会提交事务,处理完毕后告知协调者. 二阶段:协调者收到所有服务的消息后通知他们提交事务. ‌重要角色 事务管理器(TM),决 ...

  9. 项目讲解之火爆全网的开源后台管理系统RuoYi

    博主是在2018年中就接触了 RuoYi 项目 这个项目,对于当时国内的开源后台管理系统来说,RuoYi 算是一个完成度较高,易读易懂.界面简洁美观的前后端不分离项目. 对于当时刚入行还在写 jsp ...

  10. 网络计划技术——关键路线法(Python)

    关键路径法是基于进度网络模型的方法,用网络图表示各项活动之间的相互关系,获得在一定工期.成本.资源约束条件下的最优进度安排.关键路径法源于美国杜邦公司对于项目管理控制成本.减少工期的研究.1959年, ...