You need to enable JavaScript to run this app.
文档中心
大数据研发治理套件

大数据研发治理套件

复制全文
下载 pdf
高级参数
配置 JDBC Connector 高级参数
复制全文
下载 pdf
配置 JDBC Connector 高级参数

本文详细介绍了 DataSail JDBC Connector 的高级参数配置,包括 Source、Sink 等,可以帮助您提升数据同步任务的性能、稳定性与资源利用率。

Source (读取) 参数速览

下表汇总了 JDBC Source 的核心参数,帮助您快速定位和理解其作用。

参数名

简要作用

默认值参考

建议调参方向

job.reader.columns

定义需要从源端读取的列,支持常量、函数等。

按任务配置

按需配置,确保包含 split_pk 和动态分区列。

job.reader.connections

配置源数据库的连接信息(主库、备库等)。

按数据源配置

读写分离场景下可配置多个备库地址。

job.reader.enable_table_pattern

是否将 table_name 视为正则表达式,以匹配多张表。

FALSE

需要同步多张结构相似的表(如 user_001, user_002)时开启。

job.reader.table_include_list

配合 enable_table_pattern 使用,提供精确的表名白名单。

无

在正则匹配范围较大时,用于精确圈定需要同步的表。

job.reader.filter_dead_nodes

是否在任务启动时检查并排除不可用的数据库节点。

FALSE (引擎默认)

在高可用环境中建议开启,以自动跳过故障节点。

job.reader.is_master_slave_mode

是否为严格主备模式。

TRUE

若为 false,主库故障时会自动尝试将备库提升为新主库。

job.reader.session_properties

为每个数据库连接设置会话级别的初始参数。

无

用于设置时区、事务隔离级别等会话环境变量。

job.reader.query_timeout_seconds

单次数据库查询的超时时间(秒)。

300

大表或复杂查询场景可适当调大,避免因超时而失败。

job.reader.query_retry_times

查询失败后的重试次数。

3

网络抖动频繁的环境可适当调大,增加任务稳定性。

job.reader.reader_fetch_size

每次从数据库 fetch 的数据行数。

5000 / 10000

影响内存消耗和网络 IO。调大提升吞吐,调小降低单次请求压力。

job.reader.reader_parallelism_num

显式指定数据读取的并发度。

系统根据分片数自动计算

需要精细控制并发时设置,避免对源库造成过大压力。

job.reader.shard_split_mode

数据分片(切分)的策略。

accurate

nosplit 表示不切分,适用于小表或已有其他分片机制的场景。

job.reader.split_pk

用于数据切分的主键或索引列。

无

大表同步性能优化的关键,必须选择数值型或日期型等分布均匀的列。

job.reader.split_size

在使用 sqoop 风格字符串分片时,期望的分片数量。

10

调整此值以控制字符串类型分片键的切分粒度。

job.reader.filter

在 WHERE 条件中追加的自定义过滤语句。

无

用于实现增量同步或数据筛选,需注意 SQL 注入风险。

job.reader.customized_sql

使用完整的自定义 SQL 代替默认的 SELECT 语句。

无

适用于复杂的多表 JOIN 或需要特殊查询逻辑的场景。

job.reader.src_meta_info_column_enabled

是否在输出中增加一列用于标识数据来源的表名。

FALSE

同步多张表到同一目标时,用于在下游区分数据来源。

Sink (写入) 参数速览

下表汇总了 JDBC Sink 的核心参数,帮助您快速定位和理解其作用。

参数名

简要作用

默认值参考

建议调参方向

job.writer.columns

定义需要写入目标库的列及其类型。

按任务配置

确保与源端 columns 和目标表结构匹配。

job.writer.table_pattern

是否启用动态表名写入。

无

当需要根据上游数据内容将数据写入不同表时开启。

job.writer.connections

配置目标数据库的连接信息。

按数据源配置

可配置多个连接地址以实现写入的负载均衡或高可用。

job.writer.write_connection_balance

是否在多个并发写入任务间均衡分配数据库连接。

FALSE

多 db_url 场景下建议开启,以分散写入压力。

job.writer.write_mode

写入模式,如 insert, overwrite (upsert), replace 等。

insert

根据业务需求选择,overwrite 模式依赖主键或唯一键。

job.writer.update_columns

在 overwrite 模式下,定义冲突时需要更新的列。

无

未配置此项时,overwrite 将更新所有非主键列。

job.writer.partition_name

分区写入时指定的分区列名。

无

insert 或 dynamic 模式下进行分区清理和写入时必需。

job.writer.delete_threshold

insert 模式下,每次执行 DELETE 操作的最大行数。

10000

调小可降低单次删除对数据库的锁影响,但会增加删除次数。

job.writer.write_batch_size

每批次 commit 的数据行数。

100

核心性能参数。调大提升吞吐,但会增加内存消耗和失败重试的成本。

job.writer.write_retry_times

写入失败后的重试次数。

3

网络不稳定或数据库偶发繁忙时,适当增加可提升任务成功率。

job.writer.is_support_transaction

是否启用事务写入。

TRUE

建议保持开启以保证数据一致性。仅在特定数据库不支持时关闭。

job.writer.is_process_exception_as_dirty

批量写入失败并降级为单条写入时,是否将错误数据视为脏数据。

FALSE

若为 false,单条写入失败将直接导致任务失败。开启后可容忍少量“坏数据”。

JDBC Source (读取) 参数详解

job.reader.columns

参数概述

  • 参数名: job.reader.columns
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 默认值请以当前产品配置为准(通常是根据您在界面上选择的源表字段自动生成)。
  • 核心作用: 定义数据从源数据库读取时,需要查询并输出的列信息。它决定了下游算子接收到的数据结构。

适用场景

  • 场景一:选择特定列
    • 典型现象:源表有几十个字段,但下游只需要其中几个。
    • 调整方向:在 columns 中只配置需要的字段,可以减少网络传输和内存消耗。
  • 场景二:增加常量或函数列
    • 典型现象:需要在数据流中增加一个固定的标识,或对源端字段进行简单处理(如拼接、函数计算)。
    • 调整方向:可以在 columns 中添加 '常量值' as column_name 或 function(field) as new_column。
  • 场景三:排查字段缺失或不匹配问题
    • 常见报错关键字:column not found, schema mismatch
    • 调整方向:检查 columns 配置中的列名、数量、顺序是否与下游处理逻辑或目标表结构一致。特别是,如果使用了 split_pk 或 partition_name,请确保这些列也包含在 columns 中。

调参建议 / 推荐配置

  • 默认推荐: 使用产品界面生成的默认配置,它会包含您所选源表的所有字段。
  • 性能优化: 如果下游仅使用部分字段,强烈建议在 columns 中显式指定这些字段,避免读取和传输不必要的数据。
  • 排障临时配置: 当遇到 column not found 等问题时,可以尝试将 columns 配置简化为 *(如果连接器支持),以快速验证是列配置问题还是其他问题。验证后请务必恢复为显式列名配置,因为 * 会引入不确定性,且性能通常更差。

参数联动

  • split_pk: 如果配置了 split_pk 用于数据分片,该主键列必须包含在 columns 列表中。
  • customized_sql: 如果使用了自定义 SQL,columns 的定义必须与 customized_sql 中 SELECT 的列名、别名和顺序完全对应,否则会导致数据解析错误。
  • src_meta_info_column_enabled: 如果开启了此功能,您必须在 columns 中定义一个用于接收“来源表信息”的列(默认为 _src_meta_info_)。

FAQ(用户提问)

  • 问:为什么我的任务报 column not found,但我确认数据库里有这个字段?
    • 答:请检查 job.reader.columns 配置。首先,确认列名拼写是否完全正确(包括大小写,取决于数据库);其次,如果您使用了自定义别名,请确保下游使用的是别名。最后,确认该列是否在您配置的 customized_sql 或源表中确实存在。
  • 问:我想在数据里加一个固定的版本号,应该怎么做?
    • 答:这与 columns 参数相关。您可以在 columns 列表中增加一项,形如 "'v1.0' as data_version"。这样,每一行数据都会带上一个名为 data_version 且值为 v1.0 的新列。
  • 问:columns 里写 * 和写所有列名有什么区别?
    • 答:虽然结果可能看似相同,但有本质区别。显式列出所有列名是最佳实践,因为:1) 性能更优:数据库能更好地优化执行计划。2) 结构稳定:即使源表增加了新字段,您的数据流也不会受影响。3) 可维护性好:下游处理逻辑依赖的字段一目了然。使用 * 可能会在源表结构变更时引入未知风险。

注意事项

  • 列顺序: 某些场景下,数据处理可能依赖 columns 中的列顺序。请确保该顺序与预期一致。
  • 类型映射: columns 中定义的类型需要能被正确映射。例如,数据库中的 DATETIME 类型在 columns 中应配置为正确的时间戳或字符串类型。
  • 避免使用 *: 在生产环境中,强烈建议避免使用 * 来选择列,以保证数据流的稳定性和可预测性。

总结说明

job.reader.columns 参数是控制数据读取范围的核心配置。我们强烈建议您始终明确指定需要读取的列,这不仅能优化任务性能,还能在源表结构发生变化时保护您的数据任务不受影响。当遇到与字段相关的错误时,请第一时间检查此参数的配置是否准确。

job.reader.connections

参数概述

  • 参数名: job.reader.connections
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 默认值请以当前产品配置为准(通常是根据您选择的数据源拓扑结构生成)。
  • 核心作用: 定义源数据库的连接信息,包括一个或多个数据库实例的地址、端口、分片信息等。这是数据读取的入口点。

适用场景

  • 场景一:读写分离,从备库读取
    • 典型现象:为了降低对生产主库的压力,希望数据同步任务从只读备库进行。
    • 调整方向:在 connections 中配置一个或多个备库的 JDBC URL。如果配置了多个备库,可以配合 is_master_slave_mode 和 filter_dead_nodes 实现高可用读取。
  • 场景二:连接数据库失败
    • 常见报错关键字:connection refused, connect timed out, Unknown host
    • 调整方向:检查 connections 中的 db_url 是否正确,包括 IP/域名、端口。同时确认网络策略(安全组、防火墙)是否允许从任务运行环境到目标数据库的访问。
  • 场景三:分库分表读取
    • 典型现象:数据分散在多个物理库或表中(sharding)。
    • 调整方向:connections 需要包含所有相关的数据库分片信息,以便连接器能够发现并连接到所有需要读取的数据节点。

调参建议 / 推荐配置

  • 默认推荐: 使用产品界面根据您选择的数据源生成的 connections 配置。
  • 高可用配置: 在支持主备切换的环境中,同时配置主库和备库的 db_url。并设置 filter_dead_nodes=true,这样当某个节点无法连接时,任务会自动跳过它,尝试其他可用节点。
  • 读负载均衡: 如果有多个可供读取的备库,可以在 connections 中配置所有备库的地址。这允许连接器在不同并发的读取任务中分散连接,但请注意,这仅仅是连接级别的分散,不一定能实现查询级别的负载均衡。

参数联动

  • user_name / password: connections 中可以为每个连接单独指定用户名和密码,其优先级高于全局的 job.reader.user_name 和 job.reader.password。
  • filter_dead_nodes: 当此参数为 true 时,系统会在任务启动时检查 connections 中每个 db_url 的可用性,并剔除无法连接的节点。
  • is_master_slave_mode: 控制在主备模式下,当 connections 中的主库节点(通常是第一个)不可用时,是否允许将备库提升为新的主节点进行数据读取。
  • connection_parameters: 此参数可以向 connections 中所有 db_url 统一追加 JDBC 连接参数(例如 characterEncoding=utf8),简化配置。

FAQ(用户提问)

  • 问:我的任务总是连不上数据库,报 connection refused,该怎么办?
    • 答:这通常与 connections 参数或网络配置有关。请按以下步骤排查:1) 检查 db_url:确认 connections 中的 IP/域名和端口是否正确无误。2) 网络连通性:确认运行数据任务的计算资源与目标数据库之间的网络是通的,没有防火墙或安全组策略阻挡。3) 数据库状态:确认数据库服务本身在正常运行,且监听的地址和端口与配置一致。
  • 问:我想让数据同步任务只从备库读,怎么配置?
    • 答:很简单,在配置 connections 时,只填写只读备库的 db_url 即可。如果存在多个备库,可以都填入,以实现一定程度的高可用。
  • 问:connections 里可以填多个数据库地址吗?有什么用?
    • 答:可以。主要有两个用途:1) 高可用:当某个地址连接失败时,可以自动尝试其他地址(需配合 filter_dead_nodes)。2) 分库分表:在分库场景下,需要列出所有数据库分片的地址,以便任务能完整地读取所有数据。

注意事项

  • 安全性: 密码等敏感信息不应明文出现在 connections 配置中,产品通常会通过安全的变量替换机制来注入。
  • 连接参数: 某些数据库(如 MySQL)的特定行为(如批量查询优化)依赖于 JDBC URL 中的参数(如 rewriteBatchedStatements=true)。请确保这些必要的参数已通过 connection_parameters 或直接在 db_url 中正确配置。
  • 格式严格: connections 是一个结构化的列表,请确保其 JSON 或 YAML 格式的正确性,任何格式错误都将导致任务启动失败。

总结说明

job.reader.connections 是数据读取的起点,它告诉任务“数据在哪里”。正确配置 db_url、用户名和密码是任务成功的第一步。在生产环境中,我们建议您利用读写分离和主备配置,将读取压力从主库转移,并通过配置多个连接地址来提升数据同步任务的可用性。

job.reader.enable_table_pattern

参数概述

  • 参数名: job.reader.enable_table_pattern
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: FALSE
  • 核心作用: 控制是否将 job.reader.table_name 参数的值解释为一个正则表达式,用于在数据库中动态发现和匹配多张表。

适用场景

  • 场景一:同步分表数据
    • 典型现象:业务数据按日期或用户 ID 等规则分成了多张结构相同的表,如 log_20240101, log_20240102... 或 order_00, order_01...
    • 调整方向:将 enable_table_pattern 设置为 true,并把 table_name 设置为能匹配所有这些表的正则表达式,如 log_\\d{8} 或 order_\\d{2}。
  • 场景二:表名不确定或动态变化
    • 典型现象:需要同步的表名集合不是固定的,而是根据某些规则动态生成。
    • 调整方向:开启此参数,并使用一个足够宽泛的正则表达式来确保所有潜在的表都能被匹配到。强烈建议同时使用 table_include_list 来进行精确控制,防止匹配到无关的表。

调参建议 / 推荐配置

  • 默认推荐: 对于单表同步任务,保持默认值 FALSE。
  • 分表同步: 当需要同步多张结构一致的表时,设置为 true。例如,要同步所有 metrics_ 开头的表,可将 table_name 设为 metrics_.*。
  • 安全配置: 开启此功能时,为避免性能问题和数据错误,强烈建议同时配置 table_include_list 或 max_allowed_table_num。这可以作为一个安全阀,确保即使正则表达式写得过于宽泛,也只会同步预期内的表,同时避免因扫描过多表而导致任务启动缓慢。

参数联动

  • job.reader.table_name: 当 enable_table_pattern 为 true 时,table_name 的值不再被视为一个或多个具体的表名,而是被当作一个 Java 正则表达式来使用。
  • job.reader.table_include_list: 这是一个与 enable_table_pattern 配合使用的“白名单”。系统会先根据 table_name 的正则匹配出一批表,然后再用 table_include_list 对这批表做一次精确过滤,只有在白名单内的表才会被最终同步。
  • job.reader.max_allowed_table_num: 一个安全限制参数。当匹配到的表的数量超过这个阈值时,任务会启动失败。这是为了防止因错误的正则表达式匹配到数据库中成百上千张无关表,造成元数据压力和潜在的数据问题。

FAQ(用户提问)

  • 问:我有很多张名字类似的日志表,比如 app_log_2024_01,app_log_2024_02,能用一个任务全同步了吗?
    • 答:可以,这正是 enable_table_pattern 的典型应用场景。您需要将此参数设为 true,然后将 table_name 设置为 app_log_\\d{4}_\\d{2}。这样任务启动时就会自动去发现所有符合这个命名规则的表,并读取它们的数据。
  • 问:开启这个功能后,任务启动变得非常慢,怎么办?
    • 答:启动慢通常是因为正则表达式匹配范围太广,导致连接器需要花费大量时间去数据库获取元数据并进行匹配。请检查您的正则表达式是否写得过于宽泛。优化建议是:1) 收紧正则表达式,使其匹配范围更精确。2) 使用 table_include_list,提供一个确切的表名列表,这可以大大减少不必要的元数据扫描。
  • 问:如果我只想同步 user_1 到 user_10 的表,但不想同步 user_11,怎么配置?
    • 答:您可以将 enable_table_pattern 设为 true,table_name 设为 user_\\d+。然后,在 table_include_list 中明确列出 ["user_1", "user_2", ..., "user_10"]。这样就能实现精确控制。

注意事项

  • 性能影响: 开启此功能会增加任务启动时的元数据扫描开销,因为连接器需要向数据库查询所有表(或指定 database/schema下的所有表)来进行正则匹配。对于包含大量表的数据库,这可能会显著延长任务启动时间。
  • 结构一致性: 此功能假设所有匹配到的表结构都是一致的。如果各表结构不同(例如字段、类型不一),可能会导致数据读取时出错。
  • 正则表达式语法: 使用的是标准的 Java 正则表达式语法,请确保您的表达式符合规范。

总结说明

enable_table_pattern 是一个强大但需要谨慎使用的功能,它为同步命名有规律的多张表提供了极大的便利。当您需要处理分表场景时,请开启此参数,并始终配合 table_include_list 或 max_allowed_table_num 来限定范围,以确保任务的性能和稳定性。

job.reader.table_include_list

参数概述

  • 参数名: job.reader.table_include_list
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 无
  • 核心作用: 与 enable_table_pattern 配合使用,提供一个精确的表名“白名单”。在通过正则表达式匹配到一批表后,只有同时存在于这个白名单中的表才会被最终处理。

适用场景

  • 场景一:精确控制动态表范围
    • 典型现象:使用 enable_table_pattern 的正则表达式 orders_2024.* 匹配到了 orders_2024_archived 等不需要的表。
    • 调整方向:在 table_include_list 中明确指定需要同步的表名,如 ["orders_2024_q1", "orders_2024_q2"]。
  • 场景二:提升动态表发现性能
    • 典型现象:数据库中表数量巨大,即使正则表达式已经比较精确,元数据扫描和匹配过程依然缓慢。
    • 调整方向:提供一份完整的 table_include_list。这可以让连接器在获取基础表列表后,快速通过白名单进行过滤,减少后续不必要的元数据操作,从而加速任务启动。

调参建议 / 推荐配置

  • 推荐配置: 只要开启了 enable_table_pattern,就强烈建议同时配置 table_include_list。这是一种防御性编程,可以避免因正则表达式的微小失误导致同步范围扩大。
  • 最佳实践: 在可能的情况下,提供一份详尽的白名单。例如,即使你的正则表达式是 user_\\d+,也最好在 table_include_list 中列出所有确切的表名,如 ["user_1", "user_2", ...]。

参数联动

  • job.reader.enable_table_pattern: table_include_list 只有在该参数为 true 时才会生效。它的作用是在正则匹配之后进行二次过滤。
  • job.reader.table_name: table_include_list 中的表名必须是 table_name 正则表达式所能匹配到的子集。如果一个表名无法被正则匹配,即使它在白名单里,也不会被同步。

FAQ(用户提问)

  • 问:table_include_list 和 table_name 直接填多个表名有什么区别?
    • 答:当 enable_table_pattern=false 时,table_name 可以通过逗号分隔来支持多表,这适用于少量固定的表。而 table_include_list 是在 enable_table_pattern=true 的动态发现场景下,对正则匹配结果进行精确约束的工具,更适合大规模、有规律的分表场景。你可以把前者看作是“静态多表”,后者是“动态多表”的安全阀。
  • 问:我配置了白名单,为什么有些表还是没有被同步?
    • 答:请检查您 table_name 中设置的正则表达式是否能匹配到您白名单中的所有表。table_include_list 的过滤作用域是在正则表达式匹配结果之内,它不能“新增”正则匹配不到的表。

注意事项

  • 大小写敏感: 列表中的表名是否大小写敏感,取决于您的数据库配置。请确保与数据库中的实际表名完全一致。
  • 格式: table_include_list 是一个字符串列表,配置时请确保格式正确(如 JSON array ["table1", "table2"])。

总结说明

table_include_list 是 enable_table_pattern 功能的“安全带”。通过提供一份确切的表名白名单,您可以在享受动态表匹配便利性的同时,有效防止范围扩大化带来的性能和数据准确性风险。我们强烈建议您在所有动态表同步场景中都配置此参数。

job.reader.filter_dead_nodes

参数概述

  • 参数名: job.reader.filter_dead_nodes
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: FALSE(引擎默认值,产品侧可能有不同)
  • 核心作用: 在任务启动阶段,是否自动对 connections 列表中配置的所有数据库节点进行一次可用性检查,并自动过滤(排除)那些无法成功连接的“死亡”节点。

适用场景

  • 场景一:数据库节点故障或维护
    • 典型现象:数据库集群中有节点宕机或正在进行维护,导致部分连接地址不可用。
    • 调整方向:将此参数设置为 true。任务启动时会尝试连接每个节点,如果连接失败(如超时、拒绝连接),则会将该节点从本次任务的可用连接列表中移除,从而避免后续的读数据操作分配到这个故障节点上,保证任务可以继续运行。
  • 场景二:提升任务在主备切换期间的稳定性
    • 典型现象:数据库正在进行主备切换,旧主库可能已经无法访问,但 DNS 或配置还未完全更新。
    • 调整方向:设置为 true,任务可以自动检测到旧主库的不可用,并只使用当前可用的新主库或备库,实现平滑过渡。

调参建议 / 推荐配置

  • 高可用环境推荐: 在所有配置了多个数据库连接(如主备、多备)的生产环境中,强烈建议将 filter_dead_nodes 设置为 true。这是提升数据同步任务容错能力和稳定性的关键参数。
  • 单节点环境: 如果 connections 中只配置了一个数据库地址,此参数开启与否效果不大。但开启也无害。

参数联动

  • job.reader.connections: 此参数作用于 connections 中定义的整个节点列表。
  • job.reader.alive_check_timeout: 定义了在进行“存活检查”时,尝试连接每个节点的超时时间(秒)。如果一个节点在该时间内未响应,则被认为是“死亡”节点。默认30秒。
  • job.reader.is_master_slave_mode: 此参数决定了节点过滤的行为。若 is_master_slave_mode=true(严格主备),且主节点(通常是 connections 列表的第一个)被判断为“死亡”,则整个任务会失败,即使备库可用。若为 false,则主节点死亡后,任务可以继续从备库读取。

FAQ(用户提问)

  • 问:我的数据库有一个备库挂了,任务就失败了,怎么能让它自动跳过坏的节点?
    • 答:将 filter_dead_nodes 参数设置为 true 即可。这样任务启动时会进行一轮“体检”,自动“拉黑”连接不上的节点,只用健康的节点来读数据。
  • 问:开启这个功能会不会让任务启动变慢?
    • 答:会增加一点点启动耗时,因为需要对每个 connections 里的地址都尝试建立一次连接。但这个耗时通常是秒级的(取决于 alive_check_timeout 和节点数量),相比于它带来的任务稳定性提升,这点开销是完全值得的。
  • 问:主库挂了,但任务还是失败了,即使我开启了 filter_dead_nodes,为什么?
    • 答:请检查 is_master_slave_mode 参数。如果它被设置为 true(严格主备模式),那么系统会认为主库是不可替代的,一旦主库不可用,任务就会立即失败。如果希望主库挂掉后任务能继续从备库读,需要将 is_master_slave_mode 设置为 false。

注意事项

  • 探活 SQL: “存活检查”通常是通过执行一个非常简单的查询(如 SELECT 1)来完成的。请确保所用的数据库用户有执行这种基本查询的权限。
  • 超时设置: alive_check_timeout 的值需要合理设置。太短可能因为网络抖动而误判节点死亡;太长则会延长任务的启动时间。默认值 30 秒通常是一个合理的选择。

总结说明

filter_dead_nodes 是保障 JDBC 数据读取任务高可用的重要开关。在任何具有多个数据库节点(特别是主备或集群)的环境中,我们都强烈建议您开启此功能。它能让您的数据任务从容应对节点故障、网络分区和计划内维护,显著提升整体系统的健壮性。

job.reader.is_master_slave_mode

参数概述

  • 参数名: job.reader.is_master_slave_mode
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: TRUE
  • 核心作用: 定义在处理 connections 列表时的节点角色关系。它决定了当主节点(通常是列表中的第一个连接)不可用时,系统是否允许自动“故障转移”(failover)到备用节点。

适用场景

  • 场景一:允许自动故障转移到备库
    • 典型现象:希望在主库发生故障或维护时,数据同步任务能够无缝切换到备库继续读取数据,保证业务不中断。
    • 调整方向:将 is_master_slave_mode 设置为 false。在这种模式下,所有节点被视为对等或可替代的。只要 connections 列表中至少还有一个节点可用(需配合 filter_dead_nodes=true),任务就可以继续。
  • 场景二:强制从主库读取数据
    • 典型现象:由于数据一致性要求(例如,备库有延迟,无法接受)或架构设计,数据同步任务必须且只能从主库读取。
    • 调整方向:保持 is_master_slave_mode 为 true。这是严格主备模式,它会“锚定”列表中的第一个连接作为主节点。一旦该主节点不可用,即使其他备用节点是健康的,整个任务也会立即失败,从而防止读取到可能过时的数据。

调参建议 / 推荐配置

  • 容灾优先/高可用场景: 如果您的首要目标是保证任务的持续运行,并且可以接受备库可能存在的秒级数据延迟,建议设置为 false。
  • 数据一致性优先场景: 如果业务对数据一致性要求极高,完全不能容忍读取到任何可能延迟的数据,那么应保持默认值 true,并依赖外部的监控和告警系统来处理主库故障事件。

参数联动

  • job.reader.filter_dead_nodes: is_master_slave_mode 的行为逻辑强依赖于此参数。必须将 filter_dead_nodes 设为 true,节点的可用性判断才会发生。
    • 当 filter_dead_nodes=true 且 is_master_slave_mode=true: 如果主节点(第一个连接)检测失败,任务失败。
    • 当 filter_dead_nodes=true 且 is_master_slave_mode=false: 如果主节点检测失败,任务会继续尝试使用列表中的其他备用节点。
  • job.reader.connections: 此参数定义了主备列表。通常约定,列表中的第一个 db_url 是主节点,其余为备用节点。

FAQ(用户提问)

  • 问:主库挂了,我想让任务自动去读备库,怎么配置?
    • 答:您需要做两件事:1) 将 is_master_slave_mode 设置为 false。2) 确保 filter_dead_nodes 设置为 true。这样配置后,任务在启动时发现主库连不上,就会自动尝试使用您在 connections 中提供的其他备库地址。
  • 问:这个参数和数据库自身的HA(高可用)机制有什么关系?
    • 答:这是一个很好的问题。is_master_slave_mode 是在数据同步任务(客户端)层面实现的一种简单的故障切换逻辑。它不取代数据库自身的高可用机制(如 VIP、ProxySQL、MGR 等)。如果您的数据库已经有了成熟的、对应用透明的高可用方案(即应用始终连接一个虚拟 IP,后端主备切换由数据库中间件完成),那么这个参数的影响会变小。但作为一种“客户端侧”的容错增强,它依然是有价值的。
  • 问:设置为 false 有什么风险吗?
    • 答:主要的风险在于数据一致性。如果备库与主库之间存在数据同步延迟,那么在主库故障、任务切换到备库的瞬间,您可能会读取到几秒钟前的“旧”数据。您需要评估您的业务场景是否能接受这种短暂的不一致。

注意事项

  • 节点的顺序: 在 connections 列表中,节点的顺序非常重要。当 is_master_slave_mode 为 true 时,第一个节点被铁定地视为主节点。
  • 不仅仅是“主备”: 虽然参数名叫“master-slave”,但其 false 模式下的逻辑也适用于“多活”或“对等节点”的读取场景,即任何一个可用节点都可以用于数据读取。

总结说明

is_master_slave_mode 参数是您在任务的“可用性”和“数据一致性”之间做权衡的关键。设置为 false 可以获得更高的容灾能力,让任务在主库故障时“自愈”;保持 true 则能确保数据源的绝对权威性。请根据您的业务需求,选择最适合的模式。

job.reader.session_properties

参数概述

  • 参数名: job.reader.session_properties
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 无
  • 核心作用: 为每个新建立的数据库连接执行一组初始化的 SET 命令。这常用于设置会话级别的环境变量,如时区、事务隔离级别、SQL 模式等。

适用场景

  • 场景一:统一数据读取的时区
    • 典型现象:源数据库中的时间字段没有时区信息,而数据同步任务运行在不同时区的机器上,导致读取到的时间值发生偏移。
    • 调整方向:通过 session_properties 设置会话时区,例如 {"session.time_zone": "'+08:00'"},确保所有数据都在同一时区下被读取和解释。
  • 场景二:调整事务隔离级别
    • 典型现象:默认的事务隔离级别(如 REPEATABLE READ)可能因为 MVCC 导致长时间运行的查询无法看到新提交的数据,或者在某些场景下引发锁争用。
    • 调整方向:可以将会话隔离级别调整为 READ COMMITTED,例如 {"session.transaction_isolation": "'READ-COMMITTED'"},使得每次读取都能获取最新的已提交数据。

调参建议 / 推荐配置

  • 按需配置: 此参数非必填。仅当您需要为数据同步任务定制特殊的数据库会话环境时才需要配置。
  • 常见配置:
    • MySQL 时区: {"session.time_zone": "'+08:00'"}
    • Oracle NLS 日期格式: {"nls_date_format": "'YYYY-MM-DD HH24:MI:SS'"}
    • PostgreSQL 时区: {"timezone": "'Asia/Shanghai'"}
  • 注意语法: session_properties 是一个 Key-Value 맵。Key 是数据库的系统变量名,Value 是要设置的值(通常需要用引号包裹,具体取决于数据库语法)。

参数联动

  • job.reader.init_sql: session_properties 和 init_sql 都可以用于连接初始化。session_properties 更适合结构化的键值对设置,而 init_sql 可以执行任意的、更复杂的 SQL 语句。它们的执行顺序可能因连接器实现而异,建议不要混合使用来设置同一类参数。
  • job.reader.connections: session_properties 会应用到由 connections 定义的每一个数据库连接上。

FAQ(用户提问)

  • 问:从数据库读出来的时间戳和我直接在数据库里查的不一样,差了8个小时,怎么办?
    • 答:这很可能是时区问题。您可以通过 session_properties 参数来强制指定数据读取会话所使用的时区。例如,对于 MySQL,您可以配置 {"session.time_zone": "'+08:00'"} 来确保使用东八区时间。
  • 问:这个参数和直接在 JDBC URL 里加参数有什么区别?
    • 答:两者都能影响连接行为,但有细微差别。JDBC URL 里的参数(如 serverTimezone=UTC)是在驱动层面、连接建立之初就生效的。而 session_properties 是在连接建立之后,通过执行 SET 命令来实现的。通常,对于会话级的动态调整,使用 session_properties 更为灵活和直观。

注意事项

  • 数据库兼容性: session_properties 中的 Key(变量名)和 Value(值)的语法是数据库特定的。请参考您所使用的数据库(MySQL, Oracle, PostgreSQL 等)的官方文档来获取正确的变量名和值格式。
  • 权限: 执行 SET 命令的用户需要有修改相应会话变量的权限。
  • 性能: 每次建立新连接时都会执行这些 SET 命令,虽然开销很小,但如果连接非常频繁地断开和重连,也可能带来微小的性能影响。

总结说明

session_properties 为您提供了一个标准化的方式来“定制”数据读取时的数据库会话环境。当您遇到跨时区的时间偏差、需要调整事务隔离级别或设置特定于数据库的会话变量时,这个参数是您的首选工具。

job.reader.query_timeout_seconds

参数概述

  • 参数名: job.reader.query_timeout_seconds
  • 适用范围: JDBC Source
  • 单位: 秒
  • 默认值: 300
  • 核心作用: 设置单次数据库查询(Statement.executeQuery)的最大允许执行时间。如果一个查询的执行时间超过这个阈值,连接器会主动中断该查询并抛出超时异常。

适用场景

  • 场景一:大表扫描或复杂查询导致超时
    • 典型现象:任务日志中出现 Query timed out 或类似的数据库超时错误,特别是当处理的数据量很大,或者 filter 条件复杂导致无法有效使用索引时。
    • 调整方向:适当调大 query_timeout_seconds。例如,从 300 秒增加到 600 或 1800 秒,为慢查询预留更长的执行时间。
  • 场景二:防止慢查询拖垮数据库
    • 典型现象:某个数据同步任务的异常查询(如全表扫描一个巨大的无索引表)长时间占用数据库资源,影响了其他在线业务的正常运行。
    • 调整方向:适当调小 query_timeout_seconds。通过设置一个合理的、较短的超时时间(如 120 秒),可以快速“熔断”那些失控的慢查询,防止其对数据库造成持续的负面影响。

调参建议 / 推荐配置

  • 默认推荐: 300 秒(5分钟)的默认值适用于大多数常规查询场景。
  • 大表/复杂查询场景: 如果您预期查询会比较慢(例如,没有合适的 split_pk 进行分片,或者 filter 条件复杂),可以预先将此值调大至 600 (10分钟) 或 1800 (30分钟)。
  • 高负载/敏感数据库场景: 如果源数据库是核心在线业务库,对查询性能非常敏感,可以考虑将此值调小至 60 或 120 秒,作为一种保护机制。

参数联动

  • job.reader.query_retry_times: 当查询因为超时而失败后,任务会根据 query_retry_times 的设置进行重试。例如,如果超时设为 300 秒,重试次数为 3,那么一个查询最多可能花费近 15 分钟(300 * (1+3),不计重试间隔)才最终彻底失败。
  • job.reader.split_pk: 合理地使用 split_pk 对大表进行分片,是解决查询超时的根本方法。通过将一个大查询分解为多个在小数据范围上执行的快查询,可以有效避免触发 query_timeout_seconds。

FAQ(用户提问)

  • 问:我的数据同步任务总是报“查询超时”,是不是把 query_timeout_seconds 调得非常大就好了?
    • 答:简单地调大超时时间是一种“治标不治本”的方法。虽然它能让任务不因超时而失败,但它掩盖了真正的性能问题——查询本身太慢。我们更推荐您优先从以下方面进行优化:1) 检查 split_pk:是否为大表配置了合理的分片键?这是解决大表扫描性能问题的关键。2) 优化 filter 条件:确保您的 WHERE 条件能够有效利用数据库索引。3. 联系DBA:分析慢查询的执行计划,看看是否有优化空间。只有在确认查询本身确实需要很长时间才能完成时,调大超时时间才是合理的最后手段。
  • 问:这个超时时间和数据库本身的超时设置有什么关系?
    • 答:query_timeout_seconds 是在 JDBC 客户端(即数据同步任务)层面设置的超时。它通过 java.sql.Statement.setQueryTimeout() 方法生效。通常,它会与数据库服务端的超时设置(如 MySQL 的 net_read_timeout)协同工作,以两者中更短的那个为准。配置客户端超时可以提供更精细、更主动的控制。

注意事项

  • 不是连接超时: query_timeout_seconds 控制的是一个已经建立的连接上,单个 SQL 查询的执行时间。它与建立连接过程的超时(connection timeout)是两个不同的概念。
  • 合理评估: 在调整此参数前,请先在数据库客户端手动执行相应的查询,了解其大致的执行时间,然后设置一个比这个时间稍长一些的、带有合理缓冲的超时值。

总结说明

query_timeout_seconds 是保护您的数据任务和源数据库的重要“保险丝”。对于可能出现的慢查询,调大它可以给予更多耐心;对于需要保护的敏感数据库,调小它可以实现快速失败,避免资源被异常查询耗尽。但请记住,解决慢查询的根本之道在于优化查询本身(如使用分片键),而非无限延长等待时间。

job.reader.query_retry_times

参数概述

  • 参数名: job.reader.query_retry_times
  • 适用范围: JDBC Source
  • 单位: 次
  • 默认值: 3
  • 核心作用: 当一次数据库查询因网络抖动、数据库瞬时繁忙或超时等原因失败后,系统自动发起重试的最大次数。

适用场景

  • 场景一:网络环境不稳定
    • 典型现象:任务日志中偶尔出现 connection reset, broken pipe 或其他网络相关的异常,导致任务失败。
    • 调整方向:适当调大 query_retry_times,例如从 3 次增加到 5 次。这可以提高任务在面对偶发网络问题时的“韧性”,使其不必因一次短暂的故障而中断。
  • 场景二:数据库偶发性过载
    • 典型现象:源数据库偶尔会因为其他临时的高负载任务而无法及时响应查询,导致超时或错误。
    • 调整方向:同样可以适当调大此参数。通过重试,任务可以“等待”数据库从瞬时繁忙中恢复过来。重试之间通常会有一个指数退避的等待间隔,避免对繁忙的数据库造成进一步的冲击。
  • 场景三:快速失败以触发告警
    • 典型现象:对于一些核心数据链路,希望在数据库发生持续性问题(而非瞬时抖动)时尽快让任务失败,以便触发监控告警,让运维人员介入。
    • 调整方向:可以调小 query_retry_times,例如设置为 1 或 0。这样,一旦发生查询失败,任务会很快失败,从而缩短了从问题发生到被感知的延迟。

调参建议 / 推荐配置

  • 默认推荐: 3 次是一个比较均衡的配置,既能应对大多数瞬时问题,又不会在持续性故障面前“执着”太久。
  • 不稳定环境: 如果源数据库所在网络环境已知不稳定,或数据库本身负载波动较大,可以考虑增加到 5 次。
  • 核心监控链路: 对于需要快速响应失败的场景,可以设置为 1 次。不建议设置为 0,因为这会失去对最轻微网络抖动的容忍能力。

参数联动

  • job.reader.query_timeout_seconds: 重试是在查询超时后发生的。总的潜在等待时间会是 (query_retry_times + 1) * query_timeout_seconds(再加上重试间隔)。
  • reconnect 行为: 每次重试前,连接器通常会尝试关闭旧的、可能已损坏的连接,并建立一个全新的数据库连接,以最大程度保证重试的成功率。

FAQ(用户提问)

  • 问:任务因为网络问题失败了,我不想它这么脆弱,怎么办?
    • 答:您可以适当增加 query_retry_times 的值。这样,当遇到网络抖动时,任务会自己多尝试几次,很可能在网络恢复后就成功了,从而避免了整个任务的失败和重启。
  • 问:这个重试是立即重试吗?会不会一直冲击数据库?
    • 答:不是立即重试。两次重试之间通常会有一个等待间隔(backoff),并且这个间隔可能是指数增长的(例如,第一次等2秒,第二次等4秒,第三次等8秒)。这种机制旨在避免在数据库繁忙时对其进行“夺命连环call”,给予其恢复的时间。
  • 问:是不是重试次数越多越好?
    • 答:并非如此。过多的重试次数在面对“硬性”错误(如 SQL 语法错误、列不存在、权限问题)时是完全无效的,只会徒劳地延长任务的失败时间。并且,在数据库发生持续性故障时,过多的重试也会延迟问题的暴露。因此,建议设置一个合理的次数(如 3-5 次)即可。

注意事项

  • 幂等性: 重试机制假设被执行的 SELECT 查询是幂等的,即多次执行不会产生副作用。对于数据读取任务来说,这通常是成立的。
  • 非所有错误都可重试: 只有那些被认为是“瞬时”或“可恢复”的异常(如 IO 异常、特定类型的 SQL 异常)才会触发重试。对于“永久性”错误(如语法错误),系统会直接失败而不会重试。

总结说明

query_retry_times 是数据同步任务的“耐心”。通过设置合理的重试次数,您的任务将能够优雅地处理网络抖动和数据库的短暂繁忙,变得更加健壮。对于大多数场景,默认的 3 次重试是一个很好的起点。

job.reader.reader_fetch_size

参数概述

  • 参数名: job.reader.reader_fetch_size
  • 适用范围: JDBC Source
  • 单位: 行
  • 默认值: 默认值请以当前产品配置为准(通常在 5000 或 10000 左右)。
  • 核心作用: 设置 JDBC 驱动在执行查询后,一次从数据库服务端“预取”到客户端(即数据同步任务的内存)的行数。它直接影响了网络交互的频率和单次传输的数据量。

适用场景

  • 场景一:提升高延迟网络下的读取吞吐
    • 典型现象:数据同步任务运行环境与源数据库之间的网络延迟较高(例如,跨区域、跨公网同步)。
    • 调整方向:调大 reader_fetch_size。通过一次性获取更多的数据行,可以有效减少网络往返(Round Trip)的次数,从而将更多时间用于数据传输本身,而不是等待网络延迟,进而提升整体吞吐。
  • 场景二:降低任务内存消耗或避免 OOM
    • 典型现象:任务因内存溢出(OutOfMemoryError)而失败,特别是在处理含有大字段(如 TEXT, BLOB)的表时。
    • 调整方向:调小 reader_fetch_size。这会减少 JDBC 驱动在客户端内存中缓冲的数据量,从而有效降低内存峰值。
  • 场景三:减轻数据库单次响应压力
    • 典型现象:一次拉取过多数据可能给数据库服务端带来瞬时压力,或者触发某些数据库(如 Oracle)的资源限制。
    • 调整方向:调小 reader_fetch_size,将大的数据拉取请求分解为多次小的请求,使数据库负载更平滑。

调参建议 / 推荐配置

  • 吞吐优先 (高流量/高延迟网络): 如果网络带宽和任务内存都比较充裕,可以将 reader_fetch_size 适当调大,例如 20000 或 50000。这通常能带来明显的吞吐提升。
  • 内存优先 (低流量/大字段): 如果任务内存紧张,或者表中包含大文本、二进制字段,应将此值调小,例如 1000 或 500,以空间换时间。
  • 默认推荐: 5000 到 10000 是一个适用于多种场景的均衡值,在大多数情况下无需调整。

参数联动

  • split_pk: reader_fetch_size 作用于每个分片(split)内部。即使你通过 split_pk 将大查询分片,每个小查询依然受 fetch_size 的影响。
  • 内存配置: 此参数的调整应与分配给任务的内存(特别是 TaskManager 的内存)相匹配。盲目调大 fetch_size 而不增加任务内存,是导致 OOM 的常见原因。

FAQ(用户提问)

  • 问:我的数据同步任务很慢,调大 reader_fetch_size 会有帮助吗?
    • 答:很有可能会。特别是在网络延迟较高的场景下,调大 fetch_size 是提升读取吞吐最直接有效的方法之一。它通过“批量”地从数据库获取数据,减少了网络通信的开销。您可以尝试将其值翻倍,观察性能变化。
  • 问:这个值是不是越大越好?
    • 答:绝对不是。当 fetch_size 增大到一定程度后,性能提升的边际效应会递减,而内存消耗却是线性增长的。过大的 fetch_size 会导致两方面问题:1) 内存溢出(OOM):客户端需要大量内存来缓存这些数据。2) 数据库压力:可能给数据库带来瞬时压力,并且某些数据库驱动(尤其是 Oracle)在 fetch_size 极大时行为可能不符合预期。
  • 问:这个参数和 write_batch_size (Sink 端) 有什么关系?
    • 答:它们分别作用于数据同步的“入口”和“出口”。reader_fetch_size 控制一次从源端“读”多少,write_batch_size 控制一次向目标端“写”多少。两者没有直接的联动关系,但为了数据流的平滑,理想情况下两者应该大致匹配,或者 Sink 端的批次大小能有效处理 Source 端过来的数据流。

注意事项

  • 驱动实现差异: setFetchSize 的具体行为在不同数据库的 JDBC 驱动中可能略有差异。例如,MySQL JDBC 驱动只有在特定条件下(如 useCursorFetch=true)才会精确地按 fetch_size 流式拉取,否则可能是一次性加载所有结果到内存。请务- 必了解您所用驱动的特性。
  • Integer.MIN_VALUE: 某些驱动(如 MySQL)支持将 fetch_size 设置为 Integer.MIN_VALUE 来开启真正的流式读取(streaming),这在处理超大规模结果集时可以极大节省内存,但可能会牺牲一定的性能。

总结说明

reader_fetch_size 是一个在“吞吐”和“内存”之间进行权衡的关键性能参数。当网络延迟是瓶颈时,请大胆调大它;当内存资源紧张或处理大字段时,请果断调小它。合理的配置可以让您的数据读取过程既高效又稳定。

job.reader.reader_parallelism_num

参数概述

  • 参数名: job.reader.reader_parallelism_num
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 无(由系统根据分片数和 shard_parallelism_ratio 自动计算)
  • 核心作用: 显式地指定数据读取任务的并发度(并行实例数)。

适用场景

  • 场景一:精细控制数据库读取压力
    • 典型现象:系统自动计算的并发度可能过高,对源数据库造成了过大的连接和查询压力,影响了在线业务。
    • 调整方向:显式调小 reader_parallelism_num。例如,无论系统计算出多少并发,都强制将其限制在一个较低的水平,如 5 或 10,以保护源数据库。
  • 场景二:充分利用计算资源和数据库能力
    • 典型现象:系统自动计算的并发度较低,未能充分利用分配给任务的计算资源,或者源数据库本身有很高的并发处理能力未被发掘。
    • 调整方向:显式调大 reader_parallelism_num,以启动更多的并行读取任务,从而加快数据同步速度。
  • 场景三:固定并发以保证行为一致性
    • 典型现象:希望每次运行任务时,其并发行为都是完全可预测和一致的,不受源端拓扑(如分片数)变化的影响。
    • 调整方向:设置一个固定的 reader_parallelism_num 值。

调参建议 / 推荐配置

  • 默认推荐: 不配置此参数,让系统自动管理。系统通常会根据源端的分片数(shards/hosts)和 shard_parallelism_ratio 来计算一个合理的并发度,这种自适应的方式在很多场景下是有效的。
  • 数据库保护: 如果源数据库非常敏感,建议设置一个明确的、较低的并发上限,例如 reader_parallelism_num: 8。
  • 性能压测: 在进行性能调优时,可以通过逐步增加 reader_parallelism_num 来找到最佳的并发度,即在数据库可承受范围内,吞吐达到峰值的那个点。

参数联动

  • shard_parallelism_ratio: 当 reader_parallelism_num 未被设置时,系统会使用 并发度 = DISTINCT_HOSTS * shard_parallelism_ratio 这个公式来计算并发。一旦设置了 reader_parallelism_num,shard_parallelism_ratio 将会失效。
  • Flink parallelism.default / max_parallelism: reader_parallelism_num 的值会受到 Flink 层面最大并发度的限制。您设置的值不能超过 Flink 作业的 max_parallelism。
  • job.reader.split_pk: 并发读取的有效性依赖于合理的数据分片。如果未使用 split_pk 导致数据无法切分,那么即使设置了很高的并发度,也可能只有一个任务在工作。

FAQ(用户提问)

  • 问:我的任务读取数据很慢,把 reader_parallelism_num 调大就可以了吗?
    • 答:不一定。调大并发度是提升速度的手段之一,但它的前提是“数据是可并行的”。您必须首先确保已经通过 split_pk 等方式对数据进行了有效的分片。如果数据本身没有被切分成多个块,那么再多的并发实例也只会“一拥而上”去读同一块数据,无法实现并行处理。因此,正确的顺序是:先做好分片(split_pk),再考虑提升并发(reader_parallelism_num)。
  • 问:并发度设置成多少最合适?
    • 答:没有一个“万能”的数字。最佳并发度取决于多个因素的平衡:数据分片的数量、单个分片的数据量、分配给任务的 CPU/内存资源、网络带宽,以及源数据库的最大并发承载能力。最好的方法是通过实验来确定:从一个较低的并发度开始,逐步增加,同时监控任务的吞吐和源数据库的负载,找到那个“甜点”。
  • 问:为什么我设置了很高的并发度,但任务启动后看到只有几个在跑?
    • 答:可能有几个原因:1) 数据分片不足:例如,您设置了 100 并发,但数据只被分成了 10 片,那么多余的 90 个并发实例将无事可做。2) 资源不足:您申请的计算资源(如 Flink 的 Task Slot)不足以支持您设置的并发度。3) Flink 最大并发限制:您设置的值超过了整个 Flink 作业允许的最大并发度。

注意事项

  • 连接池:高并发读取会对数据库连接池造成压力。请确保数据库侧配置了足够大的连接数(max_connections)以应对。
  • 过犹不及: 过高的并发度不仅会压垮数据库,也可能因为线程切换和资源竞争,导致数据同步任务本身的性能下降。

总结说明

reader_parallelism_num 是您用来精细调控数据读取“火力”的开关。大多数情况下,您可以信赖系统的自动调节能力。但在需要保护敏感数据库,或希望榨干系统性能时,通过显式设置此参数,您可以获得对任务行为更强的掌控力。请记住,并行处理的威力,源于有效的数据分片。

job.reader.shard_split_mode

参数概述

  • 参数名: job.reader.shard_split_mode
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: accurate
  • 核心作用: 定义在使用了 split_pk(分片键)时,如何计算每个数据分片(split)的边界范围。这是大表并行读取性能优化的核心算法开关。

适用场景

  • accurate (精确模式)
    • 典型现象: 对数据完整性要求极高,不允许任何因分片算法不准而导致的数据遗漏。这是最常用、最安全的模式。
    • 工作方式: 它会通过 SELECT MIN(split_pk), MAX(split_pk) 等查询精确地获取分片键的全域范围,然后再根据并发度进行均匀切分。
  • quick (快速模式)
    • 典型现象: 任务启动速度优先,可以接受分片边界的轻微不精确。适用于分片键数值分布非常均匀的场景。
    • 工作方式: 它可能会使用采样、估算或依赖于表的统计信息来快速确定分片边界,从而避免了获取最大/最小值的全表(或索引)扫描,启动更快。
  • parallelism (并发优先模式)
    • 典型现象: 目标是生成特定数量的分片,以精确匹配期望的并发度。
    • 工作方式: 算法的核心目标是产生 N 个分片,其中 N 等于 reader_parallelism_num。
  • nosplit (不分片模式)
    • 典型现象: 表本身很小,无需分片;或者希望以整张表为单位进行处理,不希望连接器在表内进行切分。
    • 调整方向: 显式设置为 nosplit。这会强制连接器不对该表进行基于 split_pk 的内部切分,每个并发任务会收到一整个表(或一个分库分片)作为处理单元。

调参建议 / 推荐配置

  • 默认推荐: 保持 accurate 模式。这是最可靠、最能保证数据完整性的选项,适用于绝大多数场景。虽然启动时可能会稍慢(需要计算 min/max),但这份“耐心”是值得的。
  • 小表/无需切分: 对于数据量明确很小的表,或者您不希望对其进行内部切分的场景(例如,您希望一个并发任务处理一张完整的物理表),可以设置为 nosplit。
  • 高级调优: quick 和 parallelism 属于高级调优选项,仅在您完全理解其工作原理和潜在风险(如数据倾斜、边界不准)后,并且在“任务启动速度”成为主要瓶颈时才考虑使用。

参数联动

  • job.reader.split_pk: shard_split_mode 只有在 split_pk 被正确配置后才会生效。没有分片键,就无所谓分片模式。
  • job.reader.reader_parallelism_num: 分片最终会被分配给并发的读取任务。分片的数量和范围,会直接影响每个并行实例的工作负载。

FAQ(用户提问)

  • 问:我想让任务读数据快一点,是不是应该把 shard_split_mode 设为 quick?
    • 答:quick 模式加快的是“任务启动阶段的分片计算速度”,而不是“数据读取本身的速度”。它通过估算来划分边界,如果您的分片键分布不均,可能会导致“数据倾斜”——即某些并发任务分配到的数据量远多于其他任务,反而使得整个任务的“木桶效应”更严重,总时长变得更长。因此,除非任务启动时间占了总时间的很大比重,否则我们不建议轻易使用 quick 模式。
  • 问:nosplit 是什么意思?是不是就不并行了?
    • 答:nosplit 意味着连接器“在单张表内部”不做切分。但如果您的任务本身配置为读取多张表(例如,通过 enable_table_pattern 或 table_name 逗号分隔),那么并行依然是有效的,只是并行的粒度是“表级”的。例如,你有 10 张小表,设置 10 个并发和 nosplit 模式,那么理想情况下每个并发任务会负责读取一张完整的小表。

注意事项

  • 数据倾斜风险: quick 模式最大的风险就是可能导致严重的数据倾斜。请在测试环境中充分验证其分片效果。
  • 模式兼容性: 不同的分片模式可能对分片键的数据类型有不同要求。例如,某些高级模式可能不支持字符串类型作为分片键。

总结说明

shard_split_mode 是决定如何“切蛋糕”(数据)的策略。accurate 模式就像用尺子精确测量再切,保证每块都不多不少,是最稳妥的选择。nosplit 模式则表示“这块蛋糕太小,不用切了,一人一整个”。除非您是性能调优专家且面临特定的启动速度瓶颈,否则我们强烈建议您坚守 accurate 模式。

job.reader.split_pk

参数概述

  • 参数名: job.reader.split_pk
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 无
  • 核心作用: 指定一个用于对大表进行数据分片(切分)的列名。这是实现数据库并行读取、提升大表同步性能的最关键参数。

适用场景

  • 场景一:同步大表数据缓慢
    • 典型现象:一个几亿、几十亿行的大表,使用默认的单并发读取,任务执行时间长达数小时甚至数天。
    • 调整方向:必须为此表配置一个合适的 split_pk。连接器会利用这个列,将整个表的数据范围切分成多个小的数据块(splits),然后将这些小块分配给多个并行的读取任务,实现“众人拾柴火焰高”的效果。
  • 场景二:避免单次查询数据量过大
    • 典型现象:对大表的 SELECT 查询因为一次性要处理的数据太多,导致数据库长时间高负载,甚至超时。
    • 调整方向:通过配置 split_pk,原始的 SELECT * FROM big_table 会被自动改造成一系列带有 WHERE split_pk >= ? AND split_pk < ? 条件的子查询。每个子查询只处理一小部分数据,从而大大降低了对数据库的单次压力。

调参建议 / 推荐配置

  • 选列原则:
    1. 有索引: split_pk 列必须有索引,最好是主键或唯一索引。否则,为了获取分片边界(计算MIN/MAX)和执行范围查询,数据库将进行全表扫描,性能会急剧恶化。
    2. 数值型或日期型优先: 整型(INT, BIGINT)、日期/时间类型(DATE, DATETIME, TIMESTAMP)是最佳选择,因为它们的线性、可比较且分布通常较为均匀。
    3. 分布均匀: 列的值应该大致均匀地分布在整个范围内。自增 ID 是一个很好的例子。如果列的值集中在某几个点上(数据倾斜),分片效果会很差。
    4. 避免使用字符串类型: 除非别无选择,否则尽量避免使用字符串类型作为 split_pk。字符串的比较、排序和范围计算都比数值类型慢得多,且容易因字符集(collation)问题导致分片不准。
  • 推荐配置: 对于任何大小超过百万行级别的表,都强烈建议配置 split_pk。请与您的 DBA 或数据建模同学确认,找到最适合用作分片的列。

参数联动

  • job.reader.reader_parallelism_num: split_pk 负责“切数据”,而 reader_parallelism_num 决定有多少个“工人”来处理这些切好的数据块。两者需要配合使用才能发挥并行读取的威力。
  • job.reader.shard_split_mode: 定义了使用 split_pk 进行切分的具体算法。
  • job.reader.split_pk_jdbc_type: 显式告诉连接器 split_pk 列的 JDBC 类型。虽然连接器会尝试自动推断,但在某些模糊的情况下(如特定数据库的自定义类型),显式指定可以避免错误。

FAQ(用户提问)

  • 问:我有一个很大的表,同步特别慢,配置 split_pk 就行了吗?
    • 答:是的,配置 split_pk 是解决大表同步慢问题的核心步骤。它使得并行读取成为可能。配置好之后,您还可以适当增加 reader_parallelism_num(并发度),两者结合,通常能将同步性能提升数倍甚至数十倍。
  • 问:我选哪个字段作为 split_pk 最好?
    • 答:最好的选择通常是表的主键,特别是当它是自增整数时。如果没有主键,或者主键是复合主键/字符串,那么可以选择一个有唯一索引、数值类型且分布均匀的列,例如 update_time (如果更新时间戳分布均匀的话) 或者某个业务自增ID。关键是:有索引且值是散列的。
  • 问:我没有合适的数值列,可以用字符串列吗?
    • 答:可以,但这是次선책。使用字符串列作为 split_pk 时,需要注意几点:1) 性能会比数值列差。2) 可能需要额外配置 split_string_key_with_collate 或 use_sqoop_string_split_mode 来处理字符集和排序规则问题。3) 分片的均匀性更难保证。因此,非必要不推荐。

注意事项

  • 多列支持: 虽然参数名是 pk(Primary Key),但它并不一定要求是主键。另外,某些连接器实现可能支持配置多个候选 split_pk(逗号分隔),但通常只会使用第一个有效的。
  • NULL 值处理: 如果 split_pk 列中包含 NULL 值,您可能需要额外关注 support_null_split_key 参数的配置,以确保 NULL 值记录也能被正确读取。
  • 数据倾斜: split_pk 的选择至关重要。如果选择的列数据分布严重不均(例如,一个状态字段,99% 的值都是 'active'),会导致大部分并发任务无所事事,只有一个任务在处理那 99% 的数据,并行效果将大打折扣。

总结说明

split_pk 是撬动大数据同步性能的杠杆。对于所有大表的读取任务,正确地配置此参数都是实现高性能、高效率同步的第一步,也是最重要的一步。请务必选择一个带有索引且值分布均匀的数值或日期类型列作为您的分片键。

job.reader.filter

参数概述

  • 参数名: job.reader.filter
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 无
  • 核心作用: 在数据读取时,向 SELECT 语句的 WHERE 子句中追加一个自定义的过滤条件。这通常用于实现增量数据同步或对数据进行初步筛选。

适用场景

  • 场景一:实现增量数据同步
    • 典型现象:每天只需要同步前一天产生或更新的数据。
    • 调整方向:通过 filter 参数传入一个基于时间字段的过滤条件。例如,"update_time >= '${last_day}' AND update_time < '${current_day}'",其中 ${...} 是系统支持的变量占位符。这样,任务每次运行时只会读取指定时间窗口内的数据。
  • 场景二:排除特定类型或状态的数据
    • 典型现象:源表中包含一些无效、测试或无需同步的数据。
    • 调整方向:在 filter 中添加条件来排除这些数据。例如,"status != 'deleted' AND is_test = 0"。
  • 场景三:针对特定分区或范围进行补数据
    • 典型现象:需要对历史数据的某一部分进行重跑或补录。
    • 调整方向:使用 filter 精确定义需要补录的数据范围,例如 "order_date BETWEEN '2023-01-01' AND '2023-01-31'"。

调参建议 / 推荐配置

  • 增量同步: 这是 filter 最核心的用途。结合任务调度系统提供的日期/时间变量,可以轻松构建出 T-1 的增量同步逻辑。
  • 数据筛选: 在源端通过 filter 提前过滤掉不需要的数据,可以减少网络传输和下游处理的开销,是一种高效的数据预处理方式。
  • 注意语法: filter 的内容将作为纯文本直接拼接到 WHERE 子句中。您需要确保其 SQL 语法是正确的,并且字符串值需要用单引号包裹。

参数联动

  • split_pk: filter 条件会和 split_pk 产生的范围查询条件通过 AND 组合在一起。例如,最终的 WHERE 子句可能看起来像 WHERE (update_time >= '2024-01-01') AND (id >= 1000 AND id < 2000)。因此,filter 条件最好也能利用上索引,以保证每个分片的查询效率。
  • customized_sql: 如果您已经使用了 customized_sql 参数来提供完整的 SQL 语句,那么 filter 参数通常会失效,因为 WHERE 条件已经由您在自定义 SQL 中完全控制了。

FAQ(用户提问)

  • 问:我想做增量同步,只同步昨天的数据,怎么配?
    • 答:您可以使用 filter 参数,并配合系统提供的调度变量。具体语法可能因您使用的平台而异,但思路是类似的,例如:"gmt_create >= bizdate_add('${bizdate}', -1) AND gmt_create < '${bizdate}'"。
  • 问:filter 里可以写很复杂的 SQL 吗?
    • 答:可以,但需要注意几点:1) 它只是 WHERE 子句的一部分,不能包含 ORDER BY, GROUP BY 等。2) 过于复杂的条件可能导致数据库无法有效使用索引,从而影响查询性能。3) 如果逻辑非常复杂,甚至需要多表 JOIN,那么更推荐使用 customized_sql 参数。
  • 问:配置了 filter 之后查询变慢了,怎么办?
    • 答:请检查 filter 中涉及的列是否有索引。如果在一个没有索引的列上进行过滤,数据库很可能会进行全表扫描,导致性能急剧下降。请联系 DBA 为过滤列添加索引。

注意事项

  • SQL 注入风险: filter 的内容是直接拼接到 SQL 语句中的。请绝对不要将来自外部的、不可信的用户输入拼接到 filter 字符串中,否则会存在严重的安全风险。请仅使用系统提供的、受信任的调度变量。
  • 括号问题: 连接器在拼接 SQL 时,通常会将 filter 的内容用括号包裹起来,以保证 AND / OR 逻辑的优先级正确。您在编写 filter 内容时,一般无需自行在最外层添加括号。
  • SQL 方言: 请使用符合您源数据库的 SQL 方言来编写过滤条件。

总结说明

filter 参数为您在数据源头进行筛选提供了强大的能力。它是实现增量同步、过滤无效数据、定点补录的核心工具。在使用时,请务- 必保证过滤条件所涉及的列建立了索引,并注意防范 SQL 注入风险,以实现高效、安全的数据读取。

job.reader.customized_sql

参数概述

  • 参数名: job.reader.customized_sql
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: 无
  • 核心作用: 允许用户提供一段完整的、自定义的 SELECT SQL 语句来代替连接器默认生成的查询。一旦配置了此参数,连接器将放弃所有关于表名、列名、filter 的自动拼接逻辑,完全以您提供的 SQL 为准。

适用场景

  • 场景一:复杂的多表关联查询
    • 典型现象:需要的数据分散在多张表中,必须通过 JOIN 才能获取完整的记录。
    • 调整方向:在 customized_sql 中编写完整的 SELECT ... FROM table_a JOIN table_b ON ... 语句。
  • 场景二:需要进行预聚合或复杂计算
    • 典型现象:在数据读取阶段就需要进行 GROUP BY 聚合,或者使用窗口函数、复杂的 CASE WHEN 表达式等。
    • 调整方向:将这些复杂的 SQL 逻辑直接写入 customized_sql。
  • 场景三:使用数据库特定的高级功能或 Hint
    • 典型现象:希望利用数据库提供的查询优化提示(Hint)来强制指定执行计划,或者调用某个数据库特定的函数。
    • 调整方向:在 customized_sql 中自由地使用这些高级 SQL 特性。

调参建议 / 推荐配置

  • 作为最后手段: 只有当默认的表/列/filter拼接方式无法满足您的复杂查询需求时,才推荐使用 customized_sql。对于简单的单表查询,使用默认方式更简单、更安全。
  • 结构必须匹配: 您在 customized_sql 中 SELECT 的列(包括别名和顺序)必须与 job.reader.columns 中定义的完全一致,否则任务在读取数据时会因结构不匹配而失败。
  • 变量替换: SQL 中可以包含一些系统占位符,如 ${database}, ${schema}, ${table}, ${ts_ms} 等,任务在运行时会自动替换它们。

参数联动

  • job.reader.split_pk: 重要:一旦使用了 customized_sql,split_pk 和所有与之相关的数据分片逻辑将完全失效。连接器无法对一个黑盒的、复杂的自定义 SQL 进行自动分片。这意味着您的自定义 SQL 将以单并发的方式执行。
  • job.reader.columns: 如上所述,columns 必须与 customized_sql 的输出结构严格对应。
  • job.reader.filter: filter 参数会失效,所有过滤逻辑都必须写在 customized_sql 的 WHERE 子句中。

FAQ(用户提问)

  • 问:我用了 customized_sql 之后,任务变得特别慢,而且只有一个并发在跑,为什么?
    • 答:这是 customized_sql 的核心限制。因为连接器无法理解您的复杂 SQL 并对其进行安全的自动切分,所以所有与 split_pk 相关的数据分片和并行读取机制都会被禁用。您的整个 SQL 语句只能作为一个整体,由一个并发任务来执行。
  • 问:既然 customized_sql 不能并行,那如果我想对一个复杂查询的结果进行并行读取,有办法吗?
    • 答:这是一个高级场景,通常的解决方案是“两步走”:1) 创建一个数据库视图(VIEW),将您的复杂 SQL 逻辑封装在视图里。2) 配置一个新的数据同步任务,这次不再使用 customized_sql,而是直接读取这个视图。如果这个视图的数据可以基于某个列(如主键)进行分片,您就可以为这个新任务配置 split_pk,从而实现对复杂查询结果的并行读取。
  • 问:我可以在 customized_sql 里写 UPDATE 或 DELETE 吗?
    • 答:不可以。customized_sql 仅用于数据读取,必须是 SELECT 语句。执行非查询类的语句会报错。

注意事项

  • 性能责任: 使用 customized_sql 意味着您将全权负责 SQL 的性能。请确保您的 SQL 经过了充分的优化,并且其执行计划是合理的。
  • 无并行能力: 再次强调,customized_sql 会导致数据读取失去并行能力。这对于大数据量的场景可能是致命的性能瓶颈。请仅在数据量不大,或者您有其他方式(如创建视图)来解决并行问题时使用。
  • 安全性: 与 filter 类似,需要自行保证 SQL 的安全性,避免注入风险。

总结说明

customized_sql 赋予了您定义数据来源的终极灵活性,让您可以处理任意复杂的查询逻辑。但这份灵活性的代价是牺牲了并行读取的能力。因此,它是一把双刃剑,请仅在标准功能无法满足您的多表关联、复杂计算等需求时才审慎使用,并时刻警惕它可能带来的性能瓶颈。

job.reader.src_meta_info_column_enabled

参数概述

  • 参数名: job.reader.src_meta_info_column_enabled
  • 适用范围: JDBC Source
  • 单位: 无
  • 默认值: FALSE
  • 核心作用: 当开启后,连接器会在输出的数据流中自动增加一列,该列的值为这条数据来源的物理表名。这在同步多张表到同一目标时尤其有用,可以帮助下游区分和追溯数据来源。

适用场景

  • 场景一:多表汇总到单表
    • 典型现象:使用 enable_table_pattern 功能将 orders_202401, orders_202402 等多张月度订单表同步到一张年度大表中。同步完成后,希望能在年度大表中知道每一行数据具体是来自哪个月的表。
    • 调整方向:将 src_meta_info_column_enabled 设置为 true。同时,在 columns 中增加一个对应的列(例如 source_table),并在目标表中也增加此列。
  • 场景二:分库分表数据稽核
    • 典型现象:将多个分库分表的数据汇总后,需要进行数据稽核或问题排查,此时需要快速定位某条“问题数据”来自哪个原始的分片表。
    • 调整方向:开启此参数,并将来源表信息随数据一路同步到最终的稽核库中。

调参建议 / 推荐配置

  • 多表同步场景推荐: 只要您的数据读取任务涉及多于一张源表(无论是通过 enable_table_pattern 还是 table_name 逗号分隔),都建议开启此功能,并为来源信息预留一个字段。这会大大提升下游数据的可追溯性和可维护性。
  • 单表同步无需开启: 对于单表同步,数据来源是明确的,无需开启此参数。

参数联动

  • job.reader.src_meta_info_column_name: 此参数定义了那个用于存放来源表信息的列名,默认是 _src_meta_info_。您通常需要将其修改为一个更有业务含义的名称,如 source_table_name。
  • job.reader.columns: 您必须在 columns 列表中显式地包含 src_meta_info_column_name 所指定的列名,否则连接器不知道该将来源信息填充到哪里。例如: ..., "source_table_name"}。
  • job.reader.enable_table_pattern: 此功能最常与动态表发现功能一起使用,是其重要的配套能力。

FAQ(用户提问)

  • 问:我同步了很多张分表到一个大表里,后面想分析每个分表的数据量,有什么好办法吗?
    • 答:开启 src_meta_info_column_enabled 就是为此而生的。它会为您的每一行数据都打上“出生地”的标签(即来源表名)。数据同步完成后,您只需要在目标大表里对这个来源表名列进行 GROUP BY 和 COUNT(*),就可以轻松统计出每个原始分表的行数了。
  • 问:开启后,我需要自己在数据库里创建那一列吗?
    • 答:是的。连接器只负责在数据流中“添加”这一列并填充值。您需要确保:1) 在 job.reader.columns 中声明了这一列。2) 在下游的目标表中,也实际存在一个用于存储这个来源表名的字段(通常是 VARCHAR 类型)。
  • 问:来源信息具体是什么格式?
    • 答:通常就是数据的物理来源表名,例如 orders_202401。

注意事项

  • 列名匹配: src_meta_info_column_name 的值必须与 columns 列表中的某一个列名完全匹配。
  • 额外存储开销: 开启此功能会为每一行数据增加一个额外的字段,这会带来微小的网络和存储开销。但相比于它提供的可追溯性价值,这点开销通常可以忽略不计。

总结说明

src_meta_info_column_enabled 是一个“小开关,大作用”的参数。在任何多表同步的场景下,它都能像GPS一样,为您的每一条数据精准定位其来源,是提升数据血缘清晰度和后续运维、分析效率的利器。我们强烈建议您在所有适用的场景中都开启它。

JDBC Sink (写入) 参数详解

job.writer.columns

参数概述

  • 参数名: job.writer.columns
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: 默认值请以当前产品配置为准(通常是根据您在界面上选择的目标表字段自动生成)。
  • 核心作用: 定义数据写入目标数据库时,需要插入或更新的列信息及其数据类型。它负责将内存中的数据行(Row)正确地映射到 PreparedStatement 的参数上。

适用场景

  • 场景一:字段映射不匹配
    • 典型现象: 任务报错,提示列数量不匹配、找不到列或数据类型转换错误。
    • 常见报错关键字: Column count doesn't match, Cannot find column, Data truncation, Type mismatch
    • 调整方向: 仔细核对 job.writer.columns 的列名、顺序、数量和类型是否与目标数据库表的物理结构完全一致,并且与上游(Source端)输出的数据结构兼容。
  • 场景二:控制写入的字段范围
    • 典型现象: 源端数据包含多个字段,但目标表只需要写入其中的一部分。
    • 调整方向:在 job.writer.columns 中只配置目标表实际需要写入的那些列。
  • 场景三:处理动态表名的解析列
    • 典型现象: 使用了 table_pattern 动态表功能,其中用于计算目标表名的字段(例如 user_id)本身不需要被写入到数据列中。
    • 调整方向: 可以将这类字段定义在 job.writer.internal_columns 中,这样它们虽然参与了表名计算,但不会被包含在最终的 INSERT 语句里。

调参建议 / 推荐配置

  • 默认推荐: 使用产品界面根据您选择的目标表自动生成的配置。这是最安全、最不容易出错的方式。
  • 精确匹配: 始终保持 job.writer.columns 的定义与目标数据库表的 DDL (表结构定义) 精确同步。任何一侧的结构变更,都应立即更新此配置。

参数联动

  • job.writer.table_name / job.writer.table_pattern: columns 定义的列必须是 table_name 或 table_pattern 匹配到的所有目标表所共有的。
  • job.writer.update_columns: 在 overwrite (upsert) 模式下,用于指定在主键冲突时需要更新的列。这个更新列表必须是 columns 的子集。
  • job.writer.partition_name: 在动态分区写入模式下,分区列 partition_name 必须包含在 columns 列表中。

FAQ(用户提问)

  • 问:我的任务报“列数量不匹配”的错误,是什么原因?
    • 答:这通常意味着您上游(Source)传过来的数据字段数量,与您在 job.writer.columns 中定义的数量不一致。请检查并确保两边完全对应。另外,也需要确认 job.writer.columns 中定义的列数量与目标表的实际列数(或您想插入的列数)是否匹配。
  • 问:源端有个字段,我不想把它写到目标库里,怎么办?
    • 答:很简单,只要不在 job.writer.columns 中包含那个字段即可。数据写入时,连接器只会处理 columns 中列出的字段。
  • 问:job.writer.columns 里的列顺序重要吗?
    • 答:非常重要。它决定了数据行中的值与 INSERT 语句中列的对应关系。错误的顺序会导致数据写到错误的字段中(例如,把年龄写到了姓名列),造成数据混乱。

注意事项

  • 类型准确性: columns 中定义的类型(如 string, bigint, timestamp)必须与目标数据库的物理类型兼容。错误的类型定义可能导致数据截断(如长字符串写入 VARCHAR(10))或写入失败。
  • 关键字冲突: 如果您的列名是数据库的关键字(如 order, group, key),连接器通常会自动添加反引号或双引号来处理。但最佳实践是避免使用关键字作为列名。

总结说明

job.writer.columns 是数据写入的“施工图纸”,它精确地规定了哪些数据、以何种类型、按何种顺序被写入目标表。保持这份“图纸”与目标表的物理结构完全一致,是保证数据正确写入的基石。任何与列相关的写入错误,都应首先从核对这份配置开始。

job.writer.table_pattern

参数概述

  • 参数名: job.writer.table_pattern
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: 无
  • 核心作用: 启用“动态表名写入”功能。它提供一个包含占位符的模板,连接器会根据每一行数据的内容,动态地计算出该行数据应该被写入的具体表名。

适用场景

  • 场景一:按业务维度将数据分发到不同表
    • 典型现象: 一个数据流中混合了多个地区、多个业务线或多个用户的数据,希望根据数据自身的属性(如 region_id, biz_code)将它们分别写入到 sales_beijing, sales_shanghai 或 orders_clothing, orders_electronics 等不同的表中。
    • 调整方向:设置 table_pattern,例如 sales_${region}。这里 ${region} 是一个占位符,它会从每一行数据中名为 region 的列里取值,并动态拼成目标表名。
  • 场景二:数据自动按日期/月份归档
    • 典型现象: 希望将实时数据流根据其产生的时间,自动写入到按月或按天创建的表中,如 log_202401, log_202402。
    • 调整方向:首先,确保数据流中有一个表示日期的字段(例如 log_date,值为 202401)。然后,将 table_pattern 设置为 log_${log_date}。

调参建议 / 推荐配置

  • 按需开启: 仅在需要将一个数据源写入到多个目标表的场景下使用。对于单表写入,无需配置此参数。
  • 占位符列: 模式中的占位符(如 ${column_name})必须对应于上游数据流中的某个列名。
  • 与 internal_columns 配合: 如果用于拼接表名的列(如 region)本身不需要作为数据被写入表中,可以将其配置在 job.writer.internal_columns。这会让连接器在生成 INSERT 语句时忽略该列。

参数联动

  • job.writer.columns: 用于计算表名的占位符列必须存在于数据流中,即必须是 Source 端 columns 的一部分。同时,所有可能被写入的动态表,它们的结构必须与 job.writer.columns 中定义的(非 internal_columns 的)列兼容。
  • job.writer.internal_columns: 用于存放那些只参与表名计算、但不需要实际写入的列名。
  • job.writer.ignore_mismatched_table_pattern: 一个容错开关。当某行数据根据 table_pattern 计算出的表名在数据库中不存在时:如果此参数为 false(默认),任务会报错失败;如果为 true,任务会跳过该行数据,并继续处理下一行。

FAQ(用户提问)

  • 问:我想把一个 topic 里的数据按城市分开存到不同的表里,比如 metrics_beijing,metrics_shanghai,该怎么做?
    • 答:这正是 table_pattern 的用武之地。首先,确保您的数据中有一个 city 字段。然后,将 table_pattern 设置为 metrics_${city}。这样,当一条数据的 city 字段是 beijing 时,它就会被自动写入 metrics_beijing 表。
  • 问:如果算出来的表名不存在,会发生什么?
    • 答:这取决于 ignore_mismatched_table_pattern 的配置。默认情况下(false),任务会因为找不到目标表而失败。如果您希望容忍这种情况,可以将该参数设为 true,任务会简单地丢弃这条数据。
  • 问:所有动态表都必须提前创建好吗?
    • 答:是的。table_pattern 功能只负责动态路由,不负责自动创建表(DDL)。您必须预先在数据库中创建好所有可能被写入的表,并确保它们的表结构是兼容的。

注意事项

  • 性能开销: 动态表写入会带来一定的性能开销。因为对于每一批数据,连接器都可能需要按计算出的不同表名进行分组,并为每个表准备不同的 PreparedStatement。如果一批数据中的目标表非常分散,可能会降低批量写入的效率。
  • 结构一致性: 所有被 table_pattern 覆盖的表,它们的结构应该是一致的(至少要包含 job.writer.columns 中定义的所有列)。否则,向结构不匹配的表写入数据时会失败。
  • 大小写: 占位符 ${column_name} 中的列名通常是大小写敏感的,请与数据流中的字段名保持一致。

总结说明

table_pattern 为您提供了强大的数据分发能力,能够像一个智能分拣机一样,根据数据自身的特点将其路由到不同的目标表中。当您需要实现按业务维度分表存储时,它是一个不可或缺的工具。使用时请务必确保所有目标表已提前建好且结构一致。

job.writer.connections

参数概述

  • 参数名: job.writer.connections
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: 默认值请以当前产品配置为准(通常根据您选择的数据源生成)。
  • 核心作用: 定义目标数据库的连接信息。它是一个列表,可以包含一个或多个数据库实例的 JDBC URL。

适用场景

  • 场景一:写入单个数据库实例
    • 典型现象: 最常见的场景,将数据写入到一个指定的数据库实例中。
    • 调整方向: 在 connections 列表中只配置一个 db_url。
  • 场景二:写入高可用数据库集群
    • 典型现象: 目标数据库是一个具有虚拟 IP(VIP)或高可用代理的集群。
    • 调整方向: 在 connections 中配置那个对应用透明的 VIP 地址。
  • 场景三:实现写入的负载均衡
    • 典型现象: 希望将写入压力分散到数据库集群的多个节点上(例如,一个支持多点写入的集群)。
    • 调整方向: 在 connections 列表中配置多个节点的 db_url,并配合 job.writer.write_connection_balance=true,使得不同的并发写入任务可以连接到不同的物理节点。

调参建议 / 推荐配置

  • 标准配置: 对于大多数场景,只需在 connections 中配置一个主库的 db_url。
  • 写入负载均衡: 如果您的数据库架构支持多点写入,并且希望分散写入负载,可以在 connections 中提供多个节点的 URL,并务必将 write_connection_balance 设为 true。

参数联动

  • job.writer.user_name / job.writer.password: 全局的用户名和密码,适用于 connections 中的所有连接。
  • job.writer.write_connection_balance: 这是决定 connections 中多个 db_url 如何被使用的关键开关。若为 false,所有并发任务都会尝试使用列表中的第一个 URL;若为 true,并发任务会(通过取模等方式)各自选择一个不同的 URL。
  • job.writer.connection_parameters: 向 connections 中的所有 db_url 统一追加 JDBC 连接参数。特别地,对于 MySQL,如果 URL 中没有 rewriteBatchedStatements 参数,系统会自动追加 rewriteBatchedStatements=true 来开启批量写入优化。

FAQ(用户提问)

  • 问:我的 Sink 任务报 connection refused,应该检查哪里?
    • 答:首先就应该检查 job.writer.connections 中的 db_url。确认 IP/域名、端口是否正确,并检查网络防火墙或安全组是否允许从任务运行环境到目标数据库的访问。
  • 问:connections 里可以填多个地址吗?如果第一个地址挂了,会自动用第二个吗?
    • 答:可以填多个地址。但是否会自动切换取决于 write_connection_balance 的设置和连接器的具体实现。当 write_connection_balance=true 时,不同的并发任务会连接到不同的地址,如果某个任务分配到的地址挂了,该任务会失败,但其他任务不受影响。连接器在初始化连接时也会做可用性检测,可能会跳过不可用的 URL。这种机制提供了一定程度的容错,但它不完全等同于一个全功能的、自动故障转移的 HA 方案。

注意事项

  • 批量写入参数: 为了获得最佳写入性能,特别是对于 MySQL,请确保 connections 的 URL 中包含了 rewriteBatchedStatements=true。大多数情况下,连接器会自动为您添加,但了解这一点总是有益的。
  • 凭证安全: 与 Source 端一样,密码等敏感信息不应明文配置,而是通过安全的方式注入。

总结说明

job.writer.connections 指明了数据写入的“目的地”。正确配置它是任务成功的基础。对于需要分散写入压力的场景,您可以通过配置多个连接地址并开启 write_connection_balance 来实现简单的写入负载均衡。

job.writer.write_connection_balance

参数概述

  • 参数名: job.writer.write_connection_balance
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: FALSE
  • 核心作用: 当 job.writer.connections 列表中配置了多个数据库连接 (db_url) 时,此参数决定了这些连接如何在多个并发的写入任务(task)之间进行分配。

适用场景

  • 场景一:分散写入压力到多个数据库节点
    • 典型现象: 目标数据库是一个支持多点写入的集群(例如,某些分布式数据库或配置了写负载均衡的 MySQL 集群),希望避免所有写入流量都集中在单一节点上。
    • 调整方向: 将 write_connection_balance 设置为 true。这样,不同的并发写入任务会根据自己的任务编号(task index)选择 connections 列表中的一个 db_url 进行连接。例如,0号任务连第一个URL,1号任务连第二个URL,以此类推(通常是取模轮询)。
  • 场景二:固定写入主节点
    • 典型现象: connections 中虽然配置了多个地址(可能包括主库和备库),但写入操作必须严格地只发生在主库上。
    • 调整方向: 保持 write_connection_balance 为 false。在这种默认模式下,所有的并发写入任务都会忽略列表中的其他地址,只尝试使用第一个 db_url。

调参建议 / 推荐配置

  • 写入负载均衡场景: 如果您的数据库后端支持且需要负载均衡,请务必将此参数设为 true。
  • 主备写入场景: 如果您的 connections 列表是按“主-备”顺序组织的,并且只允许写主库,请务必保持此参数为 false。

参数联动

  • job.writer.connections: 此参数只有在 connections 列表包含多个 db_url 时才有意义。如果只有一个 db_url,此参数不起任何作用。

FAQ(用户提问)

  • 问:我在 connections 里配了3个数据库地址,但从监控看,压力都在第一台机器上,为什么?
    • 答:这很可能是因为您没有将 write_connection_balance 设置为 true。在默认的 false 状态下,即使您提供了多个地址,所有任务也只会使用第一个。请将其设置为 true 以启用连接的均衡分配。
  • 问:开启这个功能后,如果某个数据库节点挂了会怎么样?
    • 答:当 write_connection_balance=true 时,如果某个并发任务分配到的数据库节点正好是故障节点,那么这个并发任务在尝试连接时会失败,并可能导致其自身不断重试或最终失败。这可能会影响整个数据同步任务的进度,但不会影响那些连接到健康节点的其他并发任务。连接器在分配连接时通常也会做可用性检测,可能会主动跳过已知的坏节点。

注意事项

  • 不保证绝对均衡: 此参数提供的“负载均衡”是基于连接分配层面的简单轮询或哈希,它不保证实际的写入负载(如QPS或数据量)在各个节点上是绝对平均的。实际的负载均衡效果还取决于上游数据的分布情况。
  • 数据库架构支持: 请确保您的数据库架构支持多点并发写入。对于传统的、单主节点的数据库,开启此功能并提供多个地址可能没有意义,甚至可能导致错误。

总结说明

write_connection_balance 是您在多连接配置下,决定“雨露均沾”还是“独宠一人”的关键开关。当您希望将写入压力分散到多个数据库节点时,请将它设置为 true;当您需要确保所有写入都 строго地指向主节点时,请保持其默认的 false 状态。

job.writer.write_mode

参数概述

  • 参数名: job.writer.write_mode
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: insert
  • 核心作用: 定义数据写入目标数据库时的核心语义,即如何处理已存在或不存在的数据。

适用场景

  • insert:
    • 语义: 先删后写。在任务启动时,会先根据 partition_name 和 partition_value 生成 DELETE 语句,清空目标表中对应分区的数据。然后,再将新数据以 INSERT 的方式写入。
    • 适用场景: 典型的批量覆盖场景,例如每天重新计算前一天的全量数据并覆盖写入。
  • overwrite:
    • 语义: 插入或更新 (Upsert)。通常会生成 INSERT ... ON DUPLICATE KEY UPDATE ... (MySQL) 或 MERGE INTO ... (Oracle, PostgreSQL) 这样的语句。当插入的数据行根据主键或唯一索引判断已存在时,会执行更新操作;否则执行插入操作。
    • 适用场景: 需要对已有数据进行更新的流式或增量场景,例如同步用户信息的变更。
  • replace:
    • 语义: 替换。通常会生成 REPLACE INTO ... 语句 (MySQL)。其行为类似于:如果记录不存在,则 INSERT;如果存在,则先 DELETE 旧记录,再 INSERT 新记录。
    • 适用场景: 逻辑比 overwrite 简单,但开销可能更大(删除+插入 vs. 原地更新)。
  • insertIgnore:
    • 语义: 插入或忽略。通常生成 INSERT IGNORE INTO ... 语句 (MySQL)。当插入的数据行因主键或唯一键冲突时,它会简单地忽略这条新数据,既不插入也不更新,也不会报错。
    • 适用场景: 只希望插入新数据,对于已存在的记录不做任何处理。
  • dynamic:
    • 语义: 动态分区清理。这是一种更高级的模式,它会根据流入数据中 partition_name 列的值,动态地决定需要清理哪些分区。它只会在第一次遇到某个新的分区值时,触发对该分区的清理操作。
    • 适用场景: 流式任务,数据按分区持续写入,且希望每个分区在本次任务运行中只被清理一次。例如,一个长周期运行的任务,不断接收到新的日期分区的数据。

调参建议 / 推荐配置

  • 批量覆盖: 使用 insert。
  • 增量更新: 使用 overwrite。这是实现 Upsert 逻辑最常见、最有效的方式。
  • 只插不改: 使用 insertIgnore。
  • 流式分区覆盖: 使用 dynamic。

参数联动

  • job.writer.partition_name / job.writer.partition_value: insert 和 dynamic 模式强依赖这些参数来确定清理范围。
  • job.writer.update_columns: 在 overwrite 模式下,此参数用于指定冲突时需要更新的列。如果不配置,通常会更新所有非主键列。
  • 主键/唯一索引: overwrite, replace, insertIgnore 模式的行为都依赖于目标表上存在主键或唯一索引来判断“冲突”。

FAQ(用户提问)

  • 问:insert 和 overwrite 有什么区别?
    • 答:insert 是“先清空分区,再全部插入”,它是一种破坏性的覆盖,不关心数据是否已存在。而 overwrite 是“如果存在就更新,不存在就插入”,它是一种非破坏性的、基于逐行匹配的更新,通常更慢但更精细。
  • 问:我想实现“有就更新,没有就插入”的逻辑,应该用哪个模式?
    • 答:应该使用 overwrite 模式。
  • 问:dynamic 模式是做什么的?
    • 答:您可以把它理解为一个“智能”的 insert 模式。普通的 insert 模式在任务开始时就一次性地把指定分区(partition_value)删了。而 dynamic 模式会“看着”流过来的数据,当它发现来了一个新的分区值(例如,时间从 10:00 走到了 11:00,分区字段是小时),它才去触发对 11:00 这个分区的清理操作,并且在整个任务生命周期里只对 11:00 清理一次。这非常适合长周期运行的流式任务。

注意事项

  • 数据库支持: 不同的 write_mode 最终会生成不同的 SQL 方言。请确保您的目标数据库支持相应的语法(例如,ON DUPLICATE KEY UPDATE 是 MySQL 特有的,MERGE INTO 更通用)。
  • insert 模式的危险性: insert 模式下的 DELETE 操作是不可逆的。请在配置 partition_value 时务必小心,错误的配置可能导致删错数据。在生产环境使用前,请在测试环境充分验证其清理范围是否符合预期。
  • 性能: overwrite 和 replace 因为需要进行存在性检查,其单行写入的开销通常比纯 insert 要高。

总结说明

job.writer.write_mode 是决定数据如何“落地”的核心参数,它直接关系到数据的最终一致性。请根据您的业务是需要全量覆盖、增量更新还是只插新人,来审慎地选择 insert, overwrite 或 insertIgnore。对于需要按数据内容动态管理分区的长周期流式任务,dynamic 模式是您的不二之选。

job.writer.update_columns

参数概述

  • 参数名: job.writer.update_columns
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: 无
  • 核心作用: 在 write_mode 为 overwrite (Upsert) 时,指定当发生主键或唯一键冲突时,需要更新哪些列。

适用场景

  • 场景一:只更新特定字段
    • 典型现象: 同步用户信息时,希望只更新用户的 last_login_time 和 status 字段,而 create_time 等固定字段不应被改变。
    • 调整方向: 在 update_columns 列表中明确指定 ["last_login_time", "status"]。这样,生成的 ON DUPLICATE KEY UPDATE 语句将只会更新这两列。
  • 场景二:更新除主键外的所有字段
    • 典型现象: 增量更新时,希望以源端数据为准,全面更新目标表的记录。
    • 调整方向: 不配置 update_columns 参数。在这种情况下,连接器默认会更新 job.writer.columns 中除主键/唯一键之外的所有列。

调参建议 / 推荐配置

  • 精确更新: 为了代码的可读性和意图的明确性,即使您想更新所有列,也建议在 update_columns 中明确列出它们。这可以防止未来 columns 增加新字段时,该新字段被意外地加入到更新列表中。
  • 性能优化: 如果只需要更新少量字段,请务必配置此参数。只更新必要的列可以减少数据库的 I/O 和 binlog 日志量,提升写入性能。

参数联动

  • job.writer.write_mode: update_columns 只在 write_mode = 'overwrite' 时生效。
  • job.writer.columns: update_columns 中列出的所有字段,必须是 job.writer.columns 的子集。
  • 目标表的主键/唯一索引: overwrite 模式和 update_columns 的行为,完全依赖于目标表上存在主键或唯一索引来触发“冲突(DUPLICATE KEY)”逻辑。

FAQ(用户提问)

  • 问:使用 overwrite 模式时,是不是所有字段都会被更新?
    • 答:这取决于您是否配置了 update_columns。如果您没有配置它,那么默认行为是更新所有非主键/唯一键的字段。如果您配置了它,那么只有列表中指定的字段才会被更新。
  • 问:我想在记录冲突时,只更新 price 和 stock 字段,怎么做?
    • 答:您需要在 update_columns 中进行如下配置:["price", "stock"]。

注意事项

  • 列名准确性: 列表中的列名必须与目标数据库的物理列名完全匹配,包括大小写(取决于数据库)。
  • 不支持表达式: update_columns 只是一个列名的列表,不支持在其中使用表达式,例如 count = count + 1。这种逻辑需要数据库层面的触发器或在数据ETL过程中提前处理。

总结说明

update_columns 是您在进行“插入或更新”(Upsert)操作时的精细控制器。通过它,您可以精确地指定哪些字段需要“与时俱进”,哪些字段应该“保持初心”。为了获得最佳性能和最明确的业务意图,我们建议您始终明确配置需要更新的列。

job.writer.partition_name

参数概述

  • 参数名: job.writer.partition_name
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: 无
  • 核心作用: 在需要进行分区操作(如分区清理)时,指定作为分区依据的列名。

适用场景

  • 场景一:批量覆盖指定分区的数据
    • 典型现象: 每天的任务需要先删除目标表中前一天的数据分区,然后再插入新数据。
    • 调整方向: 将 write_mode 设为 insert,同时设置 partition_name 为您的分区字段(例如 dt 或 log_date),并提供 partition_value 来指定具体要清理哪个分区。
  • 场景二:流式写入,动态管理分区
    • 典型现象: 一个长期运行的任务,持续接收不同分区的数据(例如,按小时分区的数据流)。
    • 调整方向: 将 write_mode 设为 dynamic,并设置 partition_name。连接器会从流入的每一行数据中读取 partition_name 对应的列值,并据此动态地管理(如清理)目标表的分区。

调参建议 / 推荐配置

  • 分区写入时必填: 只要您的写入逻辑涉及分区清理(insert 或 dynamic 模式),此参数就是必需的。
  • 与 extra_partitions 配合: 对于多级分区表,您可以使用 extra_partitions 来定义更复杂的分区结构,但 partition_name 通常用于定义第一级或最主要的分区键。

参数联动

  • job.writer.write_mode: partition_name 主要与 insert 和 dynamic 模式配合使用。对于 overwrite 等不涉及分区级清理的模式,此参数可能不是必需的。
  • job.writer.partition_value: 在 insert 模式下,partition_name 和 partition_value 必须成对出现,共同定义了要清理的分区,例如 WHERE dt = '20240101'。
  • job.writer.columns: 在 dynamic 模式下,partition_name 所指定的列必须包含在 job.writer.columns 列表中,因为连接器需要从数据行中读取该列的值。

FAQ(用户提问)

  • 问:insert 模式和 partition_name 是什么关系?
    • 答:在 insert 模式下,连接器会在写入前执行 DELETE 操作。partition_name 就是用来构建这个 DELETE 语句的 WHERE 子句的。例如,partition_name 是 biz_date,partition_value 是 2024-04-10,那么执行的清理语句就会是 DELETE FROM your_table WHERE biz_date = '2024-04-10'。
  • 问:我的目标表是分区表,但 write_mode 是 overwrite,还需要配 partition_name 吗?
    • 答:不一定需要。overwrite 模式是基于行级别的主键/唯一键冲突来做 INSERT/UPDATE 的,它本身不执行分区级的 DELETE。除非连接器的某些特定实现(如为了生成 MERGE 语句的分区裁剪)需要它,否则通常可以不配。

注意事项

  • 列存在性: 请确保 partition_name 指定的列在目标数据库表中真实存在。
  • 非数据库分区: 此处的“分区”是连接器在应用层为实现“先删后写”而抽象出的一个概念,它不一定等同于数据库物理存储上的分区(Partitioned Table)。当然,两者通常是一致的,即将数据库的物理分区键作为 partition_name。

总结说明

partition_name 是您在进行分区级数据覆盖或管理时,用于定位目标的“坐标轴”。当您使用 insert 或 dynamic 写入模式时,请务必正确设置此参数,以确保清理和写入操作能够精确地作用于您指定的数据范围。

job.writer.write_batch_size

参数概述

  • 参数名: job.writer.write_batch_size(别名: job.writer.write_batch_interval)
  • 适用范围: JDBC Sink
  • 单位: 行
  • 默认值: 100
  • 核心作用: 定义了在将数据写入数据库时,内存中缓冲区的最大行数。当缓冲区中的数据达到这个数量时,连接器会触发一次批量提交(executeBatch)。这是影响写入性能的最核心参数之一。

适用场景

  • 场景一:提升写入吞吐(高流量场景)
    • 典型现象: 数据同步任务的写入速度跟不上源端数据的产生速度,出现数据积压。数据库负载不高,网络带宽充裕。
    • 调整方向:调大 write_batch_size。例如,从 100 增加到 1000, 5000 甚至更高。通过将多次小批量 commit 合并为一次大批量 commit,可以极大地减少网络往返和数据库的提交开销,从而成倍提升写入吞吐。
  • 场景二:降低写入延迟(低流量/实时性要求高场景)
    • 典型现象: 数据源产生的数据量很小,或频率很低,但需要尽快在目标库中看到。由于 write_batch_size 较大,数据一直在缓冲区中等待,无法及时提交。
    • 调整方向:调小 write_batch_size。例如,设置为 1 或 10。这样,即使只有几条数据到来,也能很快触发提交,保证了数据的实时性。
  • 场景三:避免单次提交事务过大或内存溢出
    • 典型现象: write_batch_size 设置得过大,导致单次批量写入的 PreparedStatement 过于庞大,超出了数据库或 JDBC 驱动的处理能力,或者在客户端缓冲数据时消耗了过多内存,导致 OOM。
    • 调整方向:调小 write_batch_size,将大批量分解为多个小批量,以降低对内存和数据库单次处理能力的压力。

调参建议 / 推荐配置

  • 吞吐优先 (高流量): 在数据库和任务资源允许的情况下,尽量调大此值。1000 到 10000 是一个常见的优化范围。更大的值可以带来更高的吞吐,但收益会逐渐递减。
  • 实时性优先 (低流量): 调小此值。对于严格要求实时性的场景,可以设置为 1,但这会牺牲吞吐性能,因为每次写入都将退化为单条 commit。
  • 均衡配置: 默认值 100 是一个在实时性和吞吐之间取得的保守平衡,适用于不确定负载的初始场景。

参数联动

  • job.writer.is_support_transaction: write_batch_size 定义了单个事务的大小。如果事务被关闭,那么每次批量提交的一致性将得不到保证。
  • job.writer.write_retry_times: 如果一次大批量的写入失败,整个批次的数据都会被重试。因此,越大的 batch_size 意味着越大的重试成本。
  • job.writer.flush_interval_ms: 在流式模式下,除了批次大小,还有一个基于时间的触发器。即使缓冲区未满 write_batch_size,只要距离上次提交超过了 flush_interval_ms,也会强制触发一次提交。这为低流量场景提供了延迟保障。

FAQ(用户提问)

  • 问:我的写入任务很慢,是不是把 write_batch_size 调得越大越好?
    • 答:在一定范围内是的,但存在上限。调大 batch_size 可以显著提升吞吐,但当它大到一定程度后,性能收益会减少,而内存消耗和失败时的重试代价会持续增加。过大的批次还可能触及数据库的各种限制(如最大查询长度、事务日志大小等)。最佳实践是通过逐步增大此值并进行压测,找到性能曲线的“拐点”。
  • 问:数据源过来的数据很少,但总是要等很久才能在目标库里看到,为什么?
    • 答:这很可能是因为 write_batch_size 设置得比较大,而数据流量太小,迟迟“凑不够”一个批次。您可以尝试调小 write_batch_size,或者检查 flush_interval_ms(流式场景)是否设置了一个合理的值,以保证低流量下的数据也能被及时提交。

注意事项

  • 内存消耗: 批次大小与内存消耗成正比。请确保您的任务有足够的内存来缓冲一个完整的批次。
  • 数据库支持: 批量写入的性能很大程度上依赖于 JDBC 驱动的实现。对于 MySQL,请务必确保连接 URL 中包含 rewriteBatchedStatements=true,否则 executeBatch 可能会退化为循环单条插入,失去批量优化的意义。
  • 事务日志: 大批量的写入会产生更大的数据库事务,这可能会对事务日志(如 a binlog, redo log)造成压力。

总结说明

write_batch_size 是您手中最锋利的写入性能调优工具。在高流量、追求极致吞吐的场景下,请不要吝啬,大胆地增加它;在低流量、追求实时响应的场景下,请毫不犹豫地减小它。通过在这个“吞吐”与“延迟”的跷跷板上找到最佳平衡点,您的数据写入任务将能游刃有余地应对各种业务需求。

job.writer.write_retry_times

参数概述

  • 参数名: job.writer.write_retry_times
  • 适用范围: JDBC Sink
  • 单位: 次
  • 默认值: 3
  • 核心作用: 当一次批量写入或单条写入操作因数据库暂时不可用、网络抖动、死锁等可恢复的异常而失败时,系统自动进行重试的最大次数。

适用场景

  • 场景一:提升任务在不稳定环境下的成功率
    • 典型现象: 任务日志中偶尔出现数据库连接超时、死锁、连接被重置等瞬时错误,导致任务失败。
    • 调整方向: 适当调大 write_retry_times,例如从 3 次增加到 5 次。这给了任务更多机会去“熬过”数据库的短暂不稳定,从而避免整个任务因偶发问题而失败重启。
  • 场景二:快速响应持续性故障
    • 典型现象: 对于关键任务,当数据库发生严重且持续的故障(如宕机、主备切换失败)时,希望任务能尽快失败并触发告警。
    • 调整方向:调小 write_retry_times 到 1 或 0。这样可以减少在无效重试上浪费的时间,让问题更快地暴露给监控系统。

调参建议 / 推荐配置

  • 默认推荐: 3 次重试是一个适用于大多数情况的均衡配置,它能有效处理瞬时抖动,又不会在硬性故障面前延迟太久。
  • 生产环境增强: 对于部署在生产环境,特别是网络链路较长或数据库负载较高的关键任务,可以考虑将其设置为 5 次,以增加稳健性。
  • 快速失败场景: 如果任务失败需要被立即感知并处理,可以设置为 1。

参数联动

  • job.writer.retry_interval_seconds: 定义了两次重试之间的等待间隔。合理的间隔可以避免对正在恢复中的数据库造成“雪崩”效应。
  • job.writer.is_process_exception_as_dirty: 当一个批次写入失败,并且所有重试(write_retry_times)都用尽后,连接器会降级为逐条写入。此时,如果 is_process_exception_as_dirty 为 true,那么单条写入再次失败的记录会被送入“脏数据”队列(如果配置了),任务继续运行;如果为 false,则任务直接失败。

FAQ(用户提问)

  • 问:我的写入任务有时会因为“死锁”而失败,增加重试次数有用吗?
    • 答:非常有用。死锁(Deadlock)是数据库中一种典型的瞬时资源冲突,通常数据库自身会选择一个事务作为“牺牲品”并回滚它。连接器捕获到这个死锁异常后,进行重试,大概率在下一次尝试时死锁情况已经解除,写入就能成功。因此,对于容易发生死锁的场景,合理的重试是保障任务成功率的重要手段。
  • 问:什么情况下重试是无效的?
    • 答:对于“永久性”错误,重试是无效的。例如:SQL 语法错误、违反数据表约束(如非空、外键)、数据类型不匹配、目标表或列不存在等。对于这些问题,无论重试多少次都会报同样的错,只会白白浪费时间。

注意事项

  • 幂等性: 重试机制能否安全使用,取决于写入操作是否可以被认为是幂等的。
    • overwrite (Upsert) 和 replace 模式天然是幂等的,多次执行同一批数据的结果是一样的。
    • insert 模式在有 DELETE 前置操作时,如果重试的是整个“先删后写”的批次,也是幂等的。但如果是在降级为单条写入后重试,可能会引入重复数据(如果事务被关闭)。
  • 重试成本: 对于大批量的写入,一次失败和重试的成本是比较高的。这也是为什么在调大 write_batch_size 的同时,需要审慎评估重试策略。

总结说明

job.writer.write_retry_times 是您数据写入任务的“复活甲”。它让任务在面对数据库的瞬时风波时,拥有了“再试一次”的勇气和能力。合理配置重试次数,可以在不牺牲太多时间的情况下,显著提升任务在复杂生产环境中的稳定性和最终成功率。

job.writer.is_support_transaction

参数概述

  • 参数名: job.writer.is_support_transaction
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: TRUE
  • 核心作用: 控制数据写入时是否启用 JDBC 事务。当启用时,每一批次的写入(由 write_batch_size 定义)都会被包裹在一个事务中,要么全部成功(commit),要么全部失败(rollback),从而保证了单批数据的原子性。

适用场景

  • 场景一:保证数据写入的原子性
    • 典型现象: 任何情况下都不能接受一个批次的数据只写入了一部分。例如,一个订单和它的多条明细必须同时写入成功。
    • 调整方向: 保持 is_support_transaction 为 true。这是保证数据一致性的最基本要求。
  • 场景二:绕过特定数据库的事务限制
    • 典型现象: 任务向某些特殊的数据库(如某些分布式数据库的特定版本,或配置了某些引擎的 MySQL)写入时,报错提示不支持分布式事务或 XA 事务。
    • 调整方向: 作为一种最后的规避手段,可以将 is_support_transaction 设置为 false。这会关闭事务,连接将以 auto-commit 模式运行,每条 SQL 语句执行后都会立即提交。

调参建议 / 推荐配置

  • 强烈建议保持开启: 在任何支持事务的关系型数据库(如 MySQL, PostgreSQL, Oracle)中,都应该保持 is_support_transaction=true。这是保证数据一致性的生命线。
  • 仅在特殊情况下关闭: 只有当您明确知道目标数据库不支持事务,或者遇到了无法解决的事务相关报错,并且业务上可以接受“无事务”带来的风险时,才考虑关闭此开关。

参数联动

  • job.writer.write_batch_size: 当事务开启时,write_batch_size 定义了单个事务内包含的 SQL 语句数量。
  • Flink Checkpoint: Flink 的 checkpoint 机制与此参数共同保证了端到端的 exactly-once 或 at-least-once。在 Flink 的两阶段提交协议中,JDBC Sink 的事务扮演了关键角色。关闭事务会严重影响端到端的一致性保证。

FAQ(用户提问)

  • 问:关闭事务会有什么后果?
    • 答:关闭事务意味着失去了原子性保证。如果一个批次(比如1000行)在写入到第500行时发生错误,那么前499行数据已经永久地提交到了数据库中,无法回滚。这会导致数据不一致。此外,它也会影响 Flink 的 exactly-once 语义,可能导致在任务从 checkpoint 恢复时出现数据重复。
  • 问:我的任务总是报一个关于 XA 事务的错误,怎么办?
    • 答:这通常是因为 Flink 的两阶段提交机制与目标数据库的事务支持模式存在冲突。作为临时的解决方案,您可以尝试将 is_support_transaction 设为 false 来绕过这个问题,但这会牺牲一致性。更根本的解决方案是检查您的数据库配置或 JDBC 驱动版本,看是否可以调整以更好地支持分布式事务。

注意事项

  • 一致性降级: 关闭事务是一个重大的决定,它会将数据写入的一致性保证从“批次原子性”降级为“单语句原子性”。请在做此决定前,充分评估其对业务数据准确性的影响。
  • 自动降级: 连接器内部可能存在一些智能逻辑,例如当检测到特定的、已知的 MySQL 分布式事务不支持的错误时,会自动尝试关闭事务并重连,即使 is_support_transaction 初始为 true。

总结说明

is_support_transaction 是数据写入的“安全网”,它通过事务机制保障了每批数据的“同生共死”,是数据一致性的基石。我们强烈建议您始终保持其开启状态。只有在遇到无法规避的、特定于数据库的事务兼容性问题,且业务可以容忍其风险时,才应考虑将其关闭。

job.writer.is_process_exception_as_dirty

参数概述

  • 参数名: job.writer.is_process_exception_as_dirty
  • 适用范围: JDBC Sink
  • 单位: 无
  • 默认值: FALSE
  • 核心作用: 定义了当批量写入失败、经过重试后降级为单条写入时,如何处理那些依然失败的“坏数据”。

适用场景

  • 场景一:允许任务容忍少量坏数据
    • 典型现象: 一个大数据量的同步任务中,总会有千分之几或万分之几的数据因为各种原因(如格式错误、违反约束)无法写入。不希望因为这几条“坏鱼”而导致整锅“汤”(整个任务)失败。
    • 调整方向: 将 is_process_exception_as_dirty 设置为 true。这样,在单条写入模式下失败的数据行会被捕获,并作为“脏数据”进行上报或记录(如果配置了脏数据收集机制),而任务本身会继续处理后续的正常数据。
  • 场景二:严格要求所有数据必须成功写入
    • 典型现象: 任何一条数据的写入失败都是不可接受的,必须立即中止任务并进行人工排查。
    • 调整方向: 保持 is_process_exception_as_dirty 为 false。在这种模式下,一旦在单条写入模式下有任何一行数据失败,整个任务就会立即抛出异常并失败。

调参建议 / 推荐配置

  • 容错优先: 对于数据质量无法完全保证的大规模ETL任务,建议设置为 true,配合脏数据收集机制,可以大大提升任务的健壮性。
  • 一致性/质量优先: 对于金融级或对数据准确性有极致要求的任务,建议保持 false,确保任何问题都能在第一时间被发现。

参数联动

  • job.writer.write_retry_times: 脏数据处理逻辑是在批量写入和重试都失败后,进入单条写入模式时才会被触发的。
  • 脏数据收集机制: 此参数的效果依赖于整个数据同步平台是否提供了配套的脏数据存储和展示功能。如果平台不支持,那么设置为 true 可能仅仅意味着“悄无声息地丢弃了坏数据”。

FAQ(用户提问)

  • 问:我的任务总因为几条“脏数据”就挂了,能让它跳过这些坏数据继续跑吗?
    • 答:可以。将 is_process_exception_as_dirty 设置为 true 就能实现这个效果。它会让任务在遇到无法写入的单条数据时,选择“记录并放行”,而不是“原地引爆”。
  • 问:被当作“脏数据”处理的数据去哪了?
    • 答:这取决于您所使用的数据同步平台。通常,平台会提供一个“脏数据”列表或日志,您可以从中看到具体是哪些数据、因为什么原因写入失败,以便后续进行分析和修复。

注意事项

  • 可能丢失数据: 如果没有配套的脏数据收集和告警机制,将此参数设为 true 可能会导致数据在您不知情的情况下被“丢弃”。请务必确认您的平台支持对“脏数据”的后续处理。
  • 问题掩盖: 过度依赖此功能可能会掩盖上游的数据质量问题。定期检查脏数据并从源头解决问题,比单纯地在写入时容错更为重要。

总结说明

is_process_exception_as_dirty 是您在任务的“健壮性”与“严格性”之间做选择的开关。将它设为 true,您的任务将变得“心胸宽广”,能够容忍少数害群之马,适合大规模、数据质量参差不齐的场景。保持 false,则任务会成为一个“铁面无私的法官”,任何瑕疵都将导致流程中止,适合对数据质量要求零容忍的场景。

JDBC Properties 参数详解

jdbc.properties.*

参数概述

  • 参数名:jdbc.properties.*
  • 适用范围:
    • JDBC Source / JDBC Sink
    • 通过 JDBC 驱动连接数据库的读写场景
    • 常见于 MySQL、兼容 MySQL 协议的数据库,也可扩展到其他 JDBC 驱动
  • 默认值:无默认值
  • 核心作用:jdbc.properties.*:按 key=value 方式逐项传入 JDBC 连接属性

常用子参数清单

  1. SSL / 安全相关
    • useSSL
      • 是否启用 SSL/TLS 加密连接。
      • 常见值:true / false
    • sslMode
      • 控制 SSL 的强制与校验级别。
      • 常见值:DISABLED、PREFERRED、REQUIRED、VERIFY_CA、VERIFY_IDENTITY
    • verifyServerCertificate
      • 是否校验服务端证书。
      • 常见于老版本 MySQL 驱动。
    • trustCertificateKeyStoreUrl
      • 服务端证书信任库路径
    • trustCertificateKeyStorePassword
      • 服务端证书信任库密码
    • trustCertificateKeyStoreType
      • 服务端证书信任库类型,如 JKS、PKCS12。
    • clientCertificateKeyStoreUrl
      • 客户端证书路径,用于双向 TLS
    • clientCertificateKeyStorePassword
      • 客户端证书密码
    • clientCertificateKeyStoreType
      • 客户端证书类型
    • enabledTLSProtocols
      • 指定允许的 TLS 协议版本,如 TLSv1.2,TLSv1.3。
  2. 连接稳定性相关
    • connectTimeout
      • 建连超时时间
      • 适合排查连接建立慢、网络抖动。
    • socketTimeout
      • 读写超时时间
      • 适合长查询、慢写入场景。
    • autoReconnect
      • 是否自动重连。
      • 一般只建议作为兼容性辅助参数,不建议完全依赖它解决连接不稳。
  3. 兼容性相关
    • allowPublicKeyRetrieval
      • 常见于 MySQL 8 认证相关问题。
      • 当账号认证或握手失败时常会关注它。
    • serverTimezone
      • 指定服务端时区。
      • 适合时间字段读写异常、时区偏移问题。
    • zeroDateTimeBehavior
      • 处理零日期,如 convertToNull。
    • useUnicode
      • 是否使用 Unicode
    • characterEncoding
      • 字符编码,如 utf-8、utf8。
  4. 性能相关
  • rewriteBatchedStatements
    • 是否重写批量语句。
    • 常用于提升批量写入效率
  • useServerPrepStmts
    • 是否启用服务端预编译。
  • cachePrepStmts
    • 是否缓存预编译语句。
  • prepStmtCacheSize
    • 预编译缓存大小
  • prepStmtCacheSqlLimit
    • 可缓存 SQL 长度上限。

适用场景

  1. 数据库要求必须加密传输。
    • 典型现象:
      • 明文连接被拒绝。
      • 安全规范要求链路必须加密。
    • 建议关注的参数:
      • useSSL
      • sslMode
    • 推荐方向:
      • useSSL=true
      • sslMode=REQUIRED
      • 如果安全要求更高,进一步使用 VERIFY_CA 或 VERIFY_IDENTITY。
  2. JDBC 连接经常超时或建连慢
    • 典型现象:
      • 连接初始化慢。
      • 偶发 timeout、timed out
    • 建议关注的参数:
      • connectTimeout
      • socketTimeout
    • 推荐方向:
      • 先补齐超时配置,再看网络与数据库负载。
      • 不建议只靠调大超时掩盖网络或数据库本身的问题。
  3. MySQL 8 认证或握手异常。
    • 典型现象:
      • 登录失败。
      • 握手相关报错
      • SSL 与认证同时出现问题。
    • 建议关注的参数:
      • allowPublicKeyRetrieval
      • useSSL
      • sslMode
    • 推荐方向:
      • 在明确是认证兼容问题时,再考虑增加 allowPublicKeyRetrieval=true。
  4. 中文乱码、字符集不一致
    • 典型现象:
      • 中文字段乱码
      • 特殊字符写入异常
    • 建议关注的参数:
      • useUnicode
      • characterEncoding
    • 推荐方向:
      • 常见建议:useUnicode=true
      • characterEncoding=utf-8
  5. 批量写入吞吐偏低
    • 典型现象:
      • JDBC sink 写入慢
      • 批量场景吞吐不理想
    • 建议关注的参数:
      • rewriteBatchedStatements
      • 预编译缓存相关参数
    • 推荐方向:
      • MySQL 批量写场景优先关注 rewriteBatchedStatements=true。

调参建议 / 推荐配置

  • 默认推荐

    jdbc.properties.useSSL=true
    jdbc.properties.sslMode=REQUIRED
    jdbc.properties.connectTimeout=10000
    jdbc.properties.socketTimeout=60000
    jdbc.properties.useUnicode=true
    jdbc.properties.characterEncoding=utf-8
    
  • 吞吐优先

    jdbc.properties.rewriteBatchedStatements=true
    jdbc.properties.useServerPrepStmts=true
    jdbc.properties.cachePrepStmts=true
    jdbc.properties.prepStmtCacheSize=250
    
  • 兼容优先

    jdbc.properties.useSSL=false
    jdbc.properties.useUnicode=true
    jdbc.properties.characterEncoding=utf-8
    jdbc.properties.zeroDateTimeBehavior=convertToNull
    
  • 排障临时配置

    jdbc.properties.useSSL=true
    jdbc.properties.sslMode=REQUIRED
    jdbc.properties.allowPublicKeyRetrieval=true
    jdbc.properties.connectTimeout=10000
    

参数联动

建议重点一起看以下几组:

  • useSSL + sslMode
    • 一个决定是否启用 SSL,一个决定 SSL 的强制和校验策略。
  • useUnicode + characterEncoding
    • 编码问题通常要一起看。
  • connectTimeout + socketTimeout
    • 一个控制建连,一个控制读写
  • rewriteBatchedStatements + 批量写入参数
    • 只开其中一个,效果可能不明显。
  • sslMode + 证书库参数
    • 如果使用 VERIFY_CA / VERIFY_IDENTITY,通常还要配证书相关参数。
  • 数据源统一配置
    • 需要在数据源高级参数配置 url.properties= {"":"",}。

FAQ(用户提问)

  1. jdbc.properties.* 和 url.properties 用哪个更好?
    • 功能上都可以。
    • 人工维护、排障阅读更推荐 jdbc.properties.*。
    • 平台统一下发、对象式配置更适合 url.properties。
  2. 能不能两个一起配?
    • 可以,但不建议对同一个子参数重复配置。
    • 如果同一个 key 在两处都出现,容易引起歧义,后续排障成本高。
  3. 这些参数能解决所有 JDBC 连接问题吗?
    • 不能。
    • 它们只负责 JDBC 驱动层连接属性。
    • 如果是账号密码错误、权限问题、白名单、网络不通、数据库负载过高,单靠这些参数解决不了。
  4. sslMode=REQUIRED 和 useSSL=true 是不是重复?
    • 不是完全重复。
    • 前者是策略,后者是开关。
    • 一起显式配置更清晰,也更稳定。
  5. 为什么调了这些参数效果不明显?
    • 可能瓶颈不在 JDBC 连接层。
    • 如果问题来自 SQL 本身、数据库索引、下游写入能力或网络抖动,调连接属性帮助有限。

注意事项

  • 这两个参数族是“容器”,不是固定参数名列表。
  • 真正生效的是里面的子参数,且不同数据库驱动支持范围不同。
  • MySQL 能用的子参数,不一定适用于 PostgreSQL、Oracle、SQL Server。
  • 不建议新旧风格参数混搭过多,例如同时混用 sslMode 和老式 requireSSL、verifyServerCertificate。
  • 涉及证书密码、账号密钥类参数时,注意脱敏,避免明文暴露在日志和配置展示中。
  • 建议一次只调整一组参数,方便判断效果。

总结说明

jdbc.properties.* 与 url.properties 都用于为 JDBC 连接补充扩展属性,常见可配置项包括 SSL 加密、超时、字符编码、批量写优化和驱动兼容参数。

  • 若以人工维护和排障为主,建议优先使用 jdbc.properties.*,可读性更好;
  • 若由平台统一透传扩展配置,则 url.properties 更适合集中承载。

对 MySQL 场景,常见优先关注的子参数包括 useSSL、sslMode、connectTimeout、socketTimeout、characterEncoding、rewriteBatchedStatements 和 allowPublicKeyRetrieval,并建议按安全、兼容、性能三类目标分组调优。

最近更新时间:2026.07.01 19:22:48
这个页面对您有帮助吗?
有用
有用
无用
无用