跳到主要内容
版本:Next

不向前兼容的更新

本文档记录了各版本之间不兼容的更新内容。在升级到相关版本前,请检查本文档。

dev​

Lance Sink:TIMESTAMP 值保留微秒​

  • 行为变更:Lance Sink 写入的 TIMESTAMP 保留毫秒以下的数字
    • 描述:Lance Sink 按文档以微秒精度声明 TIMESTAMP 列,但 BaseTypeWriter.convertToEpochMicro 会先把 LocalDateTime 和 java.sql.Timestamp 值转换为毫秒,因此写入的每个值最后三位微秒都是 000。现在直接由时间点(Instant)转换。
    • 影响:对同一输入,新写入的值可能与早期版本写入的值在最后三位微秒上不同。数据集中已有的行不会被重写,因此同一个数据集中可能同时存在两种值。毫秒精度的列,以及没有毫秒以下数字的值,不受影响。
    • 迁移指南:无需修改配置。如果下游需要把新写入的行与早期版本写入的行进行比较或去重,请按毫秒精度比较,或从数据源重新写入旧数据。

JDBC MySQL:DATETIME 写入保留本地日期和时间字段​

MySQL JDBC Sink 现在直接绑定 SeaTunnel TIMESTAMP(LocalDateTime),不再通过 java.sql.Timestamp 转换。当 Worker JVM 与 JDBC 连接的时区不同时,受影响的版本可能导致 DATETIME 值偏移,或拒绝合法的边界值。现在写入会保留本地字段及目标列支持的小数秒精度。DATETIME 的源端映射和 TIMESTAMP_TZ 的处理保持不变。

请移除为补偿此缺陷而设置的手动偏移。已经存储的数据不会自动修改;修正或重新加载之前,请先与原始数据核对。无需新增配置。

Doris 与 StarRocks Source:MAP 或 ROW 列为空值时不再读成空 Map 或导致作业失败​

  • 行为变更:Arrow 流中为空的复杂类型单元格现在读为 null
    • 描述:Doris 和 StarRocks Source 使用的 ArrowToSeatunnelRowReader 会把 MAP 列交给 MapConverter、ROW 列交给 StructConverter。这两个转换器在处理元素类型的分支中没有检查 Arrow 的有效性位,因此为空的 MAP 单元格被返回为空 Map,为空的 ROW 单元格则以 NullPointerException: Cannot invoke "java.util.Map.entrySet()" because "valueMap" is null 结束整个读取。现在两者都返回 null,与自 Arrow Reader 引入起就有此判断的 ListConverter、LargeListConverter 和 FixedSizeListConverter 保持一致。
    • 影响:可空的 MAP 列在该行没有 Map 时现在返回 null,此前返回空 Map。确实存放空 Map 的行仍然返回空 Map,因此“不存在”和“为空”不再是同一个值。可空的 ROW 列现在可以正常读取,而不会使整个分片失败。
    • 迁移指南:此前把空 Map 当作“无值”处理的下游无需改动。如果下游假定每行都有非空的 Map,则需要处理该列为 null 的情况。

Zeta:管道故障转移恢复后运行时计数器从零重新计数​

  • 行为变更:运行时计数器不再累计失败管道执行的数值
    • 描述:Zeta 引擎在 worker 故障转移后恢复管道(或失败后重试)时,新一次执行的运行时计数器(SourceReceivedCount、SinkWriteCount、队列指标)从零开始计数。此前由于任务位置在多次重试之间保持不变,新执行的计数器会从共享指标存储中继承失败执行的数值继续累加,导致已完成作业的指标可能包含早已被取消的执行所完成的工作量。
    • 影响:对批作业,这消除了已完成作业指标多计的问题。对流作业,故障转移恢复后上报的总量会从新一次执行的数值重新开始,而不是延续故障前的累计值;外部聚合这些计数器的看板或告警不应将这种清零解读为数据丢失。该清零是尽力而为的:恢复期间恰好在途的 worker 上报,最多可能在毫秒级窗口内携带一次旧数值。
    • 迁移指南:正确性上无需任何操作。如果需要跨故障转移的生命周期总量,请在运行中的作业之外自行累计,例如从作业历史中已完成作业存储的指标获取。

JSON 格式:ARRAY 与 MAP 字段拒绝容器类型不匹配的值​

当字段声明为 ARRAY 时,此前若 JSON 值不是数组(字符串、数字、布尔值或对象),会静默得到空数组 [],若是对象则得到每个成员都为 null 的数组;当字段声明为 MAP 时,非对象的 JSON 值会静默得到空 Map {}。无论 ignore-parse-errors 关闭还是开启,行为都是如此。

现在这类值会报告解析错误,指出字段名和预期的容器类型;配置 ignore-parse-errors = true 时只把该容器值置为 null,同一行的其余值仍然保留。嵌套在数组或 Map 中的类似值同样如此:只有出错的那个嵌套值变为 null,其兄弟值和外层容器仍然保留;与声明类型匹配的空数组、空对象,以及 null 与缺失值,以及元素和键的转换行为保持不变。如需迁移,请为 ARRAY 字段提供真正的 JSON 数组、为 MAP 字段提供真正的 JSON 对象,或开启 ignore-parse-errors = true,使格式不合法的容器值变成 null而不是让作业失败。

同样的严格校验也适用于未忽略解析错误而使用共享 JSON 转行转换的地方:JsonPath 转换(列的 dest_type)、Python 转换(声明的输出列及其声明类型),以及 Assert 的 equals_to 对 ARRAY、MAP 值的比较。这些调用方不会读取 JSON 格式的 ignore-parse-errors 选项,因此该开关对它们不生效:与声明的 ARRAY 或 MAP 类型不匹配的值在那里仍会失败,而这些转换插件自身的错误处理行为保持不变。

JDBC 达梦:NVARCHAR 和 NVARCHAR2 按声明长度上报​

  • 模式变更:达梦 Catalog 现在按声明长度 n 上报 NVARCHAR(n) 和 NVARCHAR2(n),不再使用字节长度
    • 描述:NVARCHAR(n) 和 NVARCHAR2(n) 可容纳 n 个字符,但 Catalog 此前从 ALL_TAB_COLUMNS.DATA_LENGTH 读取长度,该字段是字节数:GB18030 库上是 2n,UTF-8 库上是 4n,与 LENGTH_IN_CHAR 的取值无关。因此 NVARCHAR(10) 会被上报为 NVARCHAR(20) 或 NVARCHAR(40)。现在长度取自 SYS.SYSCOLUMNS.LENGTH$,即声明长度。
    • 影响:这类列的源类型会变化,例如从 NVARCHAR(20) 变为 NVARCHAR(10);Sink 自动建表使用的列长度变为原来的 1/2(GB18030)或 1/4(UTF-8),例如 NVARCHAR(10) 写入 MySQL Sink 时建为 VARCHAR(40),而不是 VARCHAR(80)。由于长度按字符计算,新列仍能容纳源列的所有值。下游已存在的表不会被修改。CHAR、VARCHAR、VARCHAR2 和 NCHAR 列不受影响。
    • 迁移指南:无需修改。如果作业依赖原来较宽的自动建表列(例如还要从其他数据源向同一张表写入更长的值),请自行创建 Sink 表。

File Sink:XML 应用 date_format、datetime_format 和 time_format​

  • 行为变更:文件类 Sink 的 XML 写入器按配置的格式输出 DATE、TIME 和 TIMESTAMP
    • 描述:使用 file_format_type = "xml" 时,此前 DATE、TIME 和 TIMESTAMP 直接用 Java toString() 写出,忽略 date_format、datetime_format 和 time_format。时间戳会写成 2026-01-02T10:13:45.123,秒为 0 时写成 2026-01-02T10:13,同一个文件里可能混有多种格式,无法用同一个 datetime_format 读回。现在会按配置的格式输出,与 CSV、Text、Excel 写入器一致。
    • 影响:使用默认配置时,时间戳写成 yyyy-MM-dd HH:mm:ss(T 改为空格,丢弃小数秒),时间写成 HH:mm:ss。依赖原 ISO 格式的下游需要调整。
    • 迁移指南:如需保留 ISO 格式,请在 Sink 上配置 datetime_format,例如 YYYY_MM_DD_HH_MM_SS_ISO8601(yyyy-MM-dd'T'HH:mm:ss),或使用 YYYY_MM_DD_HH_MM_SS_SSS_ISO8601(yyyy-MM-dd'T'HH:mm:ss.SSS)保留毫秒,并在读取时为 Source 配置对应的 datetime_format。

原生 CLI 帮助退出码​

seatunnel.sh -h 现在以 0 而非 234 退出。 依赖退出码 234 识别原生帮助的脚本需要调整。Spark/Flink Java 启动器仍使用 234 协议, 对应包装脚本仍将帮助请求转换为退出码 0。

CDC:可空列不再用作快照分片列​

  • 行为变更:基于 JDBC 的 CDC 源(MySQL、PostgreSQL、Oracle、SQL Server、DB2)不再使用可空列切分快照
    • 描述:对于没有主键的表,此前即使唯一键列可空,也会将其作为快照分片列。该列为 NULL 的行不会匹配任何快照分片,会被静默跳过。现在会跳过可空列,无论它来自唯一键、snapshotSplitColumn,还是 table-names-config.primaryKeys 中配置的主键;如果没有可用的非空键列,则整张表作为单个分片读取。可空性从数据库元数据中读取。
    • 影响:这类表现在会被完整读取,但快照只有一个分片而不是多个。开启 exactly_once = true 时,若表唯一的键是可空唯一键,或 table-names-config.primaryKeys 中配置的是可空列,作业会在启动时报错 Exactly once is enabled, but not found non-nullable primary key or unique key for table ...,而不是继续运行并丢失数据。对于已有作业,即使配置的 primaryKeys 列中实际没有 NULL,只要该列在数据库中可空,也会如此。
    • 迁移指南:如需保持快照并行读取,请声明一个 NOT NULL 的唯一列,或通过 table-names-config.primaryKeys / snapshotSplitColumn 配置非空列。对于 exactly_once = true,请为表添加主键或非空唯一键,或将配置的 primaryKeys 列在数据库中改为 NOT NULL。

PostgreSQL CDC pgoutput 表结构​

  • 行为变更:使用 decoding.plugin.name = "pgoutput" 的流式作业会从源表结构中排除 PostgreSQL 发布未发布的列,包括 PostgreSQL 18 之前的生成列、虚拟生成列以及发布列列表中省略的列。仅快照作业和其他解码插件不受影响。
  • 影响:下次启动或恢复作业时,快照和自动创建的目标表将不再包含未发布的非主键列。依赖这些列的现有目标表和下游使用方可能需要调整表结构或字段映射;此前流式更新可能将这些列写为 NULL,或因表结构不匹配而失败。如果必需的主键未发布(包括仅发布 INSERT 的发布),作业现在会在启动时失败,而不是保留该列并在流式同步中输出 NULL 主键。
  • 迁移指南:升级前检查发布配置及下游表结构。在 PostgreSQL 18 中,设置 publish_generated_columns = stored 的发布可以保留存储生成列;虚拟生成列仍不会发布。使用发布列列表时,请加入所有必需主键列(包括 table-names-config.primaryKeys 配置的主键)和其他必需列。发布 UPDATE/DELETE 时,PostgreSQL 还要求包含副本标识列。请调整目标表结构和下游映射,移除其他未发布的列;没有显式列列表的发布仍遵循生成列规则。

Markdown File Source 的 child_ids 数组​

Markdown File Source 现在将 child_ids 声明为 ARRAY<STRING>,每行输出 String[]。此前该字段声明为 STRING,父元素输出逗号分隔的 ID,叶子元素输出 null。请将下游 schema 和消费逻辑改为读取数组;叶子元素现在输出空数组。元素 ID、类型、页码和位置索引保持原有格式。

运行环境要求​

  • 破坏性变更:最低 Java 运行时从 Java 8 提升到 Java 11
    • 影响范围:所有模块——整个发行包、Zeta 引擎、全部连接器,以及发布的 Docker 镜像
    • 变更说明:构建目标改为 Java 11(maven.compiler.source 与 maven.compiler.target 均为 11),因此发布的每个 jar 的 class 文件版本都是 55。GitHub CI 基于该 Java 11 基线在 JDK 17 上编译和测试,发布的 Docker 镜像也从 seatunnelhub/openjdk:8u342 改为 eclipse-temurin:11-jdk——仍保留完整 JDK 而非 JRE,以便 jps/jstack/jmap 继续可用于诊断运行中的节点。
    • 影响:
      • Java 8 JVM 无法再加载 SeaTunnel 的类,启动时会抛出 java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent version of the Java Runtime (class file version 55.0)。客户端、Zeta master 与 worker 节点,以及任何会加载连接器 jar 的进程都受此影响。
      • Flink:JobManager 和 TaskManager 的 JVM 会加载 SeaTunnel 连接器类,因此整个 Flink 集群都必须运行 Java 11 及以上,而不只是提交作业的客户端。Flink 从 1.13 起支持 Java 11,官方 Flink 镜像提供 -java11 标签。
      • Spark:Driver 和 Executor 的 JVM 会加载 SeaTunnel 连接器类,因此整个 Spark 集群都必须运行 Java 11 及以上。Spark 从 3.0 起才正式支持 Java 11(SPARK-24417)。Spark 2.4 在 Java 11 上仍可启动,但会打印非法反射访问告警,并且会把较老的 commons-lang3 放进 classpath,部分连接器会因此初始化失败,因此强烈建议使用 Spark 3.x。
      • 已按 Java 8 编译的第三方连接器仍可正常使用。Java 11 JVM 可以直接加载更低版本的 class 文件,所以只有 JVM 版本有要求,对您自己 jar 的字节码级别没有要求。
    • 迁移指南:
      1. 将所有运行 SeaTunnel 代码的节点的 JVM 升级到 Java 11 或 Java 17:客户端、Zeta master 与 worker,以及作业提交到的 Flink 或 Spark 集群。
      2. 如果提交到 Flink,请将集群切换到运行 Java 11 及以上的镜像或部署。
      3. 如果提交到 Spark 2.4,请升级到运行在 Java 11 及以上的 Spark 3.x。Spark 2.x 没有任何版本支持 Java 11。
      4. 如果您修改过 ${SEATUNNEL_HOME}/config/jvm_options(以及 client、master、worker 对应的变体),请检查自己添加的参数中是否包含 Java 11 已移除的选项,例如 -XX:+UseConcMarkSweepGC 或 -XX:MaxPermSize,JVM 遇到无法识别的参数会直接拒绝启动。发行包默认提供的参数已经兼容 Java 11。
      5. 无需把新增的 JDK 模块参数手工复制到保留下来的配置目录中。seatunnel.sh 和 seatunnel-cluster.sh 会自行追加必需的 --add-opens/--add-exports 参数(java.base/java.lang、java.net、java.nio、java.util、sun.nio.ch,以及 java.security.jgss/sun.security.krb5),并跳过您的 jvm_*_options 中已有的同名参数,因此原地升级并保留旧的 config/ 目录(挂载的 Docker 卷或 Kubernetes ConfigMap)时,这些参数依然生效。当检测到的 JVM 版本低于 11 时,同样的脚本会直接以明确的 SeaTunnel requires Java 11 or newer 提示退出,而不是让 Java 8 启动器输出原始的 Unrecognized option 错误。

Application Mode 内部 API 变更​

  • ResourceManagerFactory 现在是单一具体类:无参构造器选择 standalone 资源管理器,四参构造器为 Application Mode 创建 ApplicationResourceManager。平台专属的资源管理器子类和工厂 SPI 已移除。
  • ResourceManagerDriver 初始化时接收 ResourceEventHandler、主线程执行器、IO 执行器和 Master 地址 提供函数,不再接收 ResourceManagerContext。Driver 现在通过 finish(...) 发布终态,并在 close() 中释放平台客户端。
  • AbstractResourceManager.close() 现在是 final 的幂等生命周期入口,子类不再能重写。部署相关的清理 逻辑需下移到 closeResourceManager(),由 close() 保证只调用一次;此前重写 close() 的子类将无法 编译,需要迁移。

用户变量(-i 参数)​

  • -i 参数值在 System.getProperties()中不可见

    • 以前参数值通过 -i 注入到 System.getProperties() 并通过 System.getProperty()访问。从这个版本开始,-i 参数通过 Config.resolveWith() 解析,并且不能通过 System.getProperties() 访问。
  • -i 参数不再允许重复key

    • -i 参数如果有重复key会直接报错,之前重复的key对应的参数值会静默覆盖已有的key,会导致因复制粘贴等问题造成的重复key产生非预期的数据同步错误。
    • 如有代码生成或者cli输入产生的重复key,请检查后移除不需要的参数配置。
  • 双引号包裹的 -i 值会被解包

    • 例如 -i k="v" 现在等价于 -i k=v(引号被剥掉)。双引号主要针对包含逗号(,),花括号({})和方括号([])等包含结构化定界符的字符串参数值使用,其他普通字符可不用双引号。
  • 不平衡的{}或[]会被部分解析成map和list

    • -i k=[a,b],c] 中[a,b]会当成数组解析,c] 因为没有 = 会被忽略(不会作为字符串保留)
    • 以 { 或 [ 开头、括号平衡但不是合法 HOCON/JSON 的参数值,现在会在解析阶段抛出 BadValue 错误。之前能正常工作的未加引号的值(如 -i pattern={a,b} )会因此失败。如需保留为普通字符串,请用转义双引号包裹: -i pattern=\"{a,b}\"
  • -i key 和 value 现在会 trim,空 key 会被拒绝

    • -i 'k1= , k2=v2' 现在会明确将空格去掉,k1的会变为空字符串,第二个键值对的key会变为k2而不是带空格的 k2。
    • -i ' =v1 , k2=v2' 现在会报错,因为v1的key在trim后为空。
    • 有意义的首尾空白会被静默去除。

SQL TINYINT 数组模式​

Zeta SQL ARRAY 函数现在将 TINYINT 元素声明为 ARRAY<TINYINT>,与实际输出的 Byte 值一致。此前错误的 ARRAY<STRING> 声明会导致依赖模式的行处理失败。请更新假定元素为 STRING 的下游声明;需要字符串模式时,在 SQL 中显式将值转换为 STRING。受影响的作业应使用修正后的模式重新启动,不要恢复依赖旧声明的状态。

Zeta SQL Transform:数值来源转换为 INT 时拒绝超出范围的值​

  • 行为变更:数值来源转换为 INT 时不再静默回绕,而是直接失败
    • 受影响组件:seatunnel-transforms-v2,SystemFunction.castAs(Zeta SQL transform)
    • 说明:将数值转换为 INT | INTEGER 时会经由 Number.intValue(),它只保留低 32 位, 因此 CAST(bigint_col AS INT) 对 3000000000 返回 -1294967296,略小于 Integer.MIN_VALUE 的值会变成 2147483647,符号发生翻转。而字符串来源已经经由 Integer.parseInt 报告溢出, 所以同一个表达式究竟是失败还是损坏数据,仅取决于来源列的类型。现在数值路径也会报告该情况。 TINYINT、SMALLINT 与 BYTE 不受影响,因为它们使用 Byte.parseByte 与 Short.parseShort 转换,本来就会拒绝超出范围的值。规划阶段的接受范围保持不变:每个目标类型允许的来源类型与此前完全一致。
    • 影响:如果作业(有意或无意地)依赖了回绕行为,现在会在溢出的那一行失败,而不是写入错误的数字。 范围内的值、扩宽转换和同类型转换均不受影响。本次变更不涉及 FLOAT 与 DOUBLE,它们对无法表示的值 仍返回 Infinity。
    • 同样影响 COALESCE 与 IFNULL:它们会走到同一个转换边界,且其结果类型是按第一个非空参数推断的, 而不是按最宽的类型推断。因此 COALESCE(int_col, bigint_col) 的目标类型是 INT,取自 BIGINT 参数的超范围值此前同样会被静默截断,现在也会失败。CASE 表达式不受影响,因为它的类型按最宽的分支推断, 不会发生收窄。
    • 覆盖宽类型与非有限数值来源:范围检查按数值族分别进行,而不是先统一加宽再检查,因为 Number.longValue() 本身对部分类型是有损的。超过 64 位的 DECIMAL(可通过 COALESCE(int_col, decimal_col) 到达)、BigInteger,以及来自 DOUBLE 的 NaN 或无穷, 现在都会被拒绝,而不是以截断后的值通过。
    • 小数来源的行为不变:通过 COALESCE 或 IFNULL 到达时,例如 5.7 仍然向零截断,而不是被拒绝, 这是该转换一直以来的行为,本次只改变范围相关的行为。而显式写成 CAST 到整型目标的浮点来源,在语句准备 阶段就会被拒绝,本次变更前后都是如此。注意截断这条路径与字符串来源仍然不同,Integer.parseInt("5.7") 会失败;是否统一两者是另一个决定。
    • BIGINT 由另一处变更覆盖:撰写本条目时它仍保持原有转换方式;针对它的范围检查见下方条目,原记录于 #12612。
    • 迁移指南:若希望在目标类型无法容纳该值时得到 NULL 而不是报错,请使用 TRY_CAST;或将目标类型 扩宽到足以容纳该值。如果确实需要截断语义,请显式计算,而不要依赖 CAST。

Zeta SQL Transform:数值来源转换为 BIGINT 时拒绝超出范围的值​

  • 行为变更:数值来源转换为 BIGINT 时不再静默回绕,而是直接失败
    • 受影响组件:seatunnel-transforms-v2,SystemFunction.castAs(Zeta SQL transform)
    • 说明:BIGINT | LONG 的数值分支使用 Number.longValue() 转换,它只保留 DECIMAL 或 BigInteger 的低 64 位,把 NaN 映射为 0,并把超出范围的 DOUBLE 饱和到 Long.MAX_VALUE。 在 dev 上实测:18446744073709551621(2^64+5)得到 5,18446744073709551616(2^64)得到 0,NaN 得到 0,1e30 得到 9223372036854775807。这些都不会被报告,因此该行会写入错误的 数字。现在该转换会按 Long.MIN_VALUE..Long.MAX_VALUE 做范围检查,并复用为 INT 添加的同一套 按数值族检查的逻辑。
    • 影响:如果作业(有意或无意地)依赖了回绕行为,现在会在溢出的那一行失败,而不是写入错误的数字。 范围内的值、精确的整型包装类型、扩宽转换和同类型转换均不受影响。
    • 可达路径是 COALESCE 与 IFNULL,而不是 CAST:显式的 CAST(... AS BIGINT) 不可能产生该问题, 因为规划阶段对 BIGINT 目标只接受 TINYINT、SMALLINT、INT、BIGINT 与 STRING 作为来源; 四种整型族都能无损加宽为 long,而 STRING 本来就会通过 Long.parseLong 报告自身的溢出。 DECIMAL 或 DOUBLE 是通过 COALESCE 与 IFNULL 到达该目标的,这两者的结果类型按第一个非空参数 推断,而不是按最宽的类型推断,因此 COALESCE(bigint_col, decimal_col) 的目标类型是 BIGINT, 并会静默收窄其中的 decimal。
    • TRY_CAST 无法把这些情况转成 NULL:原因同上。TRY_CAST(decimal_col AS BIGINT) 与 TRY_CAST(double_col AS BIGINT) 在语句准备阶段就会以 Unsupported CAST FROM ... AS type: BIGINT 被拒绝,因此永远不会走到 TRY_CAST 捕获失败的逐行路径。 对于超出范围的 STRING 来源,TRY_CAST 仍会返回 NULL,这是唯一以 cast 形式到达该转换的路径。
    • 小数来源的行为不变:通过 COALESCE 或 IFNULL 到达 BIGINT 的 5.7 这类值仍然向零截断, 而不是被拒绝。本次只改变范围相关的行为。
    • 迁移指南:来源为字符串时,若希望得到 NULL 而不是报错,请使用 TRY_CAST;或将目标类型扩宽到 足以容纳该值;如果确实需要截断语义,请显式计算,而不要依赖 COALESCE 与 IFNULL 推断出的收窄。 如果希望结果使用最宽的类型,而不是第一个参数的类型,请自己写出转换: COALESCE(CAST(int_col AS BIGINT), bigint_col)。 该写法仅适用于整型来源:DECIMAL 或 DOUBLE 没有到 BIGINT 的转换,请改为把它放在第一个参数, 例如 COALESCE(decimal_col, bigint_col)。但重排并非等价替换:当两个参数都非空时, 返回哪一个也会随之改变。

DuckDB BIT 和 ENUM 自动建表​

  • Catalog 未提供长度时,标量 BIT 和 ENUM 列现在保留未指定的 STRING 长度,不再使用原来的 1/255 回退值。 正长度保持不变。自动生成的列将使用 MySQL LONGTEXT 或 PostgreSQL text,不再使用原来的有界字符串类型。
  • 已有目标表不会自动扩容。传输超出原有限制的值前,请检查列定义并手动扩容。
  • 使用 create_index = true(默认值)时,如果这些列属于主键,MySQL 自动建表会失败:LONGTEXT 无法作为 使用完整列值的主键。请提前创建目标表,为主键显式选择能够容纳源数据且符合 MySQL 索引限制的有界类型, 并使用 schema_save_mode = "ERROR_WHEN_SCHEMA_NOT_EXIST" 保留该表结构。不要对手动定义的目标表使用 RECREATE_SCHEMA。任意指定索引前缀长度可能拒绝前缀相同但完整值不同的源主键,因此无法保持原有主键语义。

SQL 和 Calcite 向量运算​

  • 行为修正:VECTOR_NORM、INNER_PRODUCT、COSINE_DISTANCE、L1_DISTANCE、 L2_DISTANCE 和 VECTOR_NORMALIZE 在中间乘法或减法之前将 float 元素提升为 double。 有限输入不再仅因中间 float 运算溢出或下溢而得到错误的无穷大、NaN 或零, 结果的低位数字也可能发生变化。
  • 迁移建议:重放数据前,请检查阈值以及此前计算的向量指标或归一化向量。 配置项、类型、模式和状态格式均不变。空输入和实际零向量的处理方式不变。 未增加非有限输入的校验或清理策略;修正有限中间结果也可能影响与非有限元素混合时的结果。 归一化输出元素仍为 float,随机投影运算不受影响。

Helm Chart:默认关闭 Zeta REST API v1​

  • 行为变更:Kubernetes Helm chart 不再默认开启未鉴权的 Zeta REST API v1
    • 影响组件:Helm chart deploy/kubernetes/seatunnel(conf/hazelcast-master.yaml、 conf/hazelcast-worker.yaml、values.yaml)
    • 描述:此前 chart 将 hazelcast.network.rest-api.enabled 设为 true,在 Hazelcast 成员端口(5801)上 无鉴权地暴露了已废弃的 Zeta REST API v1(包括 submit-job、stop-job、encrypt-config、日志和线程 dump)。现在该项为 false,与独立部署的 config/hazelcast.yaml 默认值和 v1 文档保持一致。默认的 Prometheus Pod 注解也从 5801(/hazelcast/rest/instance/metrics)改为指向 8080 上的 REST API v2 / Jetty 监听(/metrics),两者返回相同的采样数据。
    • 影响:通过 5801 端口调用 REST API v1 的部署必须切换到 8080 端口的 REST API v2。直接抓取 5801/hazelcast/rest/instance/metrics(而非通过 Pod 注解)的 Prometheus 配置必须把目标改为 8080/metrics。通过 Hazelcast 客户端协议提交作业以及 8080 上的 REST API v2 不受影响。由于 ConfigMap 使用 subPath 挂载且 Deployment 没有配置校验和注解,运行中的 Pod 在重启前会继续使用旧设置,因此在 helm upgrade 之后请重启 master/worker Pod。
    • 迁移指南:使用 8080 端口上的 REST API v2(chart 文档中的接口)。如果确实需要 Zeta REST API v1,请在自定义 ConfigMap(existingConfigMap)中设置 rest-api.enabled: true,并通过 NetworkPolicy 限制成员端口 (5801)的访问。升级后重启 Pod 以应用新配置。

SQL ARRAY_MAX 和 ARRAY_MIN 精度​

  • 行为修正:整数和 DECIMAL 数组极值的精确比较
    • 影响范围:seatunnel-transforms-v2,使用 engine = ZETA(默认值)或 INTERNAL 的 Sql 转换,适用于 Zeta、Flink 和 Spark 执行引擎。
    • 变更说明:仅包含 Byte、Short、Integer、Long 和 BigDecimal 值的数组采用精确比较, 包括整数和 DECIMAL 值混合的情况。例如,对 BIGINT 值 [9007199254740992, 9007199254740993] 使用 ARRAY_MAX,现在选择 9007199254740993。 Long 值 1 与 BigDecimal 值 1.00000000000000000001 不再被视为相等。 只要包含 Float、Double 或其他 Number 子类型(包括 BigInteger),整个数组仍采用 原有的 double 排序,可能损失精度。
    • 影响:依赖舍入比较结果的作业可能选择不同的值。结果保留所选原始元素的类型和 DECIMAL 小数位数,因此不同的结果也可能具有不同的原始小数位数。值相等时保留第一个 元素。声明的输出类型、输入类型转换、null 处理和浮点排序规则保持不变。
    • 迁移指南:不需要迁移配置或状态。请检查依赖旧舍入结果的下游预期值。

Redis 认证​

  • Redis Source 和 Sink 现在会在 SINGLE 和 CLUSTER 模式下以非空白的 user 指定的用户认证。 此前,SINGLE 模式先使用仅密码认证,再执行 ACL SETUSER;CLUSTER 模式忽略 user。 连接初始化不再创建或修改 ACL 用户。
  • 升级前,请创建目标 ACL 用户并授予所需的命令和键权限,包括初始化连接器所需的 INFO, SINGLE 模式所需的 SELECT,以及 CLUSTER 模式下拓扑发现所需的 CLUSTER SLOTS。 将 auth 设置为该用户的密码。当 user 非空白时,省略密码或使用空字符串将发送空密码。
  • 如需继续使用默认用户,请移除 user,并在需要密码时保留 auth。 命名用户需要 Redis 6 或更新版本;未配置用户名的旧配置行为保持不变。

Zeta SQL Transform:内置 AES_ENCRYPT / AES_DECRYPT​

  • 行为变更:AES_ENCRYPT / AES_DECRYPT 现为内置函数
    • 影响范围:seatunnel-transforms-v2(Zeta SQL transform)。
    • 变更说明:AES_ENCRYPT(value, key[, iv]) 与 AES_DECRYPT(value, key[, iv]) 现为内置 Zeta SQL 函数,且分发顺序在用户注册的 ZetaUDF 之前。使用 AES/CBC/PKCS5Padding,输出 Base64;未显式提供 IV 时生成随机 IV 并拼接到密文头部,故 AES_DECRYPT 无需显式 IV 即可恢复。
    • 影响:若作业此前注册了名为 AES_ENCRYPT 或 AES_DECRYPT 的自定义 ZetaUDF(此前缺少内置函数时的变通做法),升级后将静默改用此内置实现而非 UDF。若该 UDF 使用了不同的密钥派生、IV 处理或输出编码,则已由 UDF 写入的密文可能无法解密(或在 CBC 填充校验以约 1/256 概率碰巧通过时解出垃圾)。
    • 迁移指南:重命名已有 UDF,或迁移到内置函数。如需与 FieldEncrypt 的 AesCbcEncryptor 保持线兼容,请使用带 base64: 前缀的密钥(裸密钥会按口令经 SHA-256 派生,不与 FieldEncrypt 互通)。完整契约见 SQL 函数。

RabbitMQ Connector​

  • 破坏性变更:amqps:// 连接现在会校验 Broker 证书
    • 影响范围:seatunnel-connectors-v2/connector-rabbitmq
    • 变更说明:此前使用 amqps:// 的 url/uri 建立连接时,会隐式启用“信任所有证书”的 TrustManager 且不校验主机名。现在 amqps:// 连接会强制校验证书,与 ssl = true 的 host/port 路径行为保持一致。
    • 影响:使用自签名或私有 CA 证书的 Broker,升级后通过 amqps:// 建立的连接将失败。
    • 迁移指南:将 Broker 证书(或私有 CA 证书链)导入 SeaTunnel 运行时的 JVM 信任库,或改用 host/port + ssl = true 配置并正确设置信任库。

FakeSource (connector-fake)​

  • 声明式选项约束现在在工厂校验阶段即强制生效,而不再静默放行、直到运行时才失败。受影响选项:split.num、 vector.dimension 和 binary.vector.dimension 必须 > 0;row.num、split.read-interval、map.size、 array.size、bytes.length 和 string.length 必须 >= 0;tinyint.min/max、smallint.min/max、 int.min/max、bigint.min/max、float.min/max、double.min/max 和 vector.float.min/max 必须满足 min <= max。注意 row.num = 0(空 Source)仍然有效。此前设置了无效值且成功运行的现有作业, 将在启动时快速抛出校验错误并失败。

SQL 数值条件的精度​

  • 行为变更:精确数值操作数不再通过 double 进行比较
    • 影响范围:seatunnel-transforms-v2,Sql 转换(ZETA 和 INTERNAL)。
    • 变更说明:当求值后的两个操作数均为整型或 DECIMAL 时,比较及 IN/NOT IN 判断保留精度, 包括搜索式和简单式 CASE 表达式中的比较。例如,BIGINT 值 9007199254740993 不再等于整数字面量 9007199254740992。
    • 影响:过滤条件可能选择不同的行,CASE 表达式也可能选择不同的分支。 涉及 FLOAT 或 DOUBLE 的比较保持原有行为。包含小数点的字面量仍求值为 DOUBLE, 一元负号会保留 DECIMAL 精度,-decimal_col 和 -CAST('...' AS DECIMAL(p, s)) 均如此。 每个 IN 元素独立选择精确或浮点比较, 因此混用精确类型和浮点类型时,仍可能匹配不同的大数值,且等号不保证传递性。
    • 迁移指南:请检查相关条件和 CASE 表达式,并核对、修正依赖此前舍入比较结果的已写入数据。 如需精确的小数常量,请使用带引号的字符串并保留足够的小数位,例如 CAST('-123456789012345678.99' AS DECIMAL(38, 2)) 或 -CAST('123456789012345678.99' AS DECIMAL(38, 2))。 现有 CAST 舍入行为不变:字符串/DECIMAL 输入在减少小数位时使用 CEILING, 因此在 CAST 之前或之后取负可能产生不同结果; FLOAT/DOUBLE 输入使用 HALF_UP,且无法恢复浮点求值时已丢失的精度。 示例与限制见数值比较。无需更改配置、输出结构或状态格式。

DataValidator 数组长度​

LENGTH 规则现在计算数组元素个数,而非数组的 Java 标识字符串长度。 因此,包含数组的行可能得到与此前不同的验证结果。请检查曾为适应旧行为而调整的数组长度限制, 并在重放数据前核对此前被跳过或路由到错误表的数据。 字符串、集合、二进制值和空值的处理保持不变,无需迁移配置或状态格式。

Zeta REST 分页参数校验​

  • 行为变更:分页接口开始校验 page 与 rows
    • 影响范围:seatunnel-engine-server,REST 接口 GET /finished-jobs/:state、GET /running-jobs 与 GET /running-jobs/summary。后两者由同一个 RunningJobsServlet 实例提供服务,因此都会受到该校验。
    • 变更说明:这些接口现在会拒绝非整数或不大于 0 的 page 与 rows,并拒绝起始偏移量会超出 32 位整数范围的分页请求。此前 rows=0 会被接受并返回空页,负数 rows 会引发内部错误,而足够大的 page 与 rows 组合可能溢出为一个较小的正偏移量,从而静默返回错误的页。
    • 影响:依赖 rows=0 返回空页的请求现在会收到 400,错误信息中会指明具体参数。传入合法正整数的调用方不受影响。响应结构、{"data": [...], "total": n} 包装格式,以及起始位置恰好等于 total 时仍返回空页的行为,均保持不变。

MySQL CDC Schema-Change 解析​

  • 行为变更:向上传播 DDL 解析监听器错误
    • 影响范围:connector-cdc-mysql
    • 变更说明:处理已解析 DDL 时发生的错误不再被吞掉并当作无操作处理,而是作为解析失败向上抛出,避免 CDC 作业静默跳过 schema 变更。
    • 影响:某些过去在内部解析器或监听器出错后被忽略的 DDL,升级后可能导致作业失败。请检查源端 DDL,修改为连接器支持的语法后再重启作业。本变更不修改 checkpoint 或 savepoint 格式。

MySQL-CDC:可空唯一键列中的 NULL 按 NULL 输出​

  • 行为变更:对于没有主键的表,MySQL-CDC 对可空唯一键列输出 NULL,而不是类型默认值
    • 影响组件:seatunnel-connectors-v2/connector-cdc/connector-cdc-mysql
    • 描述:对于没有主键的表,MySQL DDL 解析器(Debezium 1.9.8)会把第一个唯一键提升为主键,并把其中的列标记为 NOT NULL,尽管数据库允许这些列为 NULL。这些列中的 NULL 值在快照阶段和 binlog 阶段会被输出为类型默认值(例如 0、'' 或纪元时间),在 binlog 中出现 ALTER TABLE ... ADD UNIQUE KEY 或 CREATE UNIQUE INDEX 等 DDL 之后也是如此。现在这些列保持声明时的可空性,NULL 按 NULL 输出。真正的主键列不受影响。这一变更依赖于可空列不再被用作快照分片列(见“CDC:可空列不再用作快照分片列”):否则在 exactly_once = true 时,分片列中的 NULL 会导致分片范围检查失败。
    • 影响:Sink 现在会在原来收到类型默认值的位置收到 NULL。如果 Sink 列声明为 NOT NULL,或 Sink 的 primary_keys 包含这样的列,这些行可能会被拒绝。
    • 迁移指南:将受影响的 Sink 列改为可空,并且不要使用可空列作为 Sink 主键。如果作业从一个已经保存了此类表结构的 checkpoint 恢复(该表在 binlog 中出现过 DDL 之后保存),该表会保持旧行为,直到作业不使用该 checkpoint 重新启动。

JDBC Connector​

  • 破坏性变更:JDBC XA restore 改为基于 recovery 顺序证据并对缺口 fail-closed

    • 影响范围:seatunnel-connectors-v2/connector-jdbc sink 的 exactly-once XA 路径
    • 变更说明:SeaTunnel 现在会在单次 aggregated-commit 或 restore 调用内消耗完 max_commit_attempts。恢复时,只会从 XA recovery scan 中第一个仍然存在的 checkpoint XID 开始,严格回放其后的 prepared 事务后缀。位于该边界之前、且在 recovery scan 中缺失的 XID,只有在后缀严格提交成功之后才会被视为已经完成;如果 recovery scan 中一个 checkpoint XID 都不存在,SeaTunnel 会把整个批次视为已经完成并跳过回放;只有在第一个 recovered checkpoint XID 之后又出现缺失 XID 时,restore 才会直接 fail-closed,而不是仅凭 XAER_NOTA 这类“事务不存在”结果去推断已经提交成功。
    • 影响:以前依赖“XA 分支缺失即视为成功”的任务,在升级后如果 recovery scan 里仍然能看到后续 checkpoint XID、但中间出现缺口,可能会在恢复阶段收到明确的 XA restore 错误。另外,max_commit_attempts 现在会在一次 restore/commit 调用内耗尽,而不是分散到多次任务重启中。
    • 迁移指南:升级前请先检查资源管理器中是否还残留 prepared XA 事务,例如 MySQL 可使用 XA RECOVER,PostgreSQL 可检查 pg_prepared_xacts。如果升级后 restore 因为“后面仍有 checkpoint XID,但中间出现缺失 XID”而进入 fail-closed,请重点确认缺失 XID 是否被回滚、超时过期,或被外部清理,再决定后续恢复操作。XA recovery 无法区分 SeaTunnel 已提交的 XID 与被外部清理者回滚或删除的 XID。因此,位于 recovered 后缀之前的缺失 XID,或全部 XID 缺失的批次,会被推断为已经完成;在相关作业可能恢复时,不要对 SeaTunnel 所属的 prepared XA 分支执行外部清理,任何清理操作都应与作业恢复流程协调。
  • 破坏性变更:带时区的时间戳列映射为 TIMESTAMP_TZ 类型

    • 影响范围:seatunnel-connectors-v2/connector-jdbc、seatunnel-connectors-v2/connector-iceberg、seatunnel-connectors-v2/connector-cdc-base、seatunnel-connectors-v2/connector-cdc-tidb、seatunnel-connectors-v2/connector-starrocks、seatunnel-connectors-v2/connector-hudi、seatunnel-connectors-v2/connector-snowflake(通过 JDBC 方言)
    • 变更说明:以前,JDBC Source 将无时区(如 MySQL DATETIME)和带时区(如 MySQL TIMESTAMP)的时间戳列都映射为 SeaTunnel 内部的 TIMESTAMP 类型。现在,带时区的列(如 MySQL TIMESTAMP、PostgreSQL timestamptz、Oracle TIMESTAMP WITH LOCAL TIME ZONE、SQL Server datetimeoffset、Snowflake TIMESTAMP_LTZ/TZ 等)被显式映射为 TIMESTAMP_TZ。这确保了在写入 Iceberg 等格式时,时区语义得到准确保留(在 Iceberg 中 TIMESTAMP 存为无时区的 timestamp,TIMESTAMP_TZ 存为带时区的 timestamptz)。
    • 影响:如果您的下游 Sink 依赖接收 TIMESTAMP 类型且不支持 TIMESTAMP_TZ,您可能会遇到类型不匹配错误。对于 Iceberg 用户,这意味着以前作为 timestamp(无时区)写入的列现在可能会作为 timestamptz(带时区)写入,从而改变表结构。您可能需要在 SQL Transform 中转换该列或更新您的 Sink 配置。(#10685)
    • 各连接器具体行为变更:
      • Snowflake:TIMESTAMP_LTZ 和 TIMESTAMP_TZ 列现在映射为 OFFSET_DATE_TIME_TYPE(TIMESTAMP_TZ),而不是原来的 LOCAL_DATE_TIME_TYPE。这同时影响 Snowflake 的 Source 和 Sink 路径。
      • StarRocks:写入 StarRocks Sink 的 TIMESTAMP_TZ 值以 DATETIME(仅保留时钟时间,时区偏移量丢失)形式存储,这是由于 StarRocks 不支持原生带时区的日期时间类型。
      • Hudi:TIMESTAMP_TZ 现在映射为 Avro timestampMillis(UTC 纪元时间)。如果 Hudi 表不支持 Schema Evolution,以旧 Schema 写入的现有表可能需要重新创建。
      • CDC(基于 Debezium,TiDB):CDC 连接器现在可以正确处理 Debezium 反序列化层中的 TIMESTAMP_TZ 类型。以前,TIMESTAMP_TZ 不受支持,会抛出 UnsupportedOperationException。现在,在 CDC 管道中使用带时区列的用户可以正常使用。
      • Iceberg(已有表):在本 PR 之前,SeaTunnel 的 TIMESTAMP 类型错误地以带时区(withZone())的形式写入 Iceberg。本 PR 之后,TIMESTAMP 写为不带时区(withoutZone()),而 Iceberg withZone() 列读取时返回 TIMESTAMP_TZ。升级影响:如果您的 Iceberg 表是由旧版 SeaTunnel 创建的,其时间戳列以 withZone() 形式存储。升级后,SeaTunnel 会将其读取为 TIMESTAMP_TZ 而非 TIMESTAMP,下游 Sink 或 Transform 若期望 TIMESTAMP 类型可能遇到类型不匹配错误。迁移方案:重新创建受影响的 Iceberg 表,或在管道配置中使用 SQL Transform 将 TIMESTAMP_TZ 转换回 TIMESTAMP。
      • TIMESTAMP_TZ 写入约定:SeaTunnel 根据 Sink 格式的表达能力,对 TIMESTAMP_TZ 采用两级序列化约定:
        • Doris Sink:TIMESTAMP_TZ 会先转换到 Doris 的目标时区,再以 DATETIME 存储。可通过 sink.datetime-timezone 显式指定目标时区;未配置时,SeaTunnel 使用 JVM 默认时区。例如,配置 sink.datetime-timezone = "Asia/Shanghai" 时,2024-01-01T03:00:00+09:00 将存储为 2024-01-01 02:00:00。
        • 其他不支持原生时区类型的 DB 列类型 Sink(StarRocks、Xugu):丢弃时区偏移,保留时钟时间(wall-clock)。例如,2024-01-01T03:00:00+09:00 将存储为 2024-01-01 03:00:00。这是有损操作——仅凭存储值无法还原原始 UTC 时刻。
        • 基于字符串/文本的 Sink(Text 文件、Kafka、Pulsar、RocketMQ、RabbitMQ、Redis 等):保留完整的 ISO 8601 偏移(例如 "2024-01-01T03:00:00+09:00")。这些格式可以用字符串表示时区偏移,不会丢失信息。如果需要在这类 Sink 中使用 wall-clock 行为,请在写入前通过 SQL Transform 将 TIMESTAMP_TZ 转换为 TIMESTAMP。
      • Xugu TIMESTAMP_TZ(有损写入):Xugu TIMESTAMP WITH TIME ZONE 列在类型层面暴露为 TIMESTAMP_TZ,但由于 Xugu JDBC 驱动批量执行缺陷([E19138]),实际写入时会丢弃时区偏移,仅存储时钟时间。首次写入时会输出 WARN 日志。

API 变更​

  • 破坏性变更:Engine REST 表级指标 key 格式变化

    • 影响范围:SeaTunnel Engine REST API(/job-info 返回的 job metrics 中的表级指标)
    • 变更说明:为支持多个 Source/Sink/Transform 同时处理同一张表,表级指标的 key 格式从 {tableName} 变更为 {VertexIdentifier}.{tableName}(例如 Sink[0].fake.user_table)。
    • 影响:依赖旧 key 的 Grafana 仪表盘、Prometheus 告警规则以及自定义监控解析逻辑需要同步修改,否则升级后会出现指标查询/告警静默失效。

    变更前

    {
    "TableSinkWriteCount": {
    "fake.user_table": "15"
    }
    }

    变更后

    {
    "TableSinkWriteCount": {
    "Sink[0].fake.user_table": "10",
    "Sink[1].fake.user_table": "5"
    }
    }
  • 破坏性变更:运行期日志级别接口拒绝无法识别的级别

    • 影响范围:SeaTunnel Engine REST API — POST /hazelcast/rest/maps/log-level
    • 变更说明:该接口此前对任何请求都返回 200 和 {"status":"SUCCESS"},包括无法识别的级别名(DEBUGG、verbose、不存在的级别、空值)。这类请求实际上什么都没有生效,并且无法识别的级别会以 null 传给 log4j2,而 null 并不是"保持不变":它会清除该 logger 上显式设置的级别,于是 logger 静默回退到父级别,root logger 则回退到 ERROR。现在无法识别的级别、空级别以及缺少 level 参数都会返回 400,并在响应中列出有效级别;级别名仍然不区分大小写。
    • 影响:只检查 HTTP 状态码的脚本和自动化流程,对于原本就没有生效的请求,会从 200 变为 400。能够正确识别级别的请求行为不变。
    • 升级指南:请传入 log4j2 能识别的级别(OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、ALL,或配置中注册的自定义级别)。被拒绝请求的响应体会列出该节点接受的级别。
  • 破坏性变更:Condition.of(option, null) 不再允许

    • 影响范围:seatunnel-api — org.apache.seatunnel.api.configuration.util.Condition
    • 变更说明:Condition 构造器新增校验:二元字面量操作符(如 EQUAL、NOT_EQUAL、GREATER_THAN 等)的 expectValue 不能为 null。此前 Condition.of(option, null) 会被静默接受,现在会在构造时抛出 IllegalArgumentException。
    • 影响:主仓库中没有任何生产代码使用 Condition.of(option, null),实际影响为零。但如果自定义或第三方连接器代码依赖了这一用法,则需要修改。
    • 迁移指南:如需检测某个 option 是否缺省或未配置,请使用 Conditions.notBlank(option)(针对字符串类型)或在 OptionRule.Builder 层面使用 optional(...) 来处理缺失情况,而不是将 null 作为期望值传入。
  • 破坏性变更:OptionValidationException 消息格式变为结构化聚合

    • 影响范围:seatunnel-api — org.apache.seatunnel.api.configuration.util.ConfigValidator
    • 变更说明:ConfigValidator.validate(OptionRule) 现在会收集所有结构性错误和值约束错误,一次性抛出包含结构化多行消息的 OptionValidationException,而非遇到第一个错误就失败。

    变更前(快速失败,单条错误)

    ErrorCode:[API-02], ErrorDescription:[Option item validate failed] - There are unconfigured options, the options('host') are required.

    变更后(聚合、结构化)

    ErrorCode:[API-02], ErrorDescription:[Option item validate failed] - Option validation failed (2 errors):
    [1] option: 'host'
    type: required
    constraint: required option is not configured
    [2] option: 'port'
    type: value
    constraint: 'port' >= 1
    • 影响:通过子字符串匹配(如 "are required")解析异常消息,或假定单行错误格式的代码需要更新。错误码(API-02)和代码前缀与消息体之间的 " - " 分隔符保持不变。
    • 迁移指南:更新对 OptionValidationException.getMessage() 的字符串匹配逻辑以适配新的多行编号格式。可使用 getRawMessage() 获取不含 ErrorCode 前缀的消息体。

配置变更​

  • 破坏性变更:正式发布版本的连接器默认改为通过 HTTPS 直接下载

    • 影响范围:Linux 和 macOS 上的 bin/install-plugin.sh
    • 变更说明:对于固定的正式发布版本,脚本现在默认从 Maven Central 通过 HTTPS 直接下载连接器,并使用仓库发布的 SHA-512 或 SHA-1 校验文件验证完整性。此前所有连接器都通过发行包内置的 Maven Wrapper 解析。
    • 影响:如果现有环境依赖 Maven settings.xml 中配置的镜像、认证仓库、代理或自定义 TLS 策略,升级后使用默认命令安装正式版本连接器可能失败。
    • 迁移指南:运行 install-plugin.sh 时设置 SEATUNNEL_PLUGIN_DOWNLOAD_METHOD=maven,即可保留原有的 Maven 解析行为。也可以通过 SEATUNNEL_MAVEN_REPOSITORY 指定一个发布连接器校验文件的 HTTPS Maven 兼容镜像。
  • 破坏性变更:CatalogFactory 创建路径现在会校验 optionRule()

    • 影响范围:seatunnel-api — FactoryUtil.createOptionalCatalog()
    • 变更说明:FactoryUtil.createOptionalCatalog() 方法现在在创建 catalog 实例之前会调用 ConfigValidator.validate(catalogFactory.optionRule()) 进行校验。此前,catalog 创建路径不会对 catalog factory 的 option rules 执行任何校验。
    • 影响:如果 catalog factory 的 optionRule() 将某些选项声明为 required,而传入 createOptionalCatalog() 的配置中这些选项并不总是存在,则会抛出 OptionValidationException。这主要影响通过 JdbcCatalogUtils.findCatalog() 触发的 JDBC 连接器路径。
    • 迁移指南:如果您有自定义的 CatalogFactory 实现,请确保其 optionRule() 准确反映在运行时到达它的配置中,哪些选项是真正必填的,哪些是可选的。

连接器变更​

  • 破坏性变更:Doris Source 选项 doris.request.retriesdoris.deserialize.queue.size 更名为 doris.deserialize.queue.size

    • 影响范围:seatunnel-connectors-v2/connector-doris(DorisSourceOptions.DORIS_DESERIALIZE_QUEUE_SIZE)
    • 变更说明:异步 Arrow 反序列化队列大小选项的 key 自 #7895 引入时就带有笔误:key 被意外拼接成了 doris.request.retriesdoris.deserialize.queue.size,把前一个选项的名称(doris.request.retries)粘到了本意使用的 key(doris.deserialize.queue.size)上。现在该选项 key 修正为 doris.deserialize.queue.size。默认值(64)和选项行为均无变化。
    • 影响:显式配置了旧的错误 key doris.request.retriesdoris.deserialize.queue.size 的作业将不再读取到该配置,连接器会回退为默认队列大小 64。旧 key 是拼接笔误,基本只能从文档复制得到,因此绝大多数用户不受影响。
    • 迁移指南:如果您曾显式调优过该选项,请把 source 配置中的 key 重命名为 doris.deserialize.queue.size。
  • 行为变更:HTTP Sink 写入失败现在会使任务失败,而不再被静默丢弃

    • 影响范围:seatunnel-connectors-v2/connector-http/connector-http-base
    • 变更说明:此前 HttpSinkWriter.doHttpRequest 对非 200 的 HTTP 响应和任何请求异常(网络错误、超时、序列化错误)都只记录 error 日志后正常返回,导致失败的行/批次被静默丢弃,而作业继续运行、checkpoint 正常完成。现在这两种情况都会抛出 HttpConnectorException(REQUEST_FAILED),失败会传播到引擎并使任务/作业失败。
    • 影响:下游 HTTP 端点偶发返回非 200 或偶发不可达的作业,此前会带着静默丢数据继续运行;升级后会在第一次写入失败时大声失败。该连接器仍没有内置重试或死信机制,重新提交失败的作业可能重复投递失败前已成功的行——请确保接收端能够容忍重试/重启时的重复投递。
    • 迁移指南:无需更改配置。如果您的端点在正常业务中就会返回非 200 响应,请在 Sink 之前的环节处理这些响应,或在升级前引入外部重试机制。
  • 破坏性变更:ORC 文件 Sink 保留嵌套 Struct 字段名的大小写

    • 影响范围:seatunnel-connectors-v2/connector-file/connector-file-base(所有共享 OrcWriteStrategy 的 File/HDFS/S3/OSS ORC Sink)
    • 变更说明:此前,OrcWriteStrategy.buildFieldWithRowType(...) 在构建 ORC Schema 时,会将每个嵌套 ROW(struct)字段名强制转为小写,因此声明为 MD5 的嵌套字段在文件 footer 中被持久化为 md5。下游消费者按原始大小写名称读取该列时会得到 null/缺失值。本次移除了递归嵌套字段分支上的 .toLowerCase() 调用,嵌套 struct 字段名将按原始大小写写入文件 Schema。
    • 影响:升级后由 SeaTunnel 写入的 ORC 文件,其 Schema footer 中的嵌套字段名保留原始大小写。已经适配旧行为的用户(例如使用 orc.schema.evolution.case.sensitive=true 的 ORC Reader、设置 spark.sql.caseSensitive=true 的 Spark、或预期读到 md5 而非 MD5 的下游管道)将面临相反的问题:读取新文件时出现空值或 Schema 不匹配。同一目录下混合旧版本(小写嵌套字段名)和新版本(原始大小写)的文件时,相同逻辑列对应的嵌套 Schema 形态不一致,大小写敏感的 Schema 合并无法调和。
    • 迁移指南:
      • 混合版本目录:将目录重新物化,使所有文件都由新版本写入;或将旧版本与新版本文件分别写入不同目录,独立读取。
      • 大小写敏感的下游:在支持的情况下将 Reader 配置为大小写不敏感的 Schema Evolution,或在读取时重映射该列。
      • 仅大小写不同的同名兄弟字段(例如同一 struct 中同时存在 MD5 和 md5):现在可被表达;大小写不敏感的下游(如 Hive)可能将其视为歧义字段,如需保留请在源头消歧。
  • 破坏性变更:Google Bigtable Source 的 scan_row_limit 变为每个 split 的上限

    • 影响范围:seatunnel-connectors-v2/connector-google-bigtable
    • 变更说明:Enumerator 现在通过 sampleRowKeys 按 tablet 边界把表(或配置的 start_rowkey / end_rowkey 区间)切成多个 split。Reader 仍对每个 split 调用一次 query.limit(...)。此前 Source 始终只产生 1 个 split,因此 scan_row_limit 等价于整表行数上限。升级后,只要表有多个 tablet,即使 parallelism = 1(唯一 reader 会拿到全部 split),作业级上限约为 scan_row_limit × split 数。详见 Google Bigtable Source。
    • 影响:依赖 scan_row_limit 限制总输出量的存量作业(抽样、测试、成本控制、下游容量)在升级后、配置不变的情况下,可能读出远超以前的行数。
    • 迁移指南:若仍需要整表级上限,请用 start_rowkey / end_rowkey 收窄扫描范围,或下调 scan_row_limit,使 scan_row_limit × 预期 split 数 不超过原预算。采样失败、无采样点或求交为空时仍会回退为单个 split,但这不是用来锁定旧语义的受支持方式。(#11876)
  • CDC Connector:已从捕获集合移除的表不再复用恢复状态

    • 影响范围:seatunnel-connectors-v2/connector-cdc/connector-cdc-base 及其构建的 CDC 连接器。
    • 变更说明:CDC 任务从 checkpoint 或 savepoint 恢复时,SeaTunnel 现在会在分配恢复后的 split 前,按照当前捕获表集合过滤表级增量状态。已从任务捕获配置中移除的表,其状态不会再被复用;如果表发现不可用或返回空集合,为避免源数据库短暂异常时丢弃 checkpoint 元数据,SeaTunnel 会保持恢复状态不变。
    • 影响:任务移除捕获表后再从旧 checkpoint 恢复时,不再尝试恢复这些已移除表的增量状态,从而避免陈旧表元数据导致恢复失败。该行为仅作用于 checkpoint/savepoint 恢复;新启动的任务不受影响。
    • 迁移指南:无需修改配置。变更捕获表集合后恢复现有 CDC 任务前,请确认被移除的表确实不应继续参与该任务。
  • 破坏性变更:Iceberg 连接器 — 不再自动继承源表主键

    • 影响范围:seatunnel-connectors-v2/connector-iceberg
    • 变更说明:当未显式配置 iceberg.table.primary-keys 时,SchemaUtils.toIcebergSchema() 以前会回退使用 CDC 源表的主键。这会静默地将 identifier-field-ids 设置到自动创建的 Iceberg 表上,激活等值删除语义,导致 append-only CDC 管道中的 INSERT 数据静默丢失 (详见 #10747)。该回退行为已被移除。
    • 影响:使用 iceberg.table.upsert-mode-enabled=true 但未显式配置 iceberg.table.primary-keys 的任务,启动时将抛出 IllegalArgumentException 并快速失败。 依赖隐式 PK 继承来实现 upsert 语义的任务,需要显式设置 iceberg.table.primary-keys。
    • 迁移指南:
      • Upsert 模式任务:在 Iceberg sink 配置中添加 iceberg.table.primary-keys = "<主键列名>"。
      • Append-only CDC 任务:无需任何操作 — 不配置 iceberg.table.primary-keys 现在会正确使用纯 append writer,不会产生等值删除文件。
      • 已存在的 Iceberg 表(Glue/Hive 元数据中已有 identifier-field-ids)在运行时不受影响; 只有 sink 新建的表会改变行为。
  • 破坏性变更:File 源连接器拒绝大于 poi_excel_max_file_size(默认 50 MB)的 POI 引擎 Excel 文件

    • 影响范围:seatunnel-connectors-v2/connector-file(LocalFile、HdfsFile、S3File、FtpFile、SftpFile、OssFile、OssJindoFile、ObsFile、CosFile)
    • 变更说明:Apache POI 在读取任何行之前会将整个 Excel 工作簿完全加载到内存,对于较大的 .xls/.xlsx 文件可能导致 Zeta worker 严重 GC 压力甚至 OOM。新增 poi_excel_max_file_size 选项(默认 50 MB),POI 在构建工作簿之前会拒绝超过该限制的 Excel 文件。该校验同时覆盖普通 Excel 文件和归档(ZIP/TAR/TAR_GZ/GZ)中的 Excel 条目,且仅在 excel_engine = POI(默认值)时生效;流式读取的 excel_engine = EasyExcel 路径不受此限制。
    • 影响:此前以 POI 引擎读取大于 50 MB Excel 文件的任务(虽然成功但伴随严重内存压力)现在会以 FileConnectorException 快速失败,而不再可能导致 worker OOM。
    • 迁移指南:对于必须读取大 Excel 文件且 worker 内存充足的 POI 任务,可通过 poi_excel_max_file_size = <字节数> 调高限制;否则切换为 excel_engine = EasyExcel,该引擎惰性流式读取行,不受此限制约束。
  • 破坏性变更:移除 Prometheus Sink 的 flush_interval 选项

    • 受影响组件:seatunnel-connectors-v2/connector-prometheus
    • 变更说明:Prometheus Sink 不再启动自己的后台刷新线程,连接器级的 flush_interval 选项已被移除。定时刷新改为由引擎通过作业 env 中的 sink.flush.interval 驱动,仅 Zeta 引擎支持。
    • 影响:
      • Spark 和 Flink 会失去检查点之间的定时刷新。 被移除的 flush_interval 调度器是连接器自己的线程,在所有引擎上都能工作;其替代者 sink.flush.interval 是 Zeta 引擎的能力,Spark 和 Flink 的 Sink 写入器上下文并未实现它,因此这两个引擎上没有周期性定时刷新。在 Spark 和 Flink 上,缓存会在达到 batch_size、检查点时(Sink 在 prepareCommit() 中刷新)以及写入器关闭时被刷新。因此缓存的采样点最多保留一个检查点间隔,而不会一直保存到作业停止;如需降低检查点之间的延迟,请相应调整 batch_size。
      • 只有在使用 --check / --dry-run=static / --dry-run=connect 校验配置时(会执行 validateUnknownKeys),Prometheus sink 中残留的 flush_interval 键才会被拒绝。直接提交的作业会静默忽略该残留键;连接器会在每个 Sink 写入器启动时各打印一次告警作为替代提示(因此并行度为 N、多表或多副本的作业会多次打印)。
    • 迁移指南:从 Prometheus sink 中移除 flush_interval。如需在 Zeta 上继续使用定时刷新,请在作业 env 中设置 sink.flush.interval(毫秒)。在 Spark 和 Flink 上,缓存会在每个检查点被刷新;如需降低检查点之间的延迟,请调整 batch_size。batch_size 触发和写入器关闭时的最后一次刷新在所有引擎上保持不变。
  • 破坏性变更:File 连接器拒绝 XML 输入中的 DOCTYPE 声明(XXE 加固)

    • 影响范围:seatunnel-connectors-v2/connector-file/connector-file-base(XmlReadStrategy),以及所有基于该模块构建的 File Source:LocalFile、HdfsFile、S3File、OssFile、OssJindoFile、CosFile、FtpFile、SftpFile(file_format_type = xml)
    • 变更说明:此前 XML 读取器使用默认的 dom4j SAXReader 解析用户提供的文件,DTD 处理和外部实体解析均保持 JAXP 默认行为。精心构造的 DOCTYPE/外部实体载荷可能导致 worker 节点本地文件泄露、SSRF 式请求,或通过实体展开("billion laughs")耗尽内存。现在 XmlReadStrategy 的所有解析都会经过加固后的 reader:启用 JAXP 安全处理特性、彻底拒绝任何 <!DOCTYPE ...> 声明、禁用外部通用/参数实体及外部 DTD 加载,并额外安装一个拒绝一切解析请求的 EntityResolver 作为与具体解析器实现无关的兜底防护。
    • 影响:此前仅因携带 <!DOCTYPE ...> 声明才能被解析的 XML 文件——即使该声明是不引用任何外部 SYSTEM/PUBLIC 资源的良性声明——现在会以 FileConnectorException(FILE_READ_FAILED) 失败。该行为没有配置项可以恢复为旧版本的处理方式。
    • 迁移指南:在使用 SeaTunnel 读取前,移除 XML 文件中的 DOCTYPE 声明,或对文件做预处理/重新导出。不带 DOCTYPE 声明的合法 XML 文件不受影响。(#11250)

转换变更​

  • 行为变更:AMAZON 向量化遵循重试选项

    • 影响范围:配置 model_provider = AMAZON 的 Embedding 转换。
    • 变更说明:配置的 SeaTunnel 重试和退避选项现在会传递到 Bedrock 运行时。此前 Transform 忽略这些设置,只执行一次 SeaTunnel 尝试。
    • 影响及迁移:大于 1 的 model_retry_max_attempts 现在会启用 SeaTunnel 重试,可能产生额外模型费用;设置为 1 可保留单次 SeaTunnel 尝试,默认值仍为 1。SDK 自身的重试和超时行为保持不变;model_request_timeout_ms 目前不应用于 Bedrock 调用。
  • [BREAKING] SQL Transform 的 PARSEDATETIME、TO_DATE 和 IS_DATE 函数现在只接受白名单中的日期时间格式模式。以前接受的自定义格式模式现在将在运行时失败。支持的模式有:

    • DateTime: yyyy-MM-dd HH:mm:ss, yyyy-MM-dd HH:mm:ss.SSS, yyyy-MM-dd'T'HH:mm:ss, yyyy-MM-dd'T'HH:mm:ss.SSS, yyyy/MM/dd HH:mm:ss, yyyy/MM/dd HH:mm:ss.SSS, yyyyMMddHHmmss
    • Date: yyyy-MM-dd, yyyy/MM/dd, yyyyMMdd
    • Time: HH:mm:ss, HH:mm:ss.SSS, HHmmss

    异常类型变更: 无效的日期时间格式模式现在会抛出 SeaTunnelRuntimeException 而不是 TransformException。如果您的错误处理或监控系统捕获 TransformException 来处理日期时间解析错误,您需要更新它们以处理 SeaTunnelRuntimeException。

    迁移指南: 如果您在 PARSEDATETIME、TO_DATE 或 IS_DATE 函数中使用自定义日期时间格式模式,您必须更新查询以使用上述支持的模式之一。如果您的数据使用不同的格式,您可能需要预处理输入数据以匹配支持的格式,或使用字符串操作函数在解析之前转换格式。

  • DataValidator 转换:当 row_error_handle_way = ROUTE_TO_TABLE 时,路由到错误表的行 table_id 现在会携带上游的 database/schema 前缀(例如从 ffp 变为 db1.ffp / db1.schema1.ffp)。

  • [BREAKING] 多个转换插件现在通过声明式 OptionRule 在提交时执行更严格的配置校验。以前在提交时能通过但运行时失败的配置,现在会在提交时被拒绝,并抛出描述清晰的 OptionValidationException:

    转换插件新增拒绝的配置以前的行为迁移方式
    DefineSinkTypecolumns 条目中 column 或 type 为空运行时 NPE 或未定义行为确保每个条目都有非空的 column 和 type 字段
    DefineSinkTypecolumns 中存在重复列名静默覆盖或运行时冲突移除重复的列条目
    FieldEncryptmax_field_length 设置为 ≤ 0被忽略或产生意外截断设置为正整数,或移除该选项以使用默认值
    DynamicCompilecompile_pattern = SOURCE_CODE 但 source_code 为空运行时编译失败使用 SOURCE_CODE 模式时提供 source_code
    DynamicCompilecompile_pattern = ABSOLUTE_PATH 但 absolute_path 为空运行时文件读取失败使用 ABSOLUTE_PATH 模式时提供 absolute_path

    迁移指南:升级前请对照上表检查您的转换配置。如果现有配置匹配了"新增拒绝的配置"中的情况,请在升级前修改。提交时的错误消息会清楚标明哪个选项无效及原因。

  • 行为变更:每个 table_transform 条目都会在提交时校验

    • 影响范围:所有支持 table_transform 的转换:Copy、Calcite、DataValidator、DefineSinkType、DynamicCompile、FieldEncrypt、FieldMapper、Filter、FilterRowKind、JsonPath、Metadata、Python、RegexExtract、Replace、Sql、Split、TableMerge 和 TextChunk。
    • 变更说明:此前缺少 table_path 或 table_path 为空的条目会被静默过滤掉,条目被忽略但作业仍会运行;条目也不会在提交时按其单表规则校验,问题要到处理数据时才暴露。现在提交作业前就会校验:每个条目都必须用非空的 table_path 选中目标表,并且是该转换的完整单表规则;转换级规则要么不配置,要么配置完整。
    • 影响:带残留条目的配置(例如 table_transform = [{ field_rules = [...] }] 缺少 table_path)以前可以提交,现在会在提交时报错 Each 'table_transform' entry must select its table with a non-blank 'table_path';条目缺少必填选项时报错 Invalid 'table_transform' entry for table [...]。单表作业(没有 table_transform)不受影响。
    • 迁移指南:为每个条目补上 table_path,并按该转换的单表配置补全条目。不再使用的条目也可以直接删除,因为只配置 table_transform 的写法是合法的。
  • [BREAKING] Assert Sink:column_rule 里的 sink_type 现在会和实际列类型比较。此前会被忽略,所以声明不一致的作业会失败,不声明则仍不校验;升级时删掉该字段或改成实际类型。

  • [BREAKING] SQL 转换的 CEIL / CEILING、FLOOR 与 TRUNC / TRUNCATE 现在返回与参数相同的数据类型, 这与文档中一直声明的行为一致。此前无论输入类型如何,CEIL 和 FLOOR 都声明为 INT、TRUNC 声明为 DOUBLE, 从而静默产生错误的值:

    表达式输入以前的结果现在的结果
    CEIL(bigint_col)900719925474099319007199254740993
    FLOOR(double_col)1.0E1821474836471.0E18
    TRUNC(bigint_col)9007199254740993声明为 DOUBLE,实际返回 Long9007199254740993

    迁移指南:如果下游 Sink 的列是按旧的 INT / DOUBLE 输出类型创建的,请将其放宽为与源列一致的类型 (例如 CEIL(bigint_col) 对应 BIGINT),或使用显式的 CAST(... AS INT) 保持原有 schema。 对 INT 列的表达式不受影响。

  • [BREAKING] SQL 转换的 ROUND、TRUNC / TRUNCATE 和 MOD 不再将参数经由 double 中转, 因此 DECIMAL 和大 BIGINT 值可以保留完整精度。例如 ROUND(CAST('12345678901234567890.987654321' AS DECIMAL(38,9)), 2) 以前返回 12345678901234567000.00,现在返回 12345678901234567890.99;MOD(9007199254740993, 2) 以前返回 0, 现在返回 1。依赖旧的精度丢失结果的作业,其输出会发生变化(现在是正确的)。

  • [BREAKING] SQL Transform 对 DECIMAL 列的算术运算现在保持精确,并且除法改为四舍五入:

    • +、-、*、/ 的操作数之前通过 BigDecimal.valueOf(value.doubleValue()) 转换,会先退化为 double,丢弃约 17 位有效数字之后的全部内容。现在会保留完整精度——例如在 DECIMAL(38,2) 列上,123456789012345678.99 + 0.01 返回 123456789012345679.00,而不是 123456789012345680.01。
    • 除法现在使用 RoundingMode.HALF_UP 而不是 RoundingMode.UP。UP 总是向远离零的方向进位,因此在 scale 为 2 时,10 / 3 返回 3.34 而不是 3.33,1 / 1000 返回 0.01 而不是 0.00。
    • %(MOD)不受影响,它本来就委托给 MOD 函数,没有自行转换操作数。
    • * 现在会将结果舍入到输出列声明的 scale(HALF_UP),与 / 的既有行为一致。精确乘法得到的结果 scale 等于两个操作数 scale 之和,而该列声明的类型是 DECIMAL(max(precision), max(scale));若直接输出更宽的值,会导致按声明 schema 编码的 Sink 写入失败。在 DECIMAL(38,2) 列上,10.25 * 3.75 返回 38.44,而旧的有损转换对这组特定的值恰好返回 38.4375。
    • 除数为零的 DECIMAL 除法现在抛出标明该运算的 TransformException,而此前底层原因是 java.lang.ArithmeticException("/ by zero")。两种情况下出错的表达式本来就会被报告(SQL 引擎会包装表达式求值过程中抛出的任何异常),变化的只是 cause 的类型。这与 MOD 除零一直以来的报错方式保持一致。

    迁移指南:之前被旧舍入模式抬高、或被 double 转换截断的结果都会发生变化。乘法结果的小数位数可能比以前更少:旧的转换有时会输出比列声明 scale 更宽的值,现在该值会被舍入到声明的 scale,因此原先从 DECIMAL(38,2) 列读到 38.4375 的作业,升级后会读到 38.44。如果下游系统已按旧值对账,升级后需要重新校准。任何为兼容旧行为而做的补偿(例如在除法后减去一个修正值)都应当移除。如果有代码检查除法失败的 cause 并匹配 ArithmeticException,需要改为 TransformException。

  • [BREAKING] SQL 转换的 ABS,以及使用负数位数的 ROUND / CEIL / CEILING / FLOOR,现在当结果无法用参数自身的数据类型表示时, 会抛出 TransformException,而不再静默回绕成一个错误的(通常为负数的)值:

    表达式参数类型之前的结果当前的结果
    ABS(-2147483648)INT-2147483648TransformException
    ABS(-9223372036854775808)BIGINT-9223372036854775808TransformException
    ROUND(2147483647, -1)INT-2147483646TransformException
    ROUND(9223372036854775807, -1)BIGINT-9223372036854775806TransformException
    CEIL(32767, -1)SMALLINT-32766TransformException
    FLOOR(-2147483648, -1)INT2147483646TransformException

    ABS 的文档一直是这样描述的——“ABS(-2147483648) 应该是 2147483648,但是这个值对于这个数据类型是不允许的。这会导致异常”——只是实现从未真正这么做。 TRUNC / TRUNCATE 向零舍入,绝不会把值撑出自身的取值范围,因此不受影响;FLOAT、DOUBLE 和 DECIMAL 参数同样不受影响。

    迁移指南:之前会输出这些回绕值的作业,现在会在发生溢出的那一行失败。可以把参数转换为更宽的类型以保持作业运行——例如 ABS(CAST(int_col AS BIGINT)) 或 ROUND(CAST(int_col AS BIGINT), -1)——或者在上游过滤掉这些行。如果下游系统已按旧的回绕值对账, 升级后需要重新校准。

  • [BREAKING] SQL 转换现在能正确处理数值函数中此前被遗漏的 TINYINT 和 SMALLINT 参数。 ROUND / CEIL / CEILING / FLOOR / TRUNC / TRUNCATE 缺少 TINYINT 分支,因此 TINYINT 参数会直接穿过类型 switch 并被原样返回,既不舍入,也没有异常和日志。ABS 和 SIGN 缺少 TINYINT 与 SMALLINT 分支,会直接拒绝这些列:

    表达式参数类型之前的结果当前的结果
    ROUND(44, -1)TINYINT44,静默未舍入40
    CEIL(44, -1)TINYINT44,静默未舍入50
    ROUND(127, -1)TINYINT127,静默未舍入TransformException,130 超出 TINYINT
    ABS(-44)TINYINTTransformException,“Unsupported arg type”44
    ABS(-300)SMALLINTTransformException,“Unsupported arg type”300
    SIGN(-44)TINYINTTransformException,“Unsupported arg type”-1

    该类型 switch 同时补上了 default 分支,因此任何未被处理的数值类型现在会抛出 TransformException,而不再被原样返回。 SIGN 处理 DECIMAL 参数时改用 BigDecimal.signum() 而非 double 转换,因此小于 Double.MIN_VALUE 的值会返回真实 符号,而不是 0。

    迁移指南:之前 TINYINT 列静默跳过舍入的作业,现在会得到真正舍入后的值;如果下游系统已按旧的未舍入结果对账, 升级后需要重新校准。如果舍入后的 TINYINT 超出自身类型范围,可以把参数转换为更宽的类型——例如 ROUND(CAST(tiny_col AS INT), -1)——或者在上游过滤掉这些行。此前为绕开 ABS / SIGN 拒绝而使用的强制转换 (ABS(CAST(tiny_col AS INT)))仍然可以正常工作,可以在方便时再简化。

格式变更​

  • 破坏性变更:JSON 数值字段的序列化改为按运行时实际类型处理
    • 影响范围:seatunnel-formats/seatunnel-format-json(RowToJsonConverters)--影响所有以 JSON 格式序列化行的连接器(例如 Kafka、RabbitMQ、Pulsar 及文件 JSON Sink)。
    • 变更说明:以前,目录 Schema 中声明为数值类型(TINYINT、SMALLINT、INT、BIGINT、FLOAT、DOUBLE、DECIMAL)的字段,序列化时会把运行时值强制转换为声明类型对应的 Java 类型(例如 BIGINT 直接 (long) value)。在多表作业(例如多表 CDC 作业写 JSON 到 RabbitMQ/Kafka)中,多张表共享同一份目录 Schema 但物理列类型不一致时,String 或 BigDecimal 运行时值会抛出原始 ClassCastException 并导致作业失败。现在数值字段按运行时实际类型序列化:任意数值包装类型(Byte、Short、Integer、Long、Float、Double、BigInteger、BigDecimal)输出为对应的 JSON 数字;可解析为数字的字符串会解析成 JSON 数字,无法解析的文本则输出为 JSON 字符串;声明为 DECIMAL 的字段遇到 Float/Double 运行时值时,通过 BigDecimal.valueOf 序列化以避免浮点表示误差。
    • 影响:以前因 ClassCastException 崩溃的异构数值现在可以正常序列化,输出的 JSON 数值形态跟随运行时值而非声明的列类型(BIGINT 列中的 String 或 BigDecimal 值会保留其精确数值)。既不能表示为数字、也无法从文本解析的运行时值(例如 byte[]、Map、LocalDateTime)将以类型化的 SeaTunnelJsonFormatException(UNSUPPORTED_DATA_TYPE)快速失败,替代原来的原始 ClassCastException。假定 JSON 数值形态始终与声明列类型一致的下游消费方需要重新评估。(#11415)

引擎行为变更​

  • 文件型 IMap 存储:启动时自动重映射 WAL 文件中的旧版作业模型类名

    • 受影响组件:seatunnel-engine/seatunnel-engine-storage/imap-storage-plugins/imap-storage-file
    • 描述:SeaTunnel 3.0 将作业状态模型类(JobStatus、JobResult、JobStatusData)从 org.apache.seatunnel.engine.core.job.* 迁移到了 org.apache.seatunnel.engine.common.job.*(#9689)。迁移之前版本写入的 WAL 文件仍记录旧的完整类名,在当前发行版上回放会抛出 ClassNotFoundException。文件型 IMap 存储现在在读取 WAL 条目时会自动将这三个旧类名重写到当前位置,无需任何配置变更。
    • 影响:使用文件型 IMap 持久化的集群可以跨 #9689 迁移直接升级重启,无需手工修改 WAL 数据。写入不受影响:新的 WAL 条目始终记录当前类名。注意该重写是单向的:当前发行版写出的 WAL 文件中的类名无法被旧版本解析,因此在写出新 WAL 条目后回滚降级集群时,需要删除或手工改写已持久化的 WAL 数据。(#11781)
  • 行为变更:REST 日志内容接口默认最多返回 64 MB

    • 受影响组件:seatunnel-engine-server,REST v2 接口 GET /logs/:file、GET /log/:file, 以及对应的 REST v1 接口 GET /hazelcast/rest/maps/logs/:file、GET /hazelcast/rest/maps/log/:file。
    • 说明:这些接口原本会把整个日志文件读入内存,且会在堆上生成两份副本,因此对长时间运行的流作业 发起一次日志请求就可能耗尽节点内存。新增的 seatunnel.engine.http.log-response-max-size-mb 选项限制单次读取的大小,默认值为 64。超过该限制的文件只返回末尾 log-response-max-size-mb 的 UTF-8 内容,尽量从完整行开始;超长单行则保留部分末尾内容。响应开头的提示写明实际保留的字节数和文件大小快照。
    • 影响:升级后未修改 seatunnel.yaml 的集群,对超过 64 MB 的日志文件将只得到末尾内容, HTTP 状态码仍为 200。所有通过这些接口归档日志的用法——例如 curl .../logs/<job-id> > job.log,或 docs/zh/engines/zeta/log-analysis-with-ai.md 中的日志分析流程——在不调高限制的情况下都只会保存到部分内容。第一行的截断提示可以用来识别 响应是否完整。
    • 迁移指南:在 seatunnel.engine.http 下设置 log-response-max-size-mb: 0 可恢复此前的不限制读取,也可以把它调高到 足以覆盖需要收集的日志大小。建议保留默认值,因为不限制读取意味着多 GB 的日志需要完整放进节点堆内存。
  • 行为变化:引擎启动阶段的部分日志输出发生变化

    • 影响组件:seatunnel-engine-server(SeaTunnelServer、AbstractResourceManager、 StandaloneResourceManager);仅影响基于日志的监控。
    • 描述:SeaTunnel server start...、Init ResourceManager 和 initWorker... 这三行日志不再 输出;Worker 同步改为 Synchronizing existing worker profiles,standalone 资源管理器输出 Init standalone ResourceManager。
    • 影响:按旧文案匹配的告警或日志解析不再命中;运行时行为和集群生命周期不变。
    • 迁移指南:改为匹配新文案,或按前后生命周期事件判断,而不要匹配具体字符串。

依赖升级​