: write-only 救活写入后,Paimon 查询为什么一周比一周慢)
晚高峰期间订单入湖 Writer 的 Checkpoint 频繁卡在 Compaction。运维把表改成write-onlytrue超时几乎立刻消失监控重新变绿大家以为问题已经解决。一周后Spark 查询扫描的文件数翻了数倍流读恢复也越来越慢。参数没有失效它只是把 Compaction 从 Writer 的工作清单里删掉了而团队没有安排新的作业把这项工作接走。write-only关闭的是 Writer 内 Compaction不是 Paimon 对 Compaction 的需要没有独立作业合并债会原样留在表里。下文的write-only与 Compaction 行为固定在Apache Paimon 2.0.0源码基线为release-2.0.0/604e6d5e...。write-only 不是性能魔法它只是一次责任转交Dedicated Compaction 官方文档 给出的设计是Writer 设置write-onlytrue持续写入再由单独的 Compaction 作业合并。这样可以减少多 Writer 删除同一文件造成的冲突也避免同步 Compaction 阻塞写入。默认Writer 写文件 触发 Compaction 提交 write-onlyWriter 写文件 提交 Compaction Job 选择文件 重写 提交只执行上半行就等于取消垃圾清运后庆祝写入更快。为什么 lookup 与 Deletion Vector 更怕“无人接班”changelog-producerlookup默认在 Compaction 中生成完整 Changelogwrite-only会使 Writer 不再完成这部分工作。Deletion Vector 模式的 L0 文件也依赖 Compaction 才能可见。此时独立 Compaction 作业不是单纯的性能优化而可能进入数据新鲜度或下游正确性链路。别先启动新作业先用三组只读证据确认现状SELECT*FROMorders$options;SELECT*FROMorders$files;SELECTsnapshot_id,commit_kind,commit_timeFROMorders$snapshotsORDERBYsnapshot_idDESC;表是否真的启用了write-only最近是否仍有COMPACT类型 Snapshot每个 Bucket 的 L0/Sorted Run 是否持续增长。再检查独立 Compaction 作业是否存在、是否覆盖目标数据库与表、是否因分区过滤遗漏活跃分区。Writer 变稳不能证明 Compaction 作业健康。真正的修复不是打开开关而是建立双作业 SLO先启动并验证专用 Compaction再灰度启用write-only。至少监控最老未合并文件年龄、每 Bucket 文件数、Compaction 提交间隔、读取扫描文件数、Writer 与 Compaction Checkpoint P99。回滚也不是简单把write-onlyfalse。若已积累大量债务Writer 重新接管可能在首轮同步 Compaction 中超时。应先由独立作业把积压降到可控范围再逐表切回并观察资源争用。建议把责任交接做成可验收门禁阶段WriterCompaction Job成功证据切换前正常写并合并未接管基线文件与延迟已保存灰度单表write-only仅覆盖该表持续出现 COMPACT Snapshot稳态写入与提交选择、重写、提交最老未合并文件年龄不增长回滚逐表恢复合并继续偿还积压Writer 首轮合并不超时Dedicated Compaction 的启动参数和表过滤属于变更项文章不授权在生产直接执行。上线前要保留 Savepoint、当前 Snapshot ID 和配置快照若 L0 可见延迟超过 SLO、Lookup Changelog 中断或积压继续增长应停止扩大灰度。固定源码中的NoopCompactManager可以解释write-only为什么不再由 Writer 选取合并任务真正的文件重写仍由独立 Compaction 链完成。这个证据证明责任被移走不证明接管作业健康。write-only能隔离前台写入和后台整理但隔离从来不等于后台工作可以消失。用 Java 设置接管门禁没有 COMPACT 提交就不能算成功固定版本源码如何转移 Compaction 责任源码固定为release-2.0.0/604e6d5e...。paimon-core/src/main/java/org/apache/paimon/compact/NoopCompactManager.java的triggerCompaction()不提交任务getCompactionResult()也不会返回重写结果正常合并路径则进入paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManager.java的triggerCompaction()。对应源码NoopCompactManager、MergeTreeCompactManager。write-onlytrue让 Writer 走“不选合并任务”的效果Java 因而把最近是否出现COMPACTSnapshot 设为接管门禁。它能发现独立 Compaction 没工作不能仅凭一次COMPACT就证明积压已经清完。以下只读程序按paimon-flink-1.20:2.0.0API 编写args[0]为 Warehouse本环境未运行全文示例。importorg.apache.flink.table.api.EnvironmentSettings;importorg.apache.flink.table.api.TableEnvironment;importorg.apache.flink.table.api.TableResult;importorg.apache.flink.types.Row;importorg.apache.flink.util.CloseableIterator;publicfinalclassDedicatedCompactionGuard{publicstaticvoidmain(String[]args)throwsException{if(args.length!1)thrownewIllegalArgumentException(warehouse is required);Stringwarehouseargs[0].replace(,);TableEnvironmenttTableEnvironment.create(EnvironmentSettings.newInstance().inBatchMode().build());t.executeSql(CREATE CATALOG p WITH (typepaimon,warehousewarehouse));t.executeSql(USE CATALOG p);TableResultsnapshotst.executeSql(SELECT snapshot_id,commit_kind,commit_time FROM demo.orders$snapshots ORDER BY snapshot_id DESC LIMIT 30);booleancompactSeenfalse;try(CloseableIteratorRowrowssnapshots.collect()){while(rows.hasNext()){Rowrowrows.next();System.out.println(row);compactSeen|COMPACT.equalsIgnoreCase(String.valueOf(row.getField(1)));}}t.executeSql(SELECT bucket,COUNT(*) files FROM demo.orders$files GROUP BY bucket ORDER BY files DESC).print();if(!compactSeen){thrownewIllegalStateException(no COMPACT snapshot in the latest 30 commits; dedicated compaction is not proven);}System.out.println(PASS: dedicated compaction has produced a recent COMPACT snapshot);}}启用write-only后 Writer 使用不调度合并的路径可对应到NoopCompactManager独立作业必须重新产生 COMPACT Snapshot。只有 APPEND 且文件数持续增加就是接管失败信号不能因 Writer Checkpoint 变快而放行。write-only 能救一次 Checkpoint却不能替团队偿还 Compaction 债没有接管人恢复的写入只是把故障从今天搬到了下周的查询。如果 Dedicated Compaction 已经在运行Checkpoint P99 仍持续上升应继续按最热 Bucket 与最慢 Subtask 的时间线排查而不是再次打开或关闭write-only。官方资料Dedicated CompactionPrimary Key Table CompactionChangelog ProducerTable Mode