Scala Spark如何处理涉及JDBC数据源的故障场景?

Scala Spark如何处理涉及JDBC数据源的故障场景?,scala,apache-spark,jdbc,apache-spark-sql,Scala,Apache Spark,Jdbc,Apache Spark Sql,我正在编写一个与Spark的JDBC数据源实现有相似之处的数据源,我想问Spark如何处理某些故障场景。据我所知,如果执行者在运行任务时死亡,Spark将恢复执行者并尝试重新运行该任务。但是,在数据完整性和Spark的JDBC数据源API(例如,df.write.format(“JDBC”).option(…).save())的上下文中,这是如何实现的 在的savePartition函数中,我们看到Spark调用从用户提供的数据库url/凭据生成的Java连接对象的提交和回滚函数(见下文)。但是

我正在编写一个与Spark的JDBC数据源实现有相似之处的数据源,我想问Spark如何处理某些故障场景。据我所知,如果执行者在运行任务时死亡,Spark将恢复执行者并尝试重新运行该任务。但是,在数据完整性和Spark的JDBC数据源API(例如,
df.write.format(“JDBC”).option(…).save()
)的上下文中,这是如何实现的

在的savePartition函数中,我们看到Spark调用从用户提供的数据库url/凭据生成的Java连接对象的提交和回滚函数(见下文)。但是,如果一个执行器在commit()完成之后或在rollback()调用之前死亡,Spark是否会尝试重新运行任务并再次写入相同的数据分区,从而在数据库中创建重复的提交行?如果执行器在调用委托()或滚退()中死亡,会发生什么?


出于上述原因,我不得不引入一些重复数据消除逻辑。你最终可能会犯同样的错误两次(或更多)

但是,如果一个执行器在commit()完成之后或在rollback()调用之前死亡,Spark是否会尝试重新运行任务并再次写入相同的数据分区,从而在数据库中创建重复的提交行

由于Spark SQL(它是RDDAPI之上的一种高级API)并不真正了解JDBC或任何其他协议的所有特性,您会期待什么?更不用说底层执行运行时,即Spark Core

当您编写类似
df.write.format(“jdbc”).option(…).save()之类的结构化查询时,Spark SQL使用类似RDDAPI的低级程序集将其转换为分布式计算。由于Spark SQL试图采用尽可能多的“协议”(包括JDBC),因此它的DataSource API将大部分错误处理留给了数据源本身

Spark的核心是调度任务(不知道甚至不关心任务做什么),它只是监视执行,如果任务失败,它将再次尝试执行它(默认情况下,直到3次失败的尝试)

因此,当您编写自定义数据源时,您了解演练,并且必须在代码中处理此类重试


处理错误的一种方法是使用注册任务侦听器(例如,
addTaskCompletionListener
addTaskFailureListener
)。

您能否描述一下如何实现此重复数据消除逻辑?我对一些细节很好奇,比如你在哪里添加的,你使用的是什么类型的数据库。这是一个Amazon红移,我不得不添加额外的时间戳列,后来用于ETL过程中的重复数据消除。一般来说,您只需要一些唯一的键就可以判断它是新记录还是重复记录,显然红移对于键(因此是时间戳)不是很好。你的数据目标是什么?谢谢!我正在尝试使用SQL Server。我对Redshift了解不多,但我会调查一下是否可以实现类似的策略。使用SQL Server实际上更简单—请看这里。
try {
    ...
    if (supportsTransactions) {
        conn.commit()
    }
    committed = true
    Iterator.empty
} catch {
    case e: SQLException =>
        ...
        throw e
} finally {
    if (!committed) {
        // The stage must fail.  We got here through an exception path, so
        // let the exception through unless rollback() or close() want to
        // tell the user about another problem.
        if (supportsTransactions) {
          conn.rollback()
        }
        conn.close()
    } else {
        ...
    }
}