跳到主要内容

2 篇博文 含有标签「CDC」

查看所有标签

· 阅读需 24 分钟

在企业级数据集成中,数据一致性 是技术决策者最关心的核心问题之一。但在这个看似简单的诉求背后,实际隐藏着复杂的技术挑战和架构设计。

当企业用户使用 SeaTunnel 进行 批流数据同步 时,通常会关注这些问题:

🔍 “如何确保源库和目标库之间的数据完整性?”
🔄 “任务中断或恢复后,能否避免数据重复或丢失?”
⚙️ “全量同步与增量同步过程中,如何保证一致性?”

本文以 Apache SeaTunnel 2.3.13 为配置基线,说明 读取一致性、写入一致性和状态一致性 如何协同工作。“零丢失”和“零重复”并非默认能力,而是有前提的结果:Source 和 Sink 语义必须兼容,Checkpoint 必须成功完成,还需要正确的主键或唯一键以及文档要求的 exactly-once 配置。

下文示例和术语以 2.3.13 版本的 MySQL-CDC SourceJDBC SourceJDBC SinkJob Env 配置 文档为准。

一、理解数据一致性的三个维度

在数据集成领域,“一致性”并不是一个单一概念,而是一组覆盖多个维度的保障。为了便于分析,本文将 SeaTunnel 的相关机制归纳为三个维度:

读取一致性

读取一致性 确保从源端系统获取的数据,在某个时间点或事件序列上保持逻辑完整性。这个维度解决的是“应该采集哪些数据”的问题:

  • 全量读取:在特定时间点获取完整的数据快照
  • 增量采集:准确记录所有数据变更事件(CDC 模式)
  • 无锁快照一致性:设置 exactly_once = true 时,通过 low watermark 和 high watermark 补齐快照期间发生的变更

写入一致性

写入一致性 确保数据能够可靠、正确地写入目标端系统,解决的是“如何安全写入”的问题:

  • 幂等写入:存在稳定主键/唯一键且启用 Upsert 语义时,同一个键被重放只会更新一条目标记录
  • 事务完整性:当 Sink 支持时,将单个 Sink Writer 处理的数据放入与 Checkpoint 对齐的事务中提交
  • 错误处理:从已完成的 Checkpoint 恢复,重放行为由 Source 和 Sink 语义共同决定

状态一致性

状态一致性 是连接读取端和写入端的桥梁,确保整个数据同步过程中的状态跟踪与恢复:

  • 位点管理:记录读取进度,用于精确增量同步
  • Checkpoint 机制:周期性保存任务状态
  • Checkpoint 恢复:从已完成的 Checkpoint 恢复;该 Checkpoint 之后的数据可能被重放,除非 Sink 具备幂等或事务型 exactly-once 能力

二、MySQL 同步架构:CDC 与 JDBC 模式对比

SeaTunnel 提供两种主流的 MySQL 数据同步模式:JDBC 批模式CDC 实时采集模式。这两种模式适用于不同业务场景,并且在一致性保障上各有特点。

CDC 模式:基于 Binlog 的低延迟变更采集

MySQL-CDC Connector 基于嵌入式 Debezium 框架实现,直接读取并解析 MySQL 的 binlog 变更流:

核心优势

  • 低延迟:持续读取 binlog 变更,实际延迟取决于源端负载、网络和任务资源
  • 减少轮询:避免反复轮询业务表,但初始化快照仍会消耗源端资源
  • 完整性:完整捕获 INSERT/UPDATE/DELETE 事件
  • 变更元数据:输出携带 binlog 位点元数据的行级变更事件

恢复与顺序特征

  • 在 Checkpoint 中保存 binlog 文件名和位点,用于失败恢复
  • 支持多种启动模式(初始化快照 + 增量 / 仅增量)
  • 保持单个 Source Reader 观察到的事件顺序;端到端顺序仍受表路由、并行度和下游处理影响

MySQL-CDC 不会把一个源端事务转换成一个下游原子事务。Connector 输出的是独立的行级变更事件,最终交付语义由 Checkpoint 和 Sink 能力决定。

JDBC 模式:基于 SQL 的批量同步方案

JDBC Connector 通过 SQL 查询从 MySQL 读取数据,适用于周期性全量同步或低频变更场景:

核心优势

  • 开发简单:基于标准 SQL,配置灵活
  • 全量同步:适合大规模数据初始化
  • 过滤能力:支持复杂 WHERE 条件过滤
  • 并行加载:可基于主键或范围进行多分片并行读取

恢复特征

  • 跟踪 JDBC Split,而不是 Split 内部的行级 offset
  • 失败后重新分配或重放未完成的 Split
  • 支持表级并行处理

因此,JDBC Source 是 Split 级恢复。失败时,正在处理的 Split 可能从其边界重新读取,重复数据必须由幂等 Sink 或事务型 exactly-once Sink 处理。

三、读取一致性:如何确保源端数据完整采集

CDC 模式:基于 Binlog 的精确增量读取

MySQL-CDC Connector 的读取一致性基于两个核心机制:初始化快照Binlog 位点跟踪

启动模式与一致性保障

SeaTunnel 的 MySQL-CDC 提供多种启动模式,用于满足不同场景下的一致性要求:

  1. Initial Mode:先创建全量快照,再继续读取增量 binlog。如果快照阶段必须补齐 low watermark 与 high watermark 之间的变更,需要设置 exactly_once = true

    MySQL-CDC {
    startup.mode = "initial"
    exactly_once = true
    }
  2. Latest Mode:只采集 Connector 启动之后的最新变更

    MySQL-CDC {
    startup.mode = "latest"
    }
  3. Specific Mode:从指定 binlog 位点开始同步

    MySQL-CDC {
    startup.mode = "specific"
    startup.specific-offset.file = "mysql-bin.000003"
    startup.specific-offset.pos = 4571
    }

此外还有 earliest 启动模式:从能够找到的最早 offset 开始;以及 timestamp 启动模式(startup.timestamp):从用户指定的毫秒级时间戳开始。

JDBC 模式:基于分片的高效批量读取

JDBC Connector 通过智能分片策略实现高效并行读取:

分片策略与一致性

  • 主键/唯一键分片:存在受支持的键时,按该键拆分表
  • 指定分片列:自动发现的键不合适时,通过 partition_column 指定分片列
  • 均匀或采样分片:根据键分布和配置的阈值选择分片策略

SeaTunnel JDBC 读取分片示例配置:

Jdbc {
url = "jdbc:mysql://source_mysql:3306/test"
driver = "com.mysql.cj.jdbc.Driver"
user = "root"
password = "password"
table_path = "test.users"
split.size = 10000
split.even-distribution.factor.upper-bound = 100
split.even-distribution.factor.lower-bound = 0.05
split.sample-sharding.threshold = 1000
}

通过这种方式,SeaTunnel 可以实现:

  • 并行处理相互独立的 Split
  • 通过 Checkpoint 跟踪待处理的 Split 状态
  • 恢复时从 Split 边界重放未完成的 Split

这不是行级断点续传。如果重放可能让同一行多次到达目标端,应使用具备稳定主键/唯一键的幂等 Upsert,或启用受支持的 exactly-once Sink。

四、写入一致性:如何确保目标端数据准确

在数据写入阶段,SeaTunnel 提供可配置机制,用于控制目标端 MySQL 的重放与事务行为。

幂等写入:确保数据不重复

SeaTunnel 的 JDBC Sink Connector 通过多种策略实现幂等写入:

Upsert 模式

幂等写入示例配置:

Jdbc {
url = "jdbc:mysql://target_mysql:3306/test"
driver = "com.mysql.cj.jdbc.Driver"
user = "root"
password = "password"
generate_sink_sql = true
database = "test"
table = "users"
primary_keys = ["id"]
enable_upsert = true
}

批量提交与优化

JDBC Sink 的批处理和重试行为由固定配置明确控制:

  • 固定批大小batch_size 控制缓冲记录达到多少条时触发 Flush
  • Checkpoint 对齐 Flush:Checkpoint 处理过程中也会刷新缓冲数据
  • 显式重试次数max_retries 控制批执行重试,默认值为 0;启用 XA exactly-once 时必须保持为 0

分布式事务:XA 保障与两阶段提交

对于受支持的 Connector 路径,JDBC Sink 会将每个 Writer 的 XA 事务与 SeaTunnel Checkpoint 协调起来:

启用 XA 分布式事务的示例配置:

Jdbc {
url = "jdbc:mysql://target_mysql:3306/test"
driver = "com.mysql.cj.jdbc.Driver"
user = "root"
password = "password"
generate_sink_sql = true
database = "test"
table = "users"
primary_keys = ["id"]
enable_upsert = true
max_retries = 0
is_exactly_once = true
xa_data_source_class_name = "com.mysql.cj.jdbc.MysqlXADataSource"
max_commit_attempts = 3
}

XA 事务作用范围

  • 每个 Sink Writer 为一个 Checkpoint 准备自己的 XA 事务
  • Checkpoint 完成后提交已 Prepare 的事务
  • 恢复时,Connector 按协议处理该 Writer 未完成或已 Prepare 的事务

这为每个受支持的 JDBC Sink Writer 提供与 Checkpoint 对齐的 exactly-once 交付,但它不会将源端事务原样保留为一个下游事务,也不是跨多个表、Writer 或数据库的单一全局原子事务。跨系统业务原子性需要单独的事务设计。

五、状态一致性:断点续传与失败恢复

基于 Checkpoint 的状态管理为受支持的 Source 和 Sink Connector 提供可恢复的边界。

分布式 Checkpoint 机制

SeaTunnel 在分布式环境中实现状态一致性 checkpoint:

核心实现原则

  1. 位点记录:CDC Source 记录 Split offset;JDBC Source 记录 Split 状态,但不记录正在处理的 Split 内部行级 offset
  2. Checkpoint 触发:按照 checkpoint.interval 周期性调度 Checkpoint
  3. 状态持久化:将状态信息持久化到存储系统
  4. 失败恢复:恢复最近一次已完成的 Checkpoint;该 Checkpoint 之后的工作可能被重放

有前提的端到端交付语义

SeaTunnel 通过 Checkpoint 协调 Source 和 Sink 状态,最终交付语义取决于两端 Connector 及其配置:

使用 at-least-once Sink 时,重放可能产生重复写入。存在稳定主键/唯一键时,幂等 Upsert 可以吸收重复。JDBC XA exactly-once 还要求 is_exactly_once = true、兼容的 XA DataSource、max_retries = 0、已启用 Checkpoint 以及数据库端支持。

Checkpoint 配置示例

env {
checkpoint.interval = 5000
checkpoint.timeout = 60000
}

六、实战配置:MySQL CDC 到 MySQL 全量 + 增量同步

下面通过一个实战示例,展示如何配置 SeaTunnel 来实现可靠的 MySQL 到 MySQL 数据同步。

经典 CDC 模式配置

下面的 SeaTunnel 2.3.13 示例启用了 MySQL-CDC 快照一致性和与 Checkpoint 对齐的 JDBC XA 交付。其保障成立的前提包括:源端和目标端具有稳定主键、MySQL 驱动及服务端支持 XA、Checkpoint 存储可靠且 Checkpoint 成功完成。它不是跨两个目标表的全局事务。

env {
job.mode = "STREAMING"
parallelism = 3
checkpoint.interval = 60000
checkpoint.timeout = 120000
}

source {
MySQL-CDC {
url = "jdbc:mysql://source_mysql:3306/test_db"
username = "root"
password = "password"
database-names = [
"test_db"
]
table-names = [
"test_db.mysqlcdc_to_mysql_table1",
"test_db.mysqlcdc_to_mysql_table2"
]
server-id = "5400-5408"

# Initialization mode (full + incremental)
startup.mode = "initial"
exactly_once = true

# Enable DDL changes
schema-changes.enabled = true

# Parallel read configuration
snapshot.split.size = 8096
snapshot.fetch.size = 1024
}
}

transform {
# Optional data transformation processing
}

sink {
Jdbc {
url = "jdbc:mysql://mysql_target:3306/test_db?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
driver = "com.mysql.cj.jdbc.Driver"
user = "root"
password = "password"
generate_sink_sql = true
database = "${database_name}"
table = "${table_name}"
primary_keys = ["${primary_key}"]
schema_save_mode = "CREATE_SCHEMA_WHEN_NOT_EXIST"
data_save_mode = "APPEND_DATA"
enable_upsert = true
max_retries = 0
is_exactly_once = true
xa_data_source_class_name = "com.mysql.cj.jdbc.MysqlXADataSource"
}
}

生产使用前,应确认每张路由表都能正确解析 ${primary_key},且目标表具有匹配的主键或唯一键。如果不具备这些前提,应将任务描述为 at-least-once,而不是零重复。

七、一致性校验与监控

任务上线后,必须使用独立方法验证一致性。应记录源端 binlog 位点等逻辑切面,等待目标端追平后比较固定快照,或者在停止写入的窗口内比较;直接比较持续变化的源端与存在延迟的目标端,既不能证明一致,也不能证明不一致。

数据一致性校验方法

  1. 行数对比:在同一一致性窗口内,按相同主键范围比较记录数

    -- Source database
    SELECT COUNT(*) FROM source_db.users;

    -- Target database
    SELECT COUNT(*) FROM target_db.users;
  2. 确定性分段摘要:按主键顺序读取有界范围内的规范化记录,由校验程序计算 SHA-256 等强摘要

    SELECT id, name, updated_at
    FROM users
    WHERE id >= ? AND id < ?
    ORDER BY id;

    哈希前必须为每个字段定义明确的 NULL 标记和无歧义的长度或转义规则,再逐段比较行数与摘要。不要使用 SUM(CRC32(CONCAT_WS(...))):CRC32 碰撞和 NULL 处理都可能掩盖差异。

  3. 按主键下钻:某个范围存在差异时,按主键逐行比较。随机抽样适合定位问题,但不能证明全量一致。

一致性监控指标

SeaTunnel 任务执行过程中,应监控真实的 Connector 指标和 Checkpoint 信号:

  • CDCRecordFetchDelay:CDC 记录抓取阶段观测到的延迟
  • CDCRecordEmitDelay:CDC 记录输出阶段观测到的延迟
  • Checkpoint 状态:引擎报告的完成、超时和失败信号
  • 外部校验结果:由独立校验任务或数据质量平台产生的行数、摘要和逐行差异

“写入成功率”和“数据偏差率”不是 SeaTunnel 内置的一致性证明。如果在外部监控系统中定义这些指标,必须明确时间窗口和分母。

八、最佳实践与性能优化

以下建议遵循 SeaTunnel 2.3.13 的 Connector 契约。上线前仍需使用具有代表性的数据量和故障场景完成基准与恢复验证。

一致性场景配置建议

  1. 高可靠场景(例如核心业务数据):

    • 启用 MySQL-CDC exactly_once 和周期性 Checkpoint
    • 仅在驱动与数据库兼容时使用 JDBC XA,并保持 max_retries = 0
    • 配置稳定的目标端主键/唯一键与幂等 Upsert
    • 使用可靠的 Checkpoint 存储,并验证重启、超时和已 Prepare 事务恢复
  2. 高性能场景(例如分析类应用):

    • 使用 CDC 模式 + 批量写入
    • 仅在可以接受 at-least-once 或幂等重放时关闭 XA
    • 增大 batch size
    • 优化并行度设置
  3. 大规模初始化场景

    • 一个任务需要同时覆盖快照与增量时,优先使用 MySQL-CDC initial 模式
    • 仅在具备协调切换方案并能记录对应 binlog 位点时使用 JDBC 初始化
    • 配置合适的分片大小
    • 根据服务器资源调整并行度
    • 不要直接从 JDBC 切换到 CDC;未协调的切换可能产生数据缺口或重叠

常见问题与解决方案

  1. 网络环境不稳定

    • 调整连接超时和任务级恢复配置
    • 启用 XA exactly-once 时保持 JDBC Sink max_retries = 0
    • 依赖已完成的 Checkpoint,并验证实际重放行为
    • 考虑使用更小的 batch size
  2. 高并发写入场景

    • 根据目标数据库的连接和写入能力调整任务并行度
    • 测量锁与事务压力后,再考虑表分区或增大批次
  3. 资源受限环境

    • 降低并行度
    • 仅在接受更大恢复/重放窗口后增加 Checkpoint 间隔
    • 优化 JVM 内存配置

九、结语:SeaTunnel 的一致性保障之路

SeaTunnel 为可靠的批流同步提供了必要机制,但最终保障属于完整任务配置和外部系统共同形成的结果。必须同时评估 Source 位点、已完成的 Checkpoint、幂等键以及 Sink 事务。

SeaTunnel 的一致性保障理念可以总结为:

  1. Source 恢复状态:CDC 位点或 JDBC Split 状态决定从哪里恢复
  2. Checkpoint 协调:已完成的 Checkpoint 对齐可恢复的 Source 与 Sink 状态
  3. 明确的 Sink 语义:幂等 Upsert 或受支持的 XA 决定如何处理重放
  4. 独立校验:基于一致性窗口的对账用于验证最终结果

满足这些前提时,SeaTunnel 可以在受支持的 Connector 路径上提供零丢失、零重复的交付语义。它不会自动提供跨表或跨数据库原子性,可达到的数据规模和延迟也必须通过具体工作负载验证。


如果你对 SeaTunnel 的数据一致性机制还有更多问题,欢迎加入社区交流。

· 阅读需 10 分钟
David Zollo

问一位数据工程师他的管道是 ETL 还是 ELT,几乎总能得到秒答——老派工程师说 ETL,dbt 用户说 ELT。

但这两个答案都不完整。有第三种模式更准确地描述了现代数据管道实际在做的事——它一直存在,只是没有被命名:EtLT


三种范式

ETL:落库前先转换

原始数据从源端提取后,经过专用转换层(Spark、DataStage、Informatica)处理,再写入目标数仓。

源端 ──► [转换层] ──► 目标端

优点: 目标端始终存放干净、业务就绪的数据。合规管控在数据落库前就已强制执行。
缺点: 转换层容易成为瓶颈。Schema 变更需要跨多层同步修改。专用计算集群的运维成本高。

ELT:先落库,原地转换

由 dbt 带火的模式。原始数据直接落入数仓(BigQuery、Snowflake、ClickHouse),再用 SQL 原地做转换。转换层不再是独立集群——就是数仓本身。

源端 ──► 目标端(原始层)──► [数仓内 SQL] ──► 业务层

优点: 原始数据保留完整审计价值。复用数仓算力。迭代速度快。
缺点: 手机号、身份证、邮箱等敏感字段以明文落库,存在合规风险。数据质量问题要等 Load 之后才可见,此时下游模型可能已经被污染。

EtLT:传输途中做轻量变换

源端 ──► [tiny t] ──► 目标端(净化原始层)──► [目标端内的 T]

tiny t 是数据在传输过程中完成的一组行级变换:

tiny t 操作目的
字段投影 / 列裁剪传输前删除无用列——节省带宽
PII 脱敏手机号、身份证、邮箱在落库前匿名化——合规在管道层强制落地,而非事后补救
类型归一源端 VARCHAR "2023-01-01" 在入仓时就转为 DATE——省去数仓侧的类型转换 SQL
行过滤不需要的事件可在 Load 前丢弃;有状态的 CDC 变化需要按 changelog 语义处理
字段重命名适配目标端命名规范,无需数仓侧的别名层
NULL 回填减少下游聚合 SQL 中的 COALESCE 调用

大 T(Load 后的 Transform)才是真正的业务逻辑所在:多表 JOIN、指标计算、聚合、ML 特征工程。


为什么工程师长期忽略 EtLT

根本原因是工具,不是概念本身。

传统 ETL 工具(Informatica、DataStage)把转换做得极重,工程师被迫把大量业务逻辑塞进管道,结果管道变得脆弱、难以维护。

现代 ELT 工具(Airbyte、Fivetran)走向另一个极端:源端到目标端几乎没有在途处理,全部交给 dbt。

两类工具都没能填好的空白: 当你同时需要在途操作(脱敏、过滤)目标端的复杂分析 SQL 时,两个工具族都会让你陷入尴尬的临时方案。

EtLT 天然填补这个空白。


SeaTunnel 天然契合 EtLT

Apache SeaTunnel 在官方文档中把自己定位为 "EL(T) 数据集成工具"——括号里的 T 是刻意为之。Transform 步骤是轻量的、可选的。这不是营销话术,而是一个架构约束。

三层模型与 EtLT 直接对应

SeaTunnel 的执行模型分三层:Source → Transform → Sink

Source(E)
└──► Transform(tiny t) ← 可选,轻量处理
└──► Sink(L)
└──► [数仓 SQL / dbt](T) ← 大 T 在这里

SeaTunnel 对 Transform 能做的事划定了清晰边界。官方文档写道:

"Transform can only be used for some simple transformations of data, such as converting a column to uppercase/lowercase, modifying column names, or splitting one column into multiple columns."

这描述的是内置 Transform 的目标边界。当前 Zeta SQL Transform 不支持 JOIN 和 GROUP BY,因此跨表 JOIN 与聚合应放在目标系统或其他专用处理层中完成。

内置 Transform 覆盖典型 tiny t 需求

SeaTunnel Transform对应的 tiny t 操作
FieldMapper字段重命名、列投影
Filter通过 include/exclude 列表做字段投影
Replace字段值替换(脱敏 / 打码)
Split将一列拆成多列(如地址解析)
SQL Transform行过滤和轻量 SQL 表达式;当前 Zeta 实现不支持 JOIN 或 GROUP BY
Copy字段复制

SeaTunnel 同时提供 map 和 flat-map Transform 接口。当前内置 Transform 主要处理单条记录和 Schema,而不是跨行聚合,因此很适合作为 tiny t 层。

EtLT 最关键的战场:CDC 管道

实时 CDC 同步是 SeaTunnel 的核心使用场景之一——也是纯 ELT 在合规上失守的地方。

根本问题在于:binlog 事件里的字段值一旦落库,就没有第二次机会打码了。 写入 ClickHouse 的手机号或身份证,不可能被下游 dbt 模型"反写"回来。原始明文已经持久化。

EtLT 解决了 ELT 无法解决的问题:在数据到达目标端之前的唯一时间窗口内,完成合规变换。

下面给出一个带 tiny t 的 SeaTunnel CDC 作业最小配置形态。运行前请替换示例中的账号、密码和服务地址:

env {
job.mode = "STREAMING"
}

source {
MySQL-CDC {
plugin_output = "raw_user_info"
url = "jdbc:mysql://localhost:3306/orders"
username = "seatunnel"
password = "change-me"
server-id = 5601-5604
table-names = ["orders.user_info"]
}
}

transform {
# 在传输途中打码手机号——原始值永远不会到达数仓
Replace {
plugin_input = "raw_user_info"
plugin_output = "masked_user_info"
replace_field = "phone"
pattern = "(\\d{3})\\d{4}(\\d{4})"
replacement = "$1****$2"
is_regex = true
}
}

sink {
# L:落入 ClickHouse 原始层
Clickhouse {
plugin_input = "masked_user_info"
host = "clickhouse-host:8123"
database = "raw"
table = "user_info"
username = "default"
password = "change-me"
primary_key = "id"
support_upsert = true
allow_experimental_lightweight_delete = true
}
}

数据进入 ClickHouse 后,再用 SQL 构建宽表、计算留存指标、做分析查询——这就是大 T。dbt 模型在这里是天然的搭档。


SeaTunnel + dbt:全栈 EtLT

dbt 负责 Load 之后的大 T;SeaTunnel 负责从源到 Load(含 tiny t)。两者互补,而非竞争。

源端
└── SeaTunnel(E + tiny t + L)
└── dbt(T)
└── BI / ML

SeaTunnel 负责数据到达和在途卫生;dbt 负责数据建模和业务逻辑。每个工具只做它擅长的事。


常见陷阱:把大 T 塞进 SeaTunnel

因为 SeaTunnel 支持 SQL Transform,有些工程师会尝试在里面写 GROUP BY 聚合。当前 Zeta SQL Transform 会明确拒绝 GROUP BY 和 JOIN 查询。

如果确实需要 Load 前的聚合,有两条路:

  1. 在目标系统里做——这本来就是 EtLT 和 ELT 中大 T 的用途。
  2. 在 SeaTunnel Transform 链路之外使用专用处理作业——此时构建的是完整流式 ETL 管道,而不是把转换留在 tiny t 层。

边界清晰,失败才容易定位。把 tiny t 和大 T 混在同一层,出问题时几乎无法推断根源在哪里。


总结

范式最适合的场景SeaTunnel 的角色
ETL强合规要求、有专用转换计算集群负责 E、L 和已支持的轻量转换;复杂 T 需要专用处理层
ELT目标端是强 SQL 引擎(BigQuery/Snowflake),无严格在途合规要求纯 E + L——关闭 Transform
EtLT实时 CDC、在途 PII 脱敏、目标端有 dbt/SQL 能力天然契合:E + tiny t + L;大 T 归目标端

SeaTunnel 天然适合 EtLT——不是因为它声称这个标签,而是因为 Source/Transform/Sink 三层分离、当前内置 Transform 的能力边界和明确的"EL(T)"定位都指向同一件事:快速移动数据,在传输途中轻量净化,把重活留给目标系统。


延伸阅读