Apache Spark 面向用户错误规范化指南:SQLSTATE、Error Condition 与 SparkThrowable 实战

📅 发布时间:2026/9/19 11:27:22
Apache Spark 面向用户错误规范化指南:SQLSTATE、Error Condition 与 SparkThrowable 实战
Apache Spark 面向用户错误规范化指南SQLSTATE、Error Condition 与 SparkThrowable 实战【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址: https://gitcode.com/gh_mirrors/sp/spark本指南基于 common/utils/src/main/resources/error/README.md 展开系统讲解 Apache Spark 中面向用户错误User-Facing Error的规范化体系包括 SQLSTATE、错误条件Error Condition与子条件Sub-Condition的层级术语、三个核心 JSON 定义文件的作用、从抛错到上报的完整六步流程以及异常类型如何混入SparkThrowable接口并携带结构化字段。读完本文你可以在 Spark 源码开发中写出具备稳定错误码、可移植 SQLSTATE 与可参数化消息的异常并能在客户端按条件名或 SQLSTATE 精确捕获与分诊错误。错误层级与术语体系在 Spark 中开发者在抛出面向用户的错误或异常时应指定标准化的 SQLSTATE、错误条件与消息参数而不是直接写一段任意文本的错误消息。整个错误体系自上而下分为三层Error state / SQLSTATE错误状态码Error condition错误条件Error sub-condition错误子条件其中SQLSTATE 本身又由两部分组成Error class错误类别SQLSTATE 的前 2 个字符Error sub-class错误子类别SQLSTATE 的后 3 个字符。这些术语error class、state、condition均源自 SQL 标准。它们各自允许的取值分别定义在以下三个文件中error-classes.jsonSQLSTATE 中错误类别前 2 位字符的合法取值及其含义error-states.json完整 SQLSTATE 取值集合每条记录带有来源、标准状态与使用方等元数据error-conditions.json错误条件名称、默认消息模板与所属 SQLSTATE 的映射表。直观示例以文档中的两个示例说明状态码—条件—子条件之间的关系SQLSTATE42K01Class42Sub-classK01Error conditionDATATYPE_MISSING_SIZEError conditionINCOMPLETE_TYPE_DEFINITIONError sub-conditionARRAYError sub-conditionMAPError sub-conditionSTRUCTSQLSTATE42604Class42Sub-class604Error conditionINVALID_ESCAPE_CHARError conditionAS_OF_JOINError sub-conditionTOLERANCE_IS_NON_NEGATIVEError sub-conditionTOLERANCE_IS_UNFOLDABLEError sub-conditionUNSUPPORTED_DIRECTION可以看到一个 SQLSTATE 可以挂载多个错误条件一个错误条件又可以扩展出多个子条件从而在保留稳定状态码的同时对错误做细分。从 error-classes.json 可见42对应 Syntax Error or Access Rule ViolationXX对应 Internal ErrorKD对应 datasource specific errorsK0/K**为 Spark 声明的扩展区间。关于 Error Class 术语的历史性不一致需要特别说明的是历史代码中error class一词被不一致地使用既指代42这类真正的错误类别也指代DATATYPE_MISSING_SIZE这类错误条件。修正该问题需要把SparkException.errorClass重命名为SparkException.errorCondition并同步修改ErrorClassesJSONReader等相关代码这一工作由 SPARK-47429 跟踪在此之前需要接受用户文档中称为 error condition、代码中称为 error class这一现状。相关背景可参考 SPARK-46810。这一名实不符在源码中也有直接印证ErrorClassesJSONReader.scala类名仍沿用历史命名与 SparkThrowableHelper.scala 的注释中均明确说明尽管代码里称之为 error classes其规范名称实为 error conditionsJSON 文件名也因此与代码命名不同。抛出用户错误的标准流程当需要抛出一个用户可见的错误时按照文档给出的六步流程操作先判断是否为内部错误。内部错误internal error是指代码中的 bug用户正常情况下不应遇到注意不支持的操作unsupported operations不属于内部错误。若确属内部错误使用错误条件INTERNAL_ERROR并直接跳到第 4 步。检查 error-conditions.json 中是否已存在合适的错误条件。若已存在直接使用该条件名跳到第 4 步。新增错误条件向 error-conditions.json 中添加新条件若新条件需要新的状态码则同时在 error-states.json 中添加新的 SQLSTATE。检查异常类型是否已混入SparkThrowable。若已混入跳到第 6 步。将SparkThrowable混入该异常。以错误条件 消息参数的方式抛出异常。如果同一异常在多处被抛出应在QueryCompilationErrors.scala这类集中位置创建工具函数来实例化异常避免重复逻辑。从源码可以看到INTERNAL_ERROR的判定在 SparkThrowableHelper.scala 中实现isInternalError检查条件名是否以INTERNAL_ERROR开头SparkThrowable.java 的isInternalError()默认方法同样委托给该 Helper。而集中式 util 函数的范式可从 QueryCompilationErrors.scala 中大量def xxxError(...): Throwable方法看出端倪。Before任意错误消息不推荐改造前抛出的是不可结构化的任意文本throw new TestException(Problem A because B)After错误条件 消息参数推荐首先在error-conditions.json中登记条件名与消息模板PROBLEM_BECAUSE : { message : [Problem problem because cause], sqlState : XXXXX }然后定义混入SparkThrowable的异常类型示意代码class SparkTestException( errorClass: String, messageParameters: Map[String, String]) extends TestException(SparkThrowableHelper.getMessage(errorClass, messageParameters)) with SparkThrowable { override def getMessageParameters: java.util.Map[String, String] messageParameters.asJava override def getErrorClass: String errorClass }最后按条件名 参数抛出throw new SparkTestException(PROBLEM_BECAUSE, Map(problem - A, cause - B))访问错误字段要读取错误的结构化字段可以捕获所有实现了org.apache.spark.SparkThrowable的异常然后访问getErrorClass即错误条件名如DATATYPE_MISSING_SIZEgetSqlStateSQLSTATE如42K01例如按 SQLSTATE 前缀做语法错误告警try { ... } catch { case e: SparkThrowable if Option(e.getSqlState).forall(_.startsWith(42)) warn(Syntax error) }SparkThrowable.java 还提供了getCondition()规范名称getErrorClass()已标记为Deprecated并默认委托给getCondition()、getMessageParameters()、getDefaultMessageTemplate()、getQueryContext()等默认方法供客户端做翻译、格式化或上下文展示。各字段规范详解Error condition错误条件错误条件是错误类别的一种简洁、人类可读的表示例如DATATYPE_MISSING_SIZE。对于尚未归类的历史错误可以临时使用_LEGACY_ERROR_TEMP_前缀加未使用的递增序号如_LEGACY_ERROR_TEMP_0053作为条件名。不应再新增未归类错误遇到旧代码时应当将其转换为规范错误。不变量Invariants唯一Unique跨版本一致Consistent across releases按字母序排序Sorted alphabetically从 error-conditions.json 的内容可以看到条件名均为大写下划线命名且严格按字典序排列SparkThrowableSuite.scala 等测试也会校验这些不变量例如检查非_LEGACY_ERROR_TEMP_条件都携带非空的 sqlState。Message消息模板错误消息是错误的人类可读描述其模板通过HTML 标签语法接收字符串参数例如relationName、problem、cause。传给消息模板的值本身不应是另一条消息而应是运行时值、关键字、标识符或其他不需要翻译的值。消息质量需符合 Spark 官方错误消息指南该指南为外部公开规范此处仅作参考。注意_LEGACY_ERROR_前缀的条件在格式化时不显示条件名前缀而普通错误会以[ERROR_CONDITION]开头输出这一逻辑实现在 SparkThrowableHelper.scala 的formatErrorMessage中。不变量唯一UniqueSQLSTATESQLSTATE 是一种跨 SQL 引擎可移植的强制性错误标识符由2 字符 class 3 字符 sub-class组成共 5 位如42K01、42604。Spark 的取值策略是优先复用业界已有的 SQLSTATE最好是多个厂商共同使用的取值扩展场景使用 Spark 自有的K**子类区间若确需新增类别将占用K0类别。一般情况下每个错误条件及其子条件都属于同一个错误状态条件声明 SQLSTATE子条件继承之。文档记录了一个例外当重新归类会破坏线上已发布客户端对条件名的匹配时子条件可自行声明sqlState目前唯一获准的例外是INVALID_HANDLE.SESSION_*并由 SparkThrowableSuite.scala 中的测试固定INVALID_HANDLE使用HY000而SESSION_CHANGED/SESSION_CLOSED/SESSION_NOT_FOUND三个子条件使用08003。不得再添加新的 override即使是同一错误类别内的子条件也不允许未来面向客户端版本的兼容层可能移除这一既有例外。内部错误应使用XX类别并可按组件进一步细分例如既有的XXKD0用于内部 analyzer 错误。在 error-classes.json 中可确认XX定义为 Internal Error。不变量除非是内部错误否则跨版本保持一致Consistent across releases unless the error is internal。ANSI/ISO 标准来源error-states.json 中收录的 SQLSTATE 来自以下权威来源文档明确列出SQL2016DB2 zOS/LUWPostgreSQL 15Oracle 12最后公开发布版SQL ServerRedshift从该文件的记录结构看每条 SQLSTATE 都带description描述、origin来源标准、standard是否标准取值Y/N与usedBy采用该取值的引擎列表等元数据例如01004标注为 string data, right truncation来源 SQL/Foundation被 PostgreSQL、DB2、Redshift、Oracle、SQL Server 共同采用。这套数据构成了 Spark 选择 SQLSTATE 时的参照系也是优先复用多厂商取值策略的落地基础。从源码看错误体系的落地实现接口层SparkThrowable.java自 3.2.0 起定义了错误对象的结构化契约包括getCondition()、getSqlState()、getMessageParameters()、getDefaultMessageTemplate()、isInternalError()、getBreakingChangeInfo()与getQueryContext()且向后兼容地允许旧异常以null条件名抛出任意消息。消息构造层SparkThrowableHelper.scala 在启动时通过SparkClassUtils.getSparkClassLoader.getResource(error/error-conditions.json)加载 error-conditions.json据此解析消息模板、填充参数、拼接[条件名] 消息 SQLSTATE: xxxxx的最终文本并提供getSqlState、isValidErrorClass、isInternalError、MINIMAL/STANDARD/PRETTY/DEBUG 多种序列化格式。解析层ErrorClassesJSONReader.scala 负责读取并索引三个 JSON 文件该类名沿用历史命名与条件/类别术语不一致问题相关。集中工厂层QueryCompilationErrors.scala 集中定义了数以百计的xxxError工厂方法把条件名 参数封装成可复用的抛错入口正是文档第 6 步所述集中位置 util 函数的典型实现。验证层SparkThrowableSuite.scala 覆盖了条件名唯一性、SQLSTATE 继承规则、INVALID_HANDLE.SESSION_*特例08003、自定义 sqlState 与消息模板、SQLSTATE 不一致告警等行为是错误体系契约的权威测试依据。适用前提说明以上错误体系面向 Apache Spark 源码的开发者贡献者——即需要抛出新错误或在客户端按条件名解析错误的场景普通用户遇到 Spark 报错时可从形如[CONDITION_NAME] message ... SQLSTATE: xxxxx的报错文本中直接识别条件名与状态码用于检索与排查。【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址: https://gitcode.com/gh_mirrors/sp/spark创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考