本文详细介绍了 DataSail JDBC Connector 的高级参数配置,包括 Source、Sink 等,可以帮助您提升数据同步任务的性能、稳定性与资源利用率。
下表汇总了 JDBC Source 的核心参数,帮助您快速定位和理解其作用。
参数名 | 简要作用 | 默认值参考 | 建议调参方向 |
|---|---|---|---|
job.reader.columns | 定义需要从源端读取的列,支持常量、函数等。 | 按任务配置 | 按需配置,确保包含 |
job.reader.connections | 配置源数据库的连接信息(主库、备库等)。 | 按数据源配置 | 读写分离场景下可配置多个备库地址。 |
job.reader.enable_table_pattern | 是否将 | FALSE | 需要同步多张结构相似的表(如 |
job.reader.table_include_list | 配合 | 无 | 在正则匹配范围较大时,用于精确圈定需要同步的表。 |
job.reader.filter_dead_nodes | 是否在任务启动时检查并排除不可用的数据库节点。 | FALSE (引擎默认) | 在高可用环境中建议开启,以自动跳过故障节点。 |
job.reader.is_master_slave_mode | 是否为严格主备模式。 | TRUE | 若为 |
job.reader.session_properties | 为每个数据库连接设置会话级别的初始参数。 | 无 | 用于设置时区、事务隔离级别等会话环境变量。 |
job.reader.query_timeout_seconds | 单次数据库查询的超时时间(秒)。 | 300 | 大表或复杂查询场景可适当调大,避免因超时而失败。 |
job.reader.query_retry_times | 查询失败后的重试次数。 | 3 | 网络抖动频繁的环境可适当调大,增加任务稳定性。 |
job.reader.reader_fetch_size | 每次从数据库 | 5000 / 10000 | 影响内存消耗和网络 IO。调大提升吞吐,调小降低单次请求压力。 |
job.reader.reader_parallelism_num | 显式指定数据读取的并发度。 | 系统根据分片数自动计算 | 需要精细控制并发时设置,避免对源库造成过大压力。 |
job.reader.shard_split_mode | 数据分片(切分)的策略。 | accurate |
|
job.reader.split_pk | 用于数据切分的主键或索引列。 | 无 | 大表同步性能优化的关键,必须选择数值型或日期型等分布均匀的列。 |
job.reader.split_size | 在使用 | 10 | 调整此值以控制字符串类型分片键的切分粒度。 |
job.reader.filter | 在 | 无 | 用于实现增量同步或数据筛选,需注意 SQL 注入风险。 |
job.reader.customized_sql | 使用完整的自定义 SQL 代替默认的 | 无 | 适用于复杂的多表 |
job.reader.src_meta_info_column_enabled | 是否在输出中增加一列用于标识数据来源的表名。 | FALSE | 同步多张表到同一目标时,用于在下游区分数据来源。 |
下表汇总了 JDBC Sink 的核心参数,帮助您快速定位和理解其作用。
参数名 | 简要作用 | 默认值参考 | 建议调参方向 |
|---|---|---|---|
job.writer.columns | 定义需要写入目标库的列及其类型。 | 按任务配置 | 确保与源端 |
job.writer.table_pattern | 是否启用动态表名写入。 | 无 | 当需要根据上游数据内容将数据写入不同表时开启。 |
job.writer.connections | 配置目标数据库的连接信息。 | 按数据源配置 | 可配置多个连接地址以实现写入的负载均衡或高可用。 |
job.writer.write_connection_balance | 是否在多个并发写入任务间均衡分配数据库连接。 | FALSE | 多 |
job.writer.write_mode | 写入模式,如 | insert | 根据业务需求选择, |
job.writer.update_columns | 在 | 无 | 未配置此项时, |
job.writer.partition_name | 分区写入时指定的分区列名。 | 无 |
|
job.writer.delete_threshold |
| 10000 | 调小可降低单次删除对数据库的锁影响,但会增加删除次数。 |
job.writer.write_batch_size | 每批次 | 100 | 核心性能参数。调大提升吞吐,但会增加内存消耗和失败重试的成本。 |
job.writer.write_retry_times | 写入失败后的重试次数。 | 3 | 网络不稳定或数据库偶发繁忙时,适当增加可提升任务成功率。 |
job.writer.is_support_transaction | 是否启用事务写入。 | TRUE | 建议保持开启以保证数据一致性。仅在特定数据库不支持时关闭。 |
job.writer.is_process_exception_as_dirty | 批量写入失败并降级为单条写入时,是否将错误数据视为脏数据。 | FALSE | 若为 |
job.reader.columnscolumns 中只配置需要的字段,可以减少网络传输和内存消耗。columns 中添加 '常量值' as column_name 或 function(field) as new_column。column not found, schema mismatchcolumns 配置中的列名、数量、顺序是否与下游处理逻辑或目标表结构一致。特别是,如果使用了 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_)。column not found,但我确认数据库里有这个字段?job.reader.columns 配置。首先,确认列名拼写是否完全正确(包括大小写,取决于数据库);其次,如果您使用了自定义别名,请确保下游使用的是别名。最后,确认该列是否在您配置的 customized_sql 或源表中确实存在。columns 参数相关。您可以在 columns 列表中增加一项,形如 "'v1.0' as data_version"。这样,每一行数据都会带上一个名为 data_version 且值为 v1.0 的新列。columns 里写 * 和写所有列名有什么区别?* 可能会在源表结构变更时引入未知风险。columns 中的列顺序。请确保该顺序与预期一致。columns 中定义的类型需要能被正确映射。例如,数据库中的 DATETIME 类型在 columns 中应配置为正确的时间戳或字符串类型。*: 在生产环境中,强烈建议避免使用 * 来选择列,以保证数据流的稳定性和可预测性。job.reader.columns 参数是控制数据读取范围的核心配置。我们强烈建议您始终明确指定需要读取的列,这不仅能优化任务性能,还能在源表结构发生变化时保护您的数据任务不受影响。当遇到与字段相关的错误时,请第一时间检查此参数的配置是否准确。
job.reader.connectionsconnections 中配置一个或多个备库的 JDBC URL。如果配置了多个备库,可以配合 is_master_slave_mode 和 filter_dead_nodes 实现高可用读取。connection refused, connect timed out, Unknown hostconnections 中的 db_url 是否正确,包括 IP/域名、端口。同时确认网络策略(安全组、防火墙)是否允许从任务运行环境到目标数据库的访问。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),简化配置。connection refused,该怎么办?connections 参数或网络配置有关。请按以下步骤排查:1) 检查 db_url:确认 connections 中的 IP/域名和端口是否正确无误。2) 网络连通性:确认运行数据任务的计算资源与目标数据库之间的网络是通的,没有防火墙或安全组策略阻挡。3) 数据库状态:确认数据库服务本身在正常运行,且监听的地址和端口与配置一致。connections 时,只填写只读备库的 db_url 即可。如果存在多个备库,可以都填入,以实现一定程度的高可用。connections 里可以填多个数据库地址吗?有什么用?filter_dead_nodes)。2) 分库分表:在分库场景下,需要列出所有数据库分片的地址,以便任务能完整地读取所有数据。connections 配置中,产品通常会通过安全的变量替换机制来注入。rewriteBatchedStatements=true)。请确保这些必要的参数已通过 connection_parameters 或直接在 db_url 中正确配置。connections 是一个结构化的列表,请确保其 JSON 或 YAML 格式的正确性,任何格式错误都将导致任务启动失败。job.reader.connections 是数据读取的起点,它告诉任务“数据在哪里”。正确配置 db_url、用户名和密码是任务成功的第一步。在生产环境中,我们建议您利用读写分离和主备配置,将读取压力从主库转移,并通过配置多个连接地址来提升数据同步任务的可用性。
job.reader.enable_table_patternFALSEjob.reader.table_name 参数的值解释为一个正则表达式,用于在数据库中动态发现和匹配多张表。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: 一个安全限制参数。当匹配到的表的数量超过这个阈值时,任务会启动失败。这是为了防止因错误的正则表达式匹配到数据库中成百上千张无关表,造成元数据压力和潜在的数据问题。app_log_2024_01,app_log_2024_02,能用一个任务全同步了吗?enable_table_pattern 的典型应用场景。您需要将此参数设为 true,然后将 table_name 设置为 app_log_\\d{4}_\\d{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"]。这样就能实现精确控制。enable_table_pattern 是一个强大但需要谨慎使用的功能,它为同步命名有规律的多张表提供了极大的便利。当您需要处理分表场景时,请开启此参数,并始终配合 table_include_list 或 max_allowed_table_num 来限定范围,以确保任务的性能和稳定性。
job.reader.table_include_listenable_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 正则表达式所能匹配到的子集。如果一个表名无法被正则匹配,即使它在白名单里,也不会被同步。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_nodesFALSE(引擎默认值,产品侧可能有不同)connections 列表中配置的所有数据库节点进行一次可用性检查,并自动过滤(排除)那些无法成功连接的“死亡”节点。true。任务启动时会尝试连接每个节点,如果连接失败(如超时、拒绝连接),则会将该节点从本次任务的可用连接列表中移除,从而避免后续的读数据操作分配到这个故障节点上,保证任务可以继续运行。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,则主节点死亡后,任务可以继续从备库读取。filter_dead_nodes 参数设置为 true 即可。这样任务启动时会进行一轮“体检”,自动“拉黑”连接不上的节点,只用健康的节点来读数据。connections 里的地址都尝试建立一次连接。但这个耗时通常是秒级的(取决于 alive_check_timeout 和节点数量),相比于它带来的任务稳定性提升,这点开销是完全值得的。filter_dead_nodes,为什么?is_master_slave_mode 参数。如果它被设置为 true(严格主备模式),那么系统会认为主库是不可替代的,一旦主库不可用,任务就会立即失败。如果希望主库挂掉后任务能继续从备库读,需要将 is_master_slave_mode 设置为 false。SELECT 1)来完成的。请确保所用的数据库用户有执行这种基本查询的权限。alive_check_timeout 的值需要合理设置。太短可能因为网络抖动而误判节点死亡;太长则会延长任务的启动时间。默认值 30 秒通常是一个合理的选择。filter_dead_nodes 是保障 JDBC 数据读取任务高可用的重要开关。在任何具有多个数据库节点(特别是主备或集群)的环境中,我们都强烈建议您开启此功能。它能让您的数据任务从容应对节点故障、网络分区和计划内维护,显著提升整体系统的健壮性。
job.reader.is_master_slave_modeTRUEconnections 列表时的节点角色关系。它决定了当主节点(通常是列表中的第一个连接)不可用时,系统是否允许自动“故障转移”(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 是主节点,其余为备用节点。is_master_slave_mode 设置为 false。2) 确保 filter_dead_nodes 设置为 true。这样配置后,任务在启动时发现主库连不上,就会自动尝试使用您在 connections 中提供的其他备库地址。is_master_slave_mode 是在数据同步任务(客户端)层面实现的一种简单的故障切换逻辑。它不取代数据库自身的高可用机制(如 VIP、ProxySQL、MGR 等)。如果您的数据库已经有了成熟的、对应用透明的高可用方案(即应用始终连接一个虚拟 IP,后端主备切换由数据库中间件完成),那么这个参数的影响会变小。但作为一种“客户端侧”的容错增强,它依然是有价值的。false 有什么风险吗?connections 列表中,节点的顺序非常重要。当 is_master_slave_mode 为 true 时,第一个节点被铁定地视为主节点。false 模式下的逻辑也适用于“多活”或“对等节点”的读取场景,即任何一个可用节点都可以用于数据读取。is_master_slave_mode 参数是您在任务的“可用性”和“数据一致性”之间做权衡的关键。设置为 false 可以获得更高的容灾能力,让任务在主库故障时“自愈”;保持 true 则能确保数据源的绝对权威性。请根据您的业务需求,选择最适合的模式。
job.reader.session_propertiesSET 命令。这常用于设置会话级别的环境变量,如时区、事务隔离级别、SQL 模式等。session_properties 设置会话时区,例如 {"session.time_zone": "'+08:00'"},确保所有数据都在同一时区下被读取和解释。REPEATABLE READ)可能因为 MVCC 导致长时间运行的查询无法看到新提交的数据,或者在某些场景下引发锁争用。READ COMMITTED,例如 {"session.transaction_isolation": "'READ-COMMITTED'"},使得每次读取都能获取最新的已提交数据。{"session.time_zone": "'+08:00'"}{"nls_date_format": "'YYYY-MM-DD HH24:MI:SS'"}{"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 定义的每一个数据库连接上。session_properties 参数来强制指定数据读取会话所使用的时区。例如,对于 MySQL,您可以配置 {"session.time_zone": "'+08:00'"} 来确保使用东八区时间。serverTimezone=UTC)是在驱动层面、连接建立之初就生效的。而 session_properties 是在连接建立之后,通过执行 SET 命令来实现的。通常,对于会话级的动态调整,使用 session_properties 更为灵活和直观。session_properties 中的 Key(变量名)和 Value(值)的语法是数据库特定的。请参考您所使用的数据库(MySQL, Oracle, PostgreSQL 等)的官方文档来获取正确的变量名和值格式。SET 命令的用户需要有修改相应会话变量的权限。SET 命令,虽然开销很小,但如果连接非常频繁地断开和重连,也可能带来微小的性能影响。session_properties 为您提供了一个标准化的方式来“定制”数据读取时的数据库会话环境。当您遇到跨时区的时间偏差、需要调整事务隔离级别或设置特定于数据库的会话变量时,这个参数是您的首选工具。
job.reader.query_timeout_seconds300Statement.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。query_timeout_seconds 调得非常大就好了?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_times3connection 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 行为: 每次重试前,连接器通常会尝试关闭旧的、可能已损坏的连接,并建立一个全新的数据库连接,以最大程度保证重试的成功率。query_retry_times 的值。这样,当遇到网络抖动时,任务会自己多尝试几次,很可能在网络恢复后就成功了,从而避免了整个任务的失败和重启。SELECT 查询是幂等的,即多次执行不会产生副作用。对于数据读取任务来说,这通常是成立的。query_retry_times 是数据同步任务的“耐心”。通过设置合理的重试次数,您的任务将能够优雅地处理网络抖动和数据库的短暂繁忙,变得更加健壮。对于大多数场景,默认的 3 次重试是一个很好的起点。
job.reader.reader_fetch_sizereader_fetch_size。通过一次性获取更多的数据行,可以有效减少网络往返(Round Trip)的次数,从而将更多时间用于数据传输本身,而不是等待网络延迟,进而提升整体吞吐。OutOfMemoryError)而失败,特别是在处理含有大字段(如 TEXT, BLOB)的表时。reader_fetch_size。这会减少 JDBC 驱动在客户端内存中缓冲的数据量,从而有效降低内存峰值。reader_fetch_size,将大的数据拉取请求分解为多次小的请求,使数据库负载更平滑。reader_fetch_size 适当调大,例如 20000 或 50000。这通常能带来明显的吞吐提升。1000 或 500,以空间换时间。5000 到 10000 是一个适用于多种场景的均衡值,在大多数情况下无需调整。split_pk: reader_fetch_size 作用于每个分片(split)内部。即使你通过 split_pk 将大查询分片,每个小查询依然受 fetch_size 的影响。fetch_size 而不增加任务内存,是导致 OOM 的常见原因。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_numshard_parallelism_ratio 自动计算)reader_parallelism_num。例如,无论系统计算出多少并发,都强制将其限制在一个较低的水平,如 5 或 10,以保护源数据库。reader_parallelism_num,以启动更多的并行读取任务,从而加快数据同步速度。reader_parallelism_num 值。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 将会失效。parallelism.default / max_parallelism: reader_parallelism_num 的值会受到 Flink 层面最大并发度的限制。您设置的值不能超过 Flink 作业的 max_parallelism。job.reader.split_pk: 并发读取的有效性依赖于合理的数据分片。如果未使用 split_pk 导致数据无法切分,那么即使设置了很高的并发度,也可能只有一个任务在工作。reader_parallelism_num 调大就可以了吗?split_pk 等方式对数据进行了有效的分片。如果数据本身没有被切分成多个块,那么再多的并发实例也只会“一拥而上”去读同一块数据,无法实现并行处理。因此,正确的顺序是:先做好分片(split_pk),再考虑提升并发(reader_parallelism_num)。max_connections)以应对。reader_parallelism_num 是您用来精细调控数据读取“火力”的开关。大多数情况下,您可以信赖系统的自动调节能力。但在需要保护敏感数据库,或希望榨干系统性能时,通过显式设置此参数,您可以获得对任务行为更强的掌控力。请记住,并行处理的威力,源于有效的数据分片。
job.reader.shard_split_modeaccuratesplit_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: 分片最终会被分配给并发的读取任务。分片的数量和范围,会直接影响每个并行实例的工作负载。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_pksplit_pk。连接器会利用这个列,将整个表的数据范围切分成多个小的数据块(splits),然后将这些小块分配给多个并行的读取任务,实现“众人拾柴火焰高”的效果。SELECT 查询因为一次性要处理的数据太多,导致数据库长时间高负载,甚至超时。split_pk,原始的 SELECT * FROM big_table 会被自动改造成一系列带有 WHERE split_pk >= ? AND split_pk < ? 条件的子查询。每个子查询只处理一小部分数据,从而大大降低了对数据库的单次压力。split_pk 列必须有索引,最好是主键或唯一索引。否则,为了获取分片边界(计算MIN/MAX)和执行范围查询,数据库将进行全表扫描,性能会急剧恶化。INT, BIGINT)、日期/时间类型(DATE, DATETIME, TIMESTAMP)是最佳选择,因为它们的线性、可比较且分布通常较为均匀。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 类型。虽然连接器会尝试自动推断,但在某些模糊的情况下(如特定数据库的自定义类型),显式指定可以避免错误。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(逗号分隔),但通常只会使用第一个有效的。split_pk 列中包含 NULL 值,您可能需要额外关注 support_null_split_key 参数的配置,以确保 NULL 值记录也能被正确读取。split_pk 的选择至关重要。如果选择的列数据分布严重不均(例如,一个状态字段,99% 的值都是 'active'),会导致大部分并发任务无所事事,只有一个任务在处理那 99% 的数据,并行效果将大打折扣。split_pk 是撬动大数据同步性能的杠杆。对于所有大表的读取任务,正确地配置此参数都是实现高性能、高效率同步的第一步,也是最重要的一步。请务必选择一个带有索引且值分布均匀的数值或日期类型列作为您的分片键。
job.reader.filterSELECT 语句的 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 中完全控制了。filter 参数,并配合系统提供的调度变量。具体语法可能因您使用的平台而异,但思路是类似的,例如:"gmt_create >= bizdate_add('${bizdate}', -1) AND gmt_create < '${bizdate}'"。filter 里可以写很复杂的 SQL 吗?WHERE 子句的一部分,不能包含 ORDER BY, GROUP BY 等。2) 过于复杂的条件可能导致数据库无法有效使用索引,从而影响查询性能。3) 如果逻辑非常复杂,甚至需要多表 JOIN,那么更推荐使用 customized_sql 参数。filter 之后查询变慢了,怎么办?filter 中涉及的列是否有索引。如果在一个没有索引的列上进行过滤,数据库很可能会进行全表扫描,导致性能急剧下降。请联系 DBA 为过滤列添加索引。filter 的内容是直接拼接到 SQL 语句中的。请绝对不要将来自外部的、不可信的用户输入拼接到 filter 字符串中,否则会存在严重的安全风险。请仅使用系统提供的、受信任的调度变量。filter 的内容用括号包裹起来,以保证 AND / OR 逻辑的优先级正确。您在编写 filter 内容时,一般无需自行在最外层添加括号。filter 参数为您在数据源头进行筛选提供了强大的能力。它是实现增量同步、过滤无效数据、定点补录的核心工具。在使用时,请务- 必保证过滤条件所涉及的列建立了索引,并注意防范 SQL 注入风险,以实现高效、安全的数据读取。
job.reader.customized_sqlSELECT SQL 语句来代替连接器默认生成的查询。一旦配置了此参数,连接器将放弃所有关于表名、列名、filter 的自动拼接逻辑,完全以您提供的 SQL 为准。JOIN 才能获取完整的记录。customized_sql 中编写完整的 SELECT ... FROM table_a JOIN table_b ON ... 语句。GROUP BY 聚合,或者使用窗口函数、复杂的 CASE WHEN 表达式等。customized_sql。customized_sql 中自由地使用这些高级 SQL 特性。customized_sql。对于简单的单表查询,使用默认方式更简单、更安全。customized_sql 中 SELECT 的列(包括别名和顺序)必须与 job.reader.columns 中定义的完全一致,否则任务在读取数据时会因结构不匹配而失败。${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 子句中。customized_sql 之后,任务变得特别慢,而且只有一个并发在跑,为什么?customized_sql 的核心限制。因为连接器无法理解您的复杂 SQL 并对其进行安全的自动切分,所以所有与 split_pk 相关的数据分片和并行读取机制都会被禁用。您的整个 SQL 语句只能作为一个整体,由一个并发任务来执行。customized_sql 不能并行,那如果我想对一个复杂查询的结果进行并行读取,有办法吗?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_enabledFALSEenable_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: 此功能最常与动态表发现功能一起使用,是其重要的配套能力。src_meta_info_column_enabled 就是为此而生的。它会为您的每一行数据都打上“出生地”的标签(即来源表名)。数据同步完成后,您只需要在目标大表里对这个来源表名列进行 GROUP BY 和 COUNT(*),就可以轻松统计出每个原始分表的行数了。job.reader.columns 中声明了这一列。2) 在下游的目标表中,也实际存在一个用于存储这个来源表名的字段(通常是 VARCHAR 类型)。orders_202401。src_meta_info_column_name 的值必须与 columns 列表中的某一个列名完全匹配。src_meta_info_column_enabled 是一个“小开关,大作用”的参数。在任何多表同步的场景下,它都能像GPS一样,为您的每一条数据精准定位其来源,是提升数据血缘清晰度和后续运维、分析效率的利器。我们强烈建议您在所有适用的场景中都开启它。
job.writer.columnsPreparedStatement 的参数上。Column count doesn't match, Cannot find column, Data truncation, Type mismatchjob.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 列表中。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_patternregion_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,任务会跳过该行数据,并继续处理下一行。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.connectionsconnections 列表中只配置一个 db_url。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 来开启批量写入优化。connection refused,应该检查哪里?job.writer.connections 中的 db_url。确认 IP/域名、端口是否正确,并检查网络防火墙或安全组是否允许从任务运行环境到目标数据库的访问。connections 里可以填多个地址吗?如果第一个地址挂了,会自动用第二个吗?write_connection_balance 的设置和连接器的具体实现。当 write_connection_balance=true 时,不同的并发任务会连接到不同的地址,如果某个任务分配到的地址挂了,该任务会失败,但其他任务不受影响。连接器在初始化连接时也会做可用性检测,可能会跳过不可用的 URL。这种机制提供了一定程度的容错,但它不完全等同于一个全功能的、自动故障转移的 HA 方案。connections 的 URL 中包含了 rewriteBatchedStatements=true。大多数情况下,连接器会自动为您添加,但了解这一点总是有益的。job.writer.connections 指明了数据写入的“目的地”。正确配置它是任务成功的基础。对于需要分散写入压力的场景,您可以通过配置多个连接地址并开启 write_connection_balance 来实现简单的写入负载均衡。
job.writer.write_connection_balanceFALSEjob.writer.connections 列表中配置了多个数据库连接 (db_url) 时,此参数决定了这些连接如何在多个并发的写入任务(task)之间进行分配。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,此参数不起任何作用。connections 里配了3个数据库地址,但从监控看,压力都在第一台机器上,为什么?write_connection_balance 设置为 true。在默认的 false 状态下,即使您提供了多个地址,所有任务也只会使用第一个。请将其设置为 true 以启用连接的均衡分配。write_connection_balance=true 时,如果某个并发任务分配到的数据库节点正好是故障节点,那么这个并发任务在尝试连接时会失败,并可能导致其自身不断重试或最终失败。这可能会影响整个数据同步任务的进度,但不会影响那些连接到健康节点的其他并发任务。连接器在分配连接时通常也会做可用性检测,可能会主动跳过已知的坏节点。write_connection_balance 是您在多连接配置下,决定“雨露均沾”还是“独宠一人”的关键开关。当您希望将写入压力分散到多个数据库节点时,请将它设置为 true;当您需要确保所有写入都 строго地指向主节点时,请保持其默认的 false 状态。
job.writer.write_modeinsertinsert:
partition_name 和 partition_value 生成 DELETE 语句,清空目标表中对应分区的数据。然后,再将新数据以 INSERT 的方式写入。overwrite:
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 模式的行为都依赖于目标表上存在主键或唯一索引来判断“冲突”。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_columnswrite_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 增加新字段时,该新字段被意外地加入到更新列表中。job.writer.write_mode: update_columns 只在 write_mode = 'overwrite' 时生效。job.writer.columns: update_columns 中列出的所有字段,必须是 job.writer.columns 的子集。overwrite 模式和 update_columns 的行为,完全依赖于目标表上存在主键或唯一索引来触发“冲突(DUPLICATE KEY)”逻辑。overwrite 模式时,是不是所有字段都会被更新?update_columns。如果您没有配置它,那么默认行为是更新所有非主键/唯一键的字段。如果您配置了它,那么只有列表中指定的字段才会被更新。price 和 stock 字段,怎么做?update_columns 中进行如下配置:["price", "stock"]。update_columns 只是一个列名的列表,不支持在其中使用表达式,例如 count = count + 1。这种逻辑需要数据库层面的触发器或在数据ETL过程中提前处理。update_columns 是您在进行“插入或更新”(Upsert)操作时的精细控制器。通过它,您可以精确地指定哪些字段需要“与时俱进”,哪些字段应该“保持初心”。为了获得最佳性能和最明确的业务意图,我们建议您始终明确配置需要更新的列。
job.writer.partition_namewrite_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 列表中,因为连接器需要从数据行中读取该列的值。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 指定的列在目标数据库表中真实存在。partition_name。partition_name 是您在进行分区级数据覆盖或管理时,用于定位目标的“坐标轴”。当您使用 insert 或 dynamic 写入模式时,请务必正确设置此参数,以确保清理和写入操作能够精确地作用于您指定的数据范围。
job.writer.write_batch_size(别名: job.writer.write_batch_interval)100executeBatch)。这是影响写入性能的最核心参数之一。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,也会强制触发一次提交。这为低流量场景提供了延迟保障。write_batch_size 调得越大越好?batch_size 可以显著提升吞吐,但当它大到一定程度后,性能收益会减少,而内存消耗和失败时的重试代价会持续增加。过大的批次还可能触及数据库的各种限制(如最大查询长度、事务日志大小等)。最佳实践是通过逐步增大此值并进行压测,找到性能曲线的“拐点”。write_batch_size 设置得比较大,而数据流量太小,迟迟“凑不够”一个批次。您可以尝试调小 write_batch_size,或者检查 flush_interval_ms(流式场景)是否设置了一个合理的值,以保证低流量下的数据也能被及时提交。rewriteBatchedStatements=true,否则 executeBatch 可能会退化为循环单条插入,失去批量优化的意义。write_batch_size 是您手中最锋利的写入性能调优工具。在高流量、追求极致吞吐的场景下,请不要吝啬,大胆地增加它;在低流量、追求实时响应的场景下,请毫不犹豫地减小它。通过在这个“吞吐”与“延迟”的跷跷板上找到最佳平衡点,您的数据写入任务将能游刃有余地应对各种业务需求。
job.writer.write_retry_times3write_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,则任务直接失败。overwrite (Upsert) 和 replace 模式天然是幂等的,多次执行同一批数据的结果是一样的。insert 模式在有 DELETE 前置操作时,如果重试的是整个“先删后写”的批次,也是幂等的。但如果是在降级为单条写入后重试,可能会引入重复数据(如果事务被关闭)。write_batch_size 的同时,需要审慎评估重试策略。job.writer.write_retry_times 是您数据写入任务的“复活甲”。它让任务在面对数据库的瞬时风波时,拥有了“再试一次”的勇气和能力。合理配置重试次数,可以在不牺牲太多时间的情况下,显著提升任务在复杂生产环境中的稳定性和最终成功率。
job.writer.is_support_transactionTRUEwrite_batch_size 定义)都会被包裹在一个事务中,要么全部成功(commit),要么全部失败(rollback),从而保证了单批数据的原子性。is_support_transaction 为 true。这是保证数据一致性的最基本要求。is_support_transaction 设置为 false。这会关闭事务,连接将以 auto-commit 模式运行,每条 SQL 语句执行后都会立即提交。is_support_transaction=true。这是保证数据一致性的生命线。job.writer.write_batch_size: 当事务开启时,write_batch_size 定义了单个事务内包含的 SQL 语句数量。exactly-once 或 at-least-once。在 Flink 的两阶段提交协议中,JDBC Sink 的事务扮演了关键角色。关闭事务会严重影响端到端的一致性保证。exactly-once 语义,可能导致在任务从 checkpoint 恢复时出现数据重复。is_support_transaction 设为 false 来绕过这个问题,但这会牺牲一致性。更根本的解决方案是检查您的数据库配置或 JDBC 驱动版本,看是否可以调整以更好地支持分布式事务。is_support_transaction 初始为 true。is_support_transaction 是数据写入的“安全网”,它通过事务机制保障了每批数据的“同生共死”,是数据一致性的基石。我们强烈建议您始终保持其开启状态。只有在遇到无法规避的、特定于数据库的事务兼容性问题,且业务可以容忍其风险时,才应考虑将其关闭。
job.writer.is_process_exception_as_dirtyFALSEis_process_exception_as_dirty 设置为 true。这样,在单条写入模式下失败的数据行会被捕获,并作为“脏数据”进行上报或记录(如果配置了脏数据收集机制),而任务本身会继续处理后续的正常数据。is_process_exception_as_dirty 为 false。在这种模式下,一旦在单条写入模式下有任何一行数据失败,整个任务就会立即抛出异常并失败。true,配合脏数据收集机制,可以大大提升任务的健壮性。false,确保任何问题都能在第一时间被发现。job.writer.write_retry_times: 脏数据处理逻辑是在批量写入和重试都失败后,进入单条写入模式时才会被触发的。true 可能仅仅意味着“悄无声息地丢弃了坏数据”。is_process_exception_as_dirty 设置为 true 就能实现这个效果。它会让任务在遇到无法写入的单条数据时,选择“记录并放行”,而不是“原地引爆”。true 可能会导致数据在您不知情的情况下被“丢弃”。请务必确认您的平台支持对“脏数据”的后续处理。is_process_exception_as_dirty 是您在任务的“健壮性”与“严格性”之间做选择的开关。将它设为 true,您的任务将变得“心胸宽广”,能够容忍少数害群之马,适合大规模、数据质量参差不齐的场景。保持 false,则任务会成为一个“铁面无私的法官”,任何瑕疵都将导致流程中止,适合对数据质量要求零容忍的场景。
jdbc.properties.* jdbc.properties.*jdbc.properties.*:按 key=value 方式逐项传入 JDBC 连接属性useSSLtrue / falsesslModeDISABLED、PREFERRED、REQUIRED、VERIFY_CA、VERIFY_IDENTITYverifyServerCertificatetrustCertificateKeyStoreUrltrustCertificateKeyStorePasswordtrustCertificateKeyStoreTypeJKS、PKCS12。clientCertificateKeyStoreUrlclientCertificateKeyStorePasswordclientCertificateKeyStoreTypeenabledTLSProtocolsTLSv1.2,TLSv1.3。connectTimeoutsocketTimeoutautoReconnectallowPublicKeyRetrievalserverTimezonezeroDateTimeBehaviorconvertToNull。useUnicodecharacterEncodingutf-8、utf8。rewriteBatchedStatementsuseServerPrepStmtscachePrepStmtsprepStmtCacheSizeprepStmtCacheSqlLimituseSSLsslModeuseSSL=truesslMode=REQUIREDVERIFY_CA 或 VERIFY_IDENTITY。timeout、timed outconnectTimeoutsocketTimeoutallowPublicKeyRetrievaluseSSLsslModeallowPublicKeyRetrieval=true。useUnicodecharacterEncodinguseUnicode=truecharacterEncoding=utf-8rewriteBatchedStatementsrewriteBatchedStatements=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 + sslModeuseUnicode + characterEncodingconnectTimeout + socketTimeoutrewriteBatchedStatements + 批量写入参数
sslMode + 证书库参数
VERIFY_CA / VERIFY_IDENTITY,通常还要配证书相关参数。jdbc.properties.* 和 url.properties 用哪个更好?
jdbc.properties.*。url.properties。sslMode=REQUIRED 和 useSSL=true 是不是重复?
sslMode 和老式 requireSSL、verifyServerCertificate。jdbc.properties.* 与 url.properties 都用于为 JDBC 连接补充扩展属性,常见可配置项包括 SSL 加密、超时、字符编码、批量写优化和驱动兼容参数。
jdbc.properties.*,可读性更好;url.properties 更适合集中承载。对 MySQL 场景,常见优先关注的子参数包括 useSSL、sslMode、connectTimeout、socketTimeout、characterEncoding、rewriteBatchedStatements 和 allowPublicKeyRetrieval,并建议按安全、兼容、性能三类目标分组调优。