DLC 原生表常见 FAQ

最近更新时间:2025-08-19 11:22:42

我的收藏

为什么 Upsert 写入的 DLC 原生表(Iceberg)一定要开启数据优化?

1. DLC 原生表(Iceberg)采用的 MOR(Merge On Read)表,上游 Upsert 写入时,针对 update 的数据,会先写 delete file 标记某记录已经被删除,然后再写 data file 新增改记录。
2. 如果不提交进行合并,作业引擎在读取数据时,需要将读取原来的数据,该记录的 delete file 和新增的 data file,将三者进行合并得到最新的数据,这会导致作业需要大量的资源和时间来进行。数据优化中的小文件合并是提前将上述的文件读取回来合并,并写成新的 data file,使得作业引擎不用再进行数据文件合并而直接读取最新的文件。
3. DLC 元数据(Iceberg)采用了的快照机制,写入流程中即便是产生了新的快照也不会将历史快照清理,这依赖于数据优化的快照过期能力,将产生时间较久远的快照过期移除,从而达到释放存储空间效果,避免无用的历史数据占用存储空间。

数据优化任务出现执行超时的任务怎么处理?

系统针对数据优化任务默认设置运行超时时间(默认2小时),避免某个任务长时间占用资源而导致其他任务无法执行,当超时时间到期时该优化任务会被系统取消,根据任务类型的不同,可参考如下流程处理。
1. 如果是小文件合并任务超时,当出现连续多次超时识别的,则是数据存在了堆积,当前资源已经无法满足该表的合并,则可以临时扩展资源(或者设置该表只有优化资源为独立的资源),将历史堆积数据处理完毕后再设置回来。
2. 如果是小文件合并任务,偶尔出现任务执行超时,则是治理资源有些不足,可以适当地对数据资源扩容,并持续观察后续多个周期的治理任务是否还存在超时。当某些表偶尔出现小文件合并超时,短期内并不会对查询性能造成影响,但是不处理可能会发展为连续超时失败,到达该阶段后将影响查询性能。 DLC 默认针对小文件合并开启了分段提交,当执行超时,已经完成的部分任务仍然有机会提交成功,提交成功的合并仍然有效。
3. 如果是快照过期执行超时,快照过期执行分为两个阶段,第一个阶段从元数据中移除快照,该过程执行快照,通常不会在该阶段超时,第二个阶段将被移除快照的数据文件从存储上删除,该阶段需要逐一比较删除文件,当待删除的文件较多时,可能会出现超时。该类型的任务超时可以忽略,任务超时被移除的文件在系统会被当做孤立文件而被后续的移除孤立文件清理。
4. 如果是移除孤立文件执行超时,本次执行的结果仍然是有效的,可能只移除了部分孤立文件。由于移除孤立文件是周期性地扫描执行,当本次任务超时后未被成功删除的孤立文件,后续的周期会继续扫描到被移除。

为什么 Iceberg 在 insert 写完数据后会偶尔在极短的时间内读到旧的快照?

1. Iceberg 提供了默认缓存 Catalog 的能力,默认30秒,极端情况下如果两次查询相同表间隔特别短且不在同一个 session 中执行时,在缓存没有过期和获取更新之前,有极低的概率将会查询到上一个旧快照。
2. 该参数 Iceberg 社区建议开启,DLC 在早期版本也是默认开启,该参数是为了加速任务执行,减少查询过程中对元数据的访问。 但是在极端情况下,如果两个任务读写间隔特别近,可能会出现上述描述的情况。
3. DLC 在新版本的引擎中已经默认关闭,在结合用户场景,用户在2024年1月份之前购买的引擎如果用户需要保证数据查询到强一致,可通过如下手动关闭该参数,配置方法参考,修改引擎参数:
"spark.sql.catalog.DataLakeCatalog.cache-enabled": "false" "spark.sql.catalog.DataLakeCatalog.cache.expiration-interval-ms": "0"

为什么建议 DLC 原生表(Iceberg)需要进行分区?

1. 数据优化首先按照分区进行 job 划分,如果原生表(Iceberg)没有分区,大多数情况会改表的小文件合并都只有一个 job 执行,无法并行合并,很大程度降低小文件合并效率。
2. 如果表上游无分区字段,如何分区呢?此时可考虑 Iceberg 的 bucket 分桶,详细描述请参见 原生表(Iceberg)格式说明

为什么 Upsert 流式写入的表在进行分区字段变更时需要重启 Flink/Inlong 导入任务?

Upsert 写入场景,当 Iceberg 表的分区配置发生变化后,如果导入任务没有重启,导入任务无法感知分区的变更,仍然按照老的分区配置写入数据,而离线写入/小文件合并任务将按照表上最新的分区配置写入数据,这会造成导入任务产生的 Equality Delete File 无法正确删除离线/小文件合并任务产生的数据,最终导致出现重复 upsert 键的数据。当需要修改表上的分区时,需要按照如下步骤进行:
1. 停止当前的导入任务。
2. 确定当前的最新的Delete File已经全部合并,用户可手动执行一次 rewrite all 确保全部执行,合并 SQL 参考:
CALL `DataLakeCatalog`.`system`.`rewrite_data_files`(
`table` => 'test_db.test_tb',
`options` => map(
'rewrite-all',
'true',
'max-concurrent-file-group-rewrites', --根据实际资源情况而定,并发度越高,采用的资源越多,文件合并越快
'5',
'partial-progress.enabled',
'true',
'partial-progress.max-commits',
'10'
)
)
3. 修改表分区字段。
4. 启动导入任务。

DLC 原生表(Iceberg)写冲突如何处理?

1. Iceberg 为保证 ACID,在 commit 时要检查当前的视图是否有变化,如果有变化则判断为发生了冲突,之后回退到 commit 操作,合并当前视图,然后重新提交。
2. 系统提供了默认的冲突重试次数和时间,当发生多次 commit 操作还是发生了冲突,则将写入失败。默认冲突参数请参见 原生表(Iceberg)格式说明
3. 当冲突发生了,用户可以调整重试次数和重试时间。如下示例将冲突重试次数调整为10次,更多的参数含义请参见 原生表(Iceberg)格式说明
// 修改冲突重试次数为10

ALTER TABLE `DataLakeCatalog`.`axitest`.`upsert_case` SET TBLPROPERTIES('commit.retry.num-retries' = '10');

DLC 原生表(Iceberg)已经删除了,为什么存储空间容量还没有释放?

DLC 原生表(Iceberg)drop table 时元数据立即删除,数据是异步删除,先是将数据移动到回收站目录,延迟一天后数据才会从存储上移除。

DLC 原生表(Iceberg)对使用 iceberg days 等时间类型的隐式分区的场景,使用 insert overwrite 进行动态分区覆盖,会导致丢失部分数据,怎么处理?

Iceberg 隐式分区 day/hour/month,内核会默认当做 UTC 时间作隐私转换,因此如果上层计算引擎的时区不是按照 UTC 区传入的时间数据,iceberg 将可能导致数据写错分区。参考 Iceberg 社区 Issue
建议解决方案:
1. Spark 3.2 版本,将 spark 的时区设置为 UTC 时区,spark.sql.session.timeZone=UTC。
2. Spark 3.5版本,建表语句指定需要 Iceberg 进行隐式转换的时间字段格式为 timestamp_ntz。