资讯动态

Opik traces 表 DDL 迁移规范:在 cutover 双拓扑窗口内安全修改 ClickHouse traces schema

发布时间:2026/9/13 18:36:44 来源:尧图企业网站定制
Opik traces 表 DDL 迁移规范在 cutover 双拓扑窗口内安全修改 ClickHouse traces schema【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm本文是 traces-schema-ddl.md 的深度展开。Opik 的traces物理层正处在向「分区 可分片」继任表迁移的过渡期同一份 Liquibase changelog 必须同时兼容 pre-cutoverReplicatedReplacingMergeTree与 post-cutoverDistributed包装 traces_local分片两套物理布局而写错的后果是静默的——迁移时零报错随后表现为读失败或数据静默丢失。读完本文你将掌握两种拓扑的精确差异、schema 不变式的三层含义、双分支双 changeset 的标准模式、backfill 列清单与类型转换义务以及四道 CI 门禁如何把每一次失误挡在合并之前。背景为什么一份 changelog 必须同时对两套物理布局正确Opik 的 trace 数据链路正经历一次重大物理层重构live 的、未分区的traces表ReplicatedReplacingMergeTree将被迁移到每周分区、去 Nullable、为is_deleted就绪的继任表traces_local_v2并最终包装成面向分片就绪的Distributed表。这一迁移cutover由操作员 runbook驱动而不是由 Liquibase 执行——完整流程见>--changeset opik:000123_add_foo_to_traces_pre_cutover --comment: Pre-cutover branch — traces is the live MergeTree and traces_local_v2 is the shadow; apply to both --preconditions onFail:MARK_RAN onError:HALT --precondition-sql-check expectedResult:0 SELECT count() FROM system.tables WHERE database ${ANALYTICS_DB_DATABASE_NAME} AND name traces_local ALTER TABLE ${ANALYTICS_DB_DATABASE_NAME}.traces ON CLUSTER {cluster} ADD COLUMN IF NOT EXISTS foo String DEFAULT ; ALTER TABLE ${ANALYTICS_DB_DATABASE_NAME}.traces_local_v2 ON CLUSTER {cluster} ADD COLUMN IF NOT EXISTS foo String DEFAULT ; --changeset opik:000123_add_foo_to_traces_post_cutover --comment: Post-cutover branch — traces is the Distributed wrapper over traces_local --preconditions onFail:MARK_RAN onError:HALT --precondition-sql-check expectedResult:1 SELECT count() FROM system.tables WHERE database ${ANALYTICS_DB_DATABASE_NAME} AND name traces_local ALTER TABLE ${ANALYTICS_DB_DATABASE_NAME}.traces_local ON CLUSTER {cluster} ADD COLUMN IF NOT EXISTS foo String DEFAULT ; ALTER TABLE ${ANALYTICS_DB_DATABASE_NAME}.traces ON CLUSTER {cluster} ADD COLUMN IF NOT EXISTS foo String DEFAULT ;参考夹具中每个分支都带--rollback语句DROP COLUMN IF EXISTS/DROP INDEX IF EXISTS同样ON CLUSTER这是 shipped 迁移的既有约定。五个承重细节sqlCheck针对system.tables而非tableExists。守卫必须读取运行时拓扑——Liquibase 自身的记账无法告诉你操作员是否跑过 cutover。参考夹具的注释写得很直白guard branch 由一次本地system.tables读取选择。onFail:MARK_RAN。被跳过的分支被记录为「已应用但未执行」于是后续启动永远不会在错误的拓扑上重试它。liquibase-clickhouse0.7.2 遵守该语义门禁断言它——版本升级若破坏这一点会先挂 CI 而非生产。onError:HALT。若前置条件本身无法评估就停下来——不要猜测拓扑。ON CLUSTER {cluster}出现在每条语句上。缺失时 DDL 只到达 Liquibase 连接的那个节点其余副本缺列而 changeset 已记为应用。在此处还会叠加守卫从本地system.tables读取评估因此被非集群 DDL 弄出分歧的集群可能一个节点为另一节点不存在的拓扑记录MARK_RAN。处处IF [NOT] EXISTS。使重跑、部分应用的分支、以及从任一侧到达的安装幂等。两个常规场景与一个罕见场景Case 1 —— 一个字段读向变更。两个分支每个分支内两张表。若它是保留型而非派生型还要把它加入 backfill 列清单。Case 2 —— 一个索引存储专用变更。pre-cutover 两张表post-cutover仅分片——不要试图在包装上建索引它没有数据可索引。罕见结构性变更ORDER BY、PRIMARY KEY和PARTITION BY在MergeTree上不可变完全无法ALTER修改任何一个都需要重建表并拷贝数据。不要在混合集群窗口期内尝试结构性变更。它要搭乘继任表的定义就像000114中的每周分区键那样而不是窗口内的ALTER。若你认为确有必要那是设计对话不是迁移。上述不变式对结构性变更依然成立门禁依然执行——它们比较排序键与主键无论变更以何种方式做出。已知限制守卫在单个节点上评估Liquibase 在它持有的唯一 JDBC 连接上、针对该服务器自身的system.tables评估sqlCheck然后才提交ALTER ... ON CLUSTER。因此分支从一个主机的拓扑视图选出若副本短暂偏斜——cutover 中途或某副本在追赶——一个主机可能选了某分支互补 changeset 却被记录为MARK_RAN其余主机永久缺该变更而账本却声称已应用。实践中有三件事约束它但没有一件能消除它cutover 的EXCHANGE 包装本身就是ON CLUSTER所以traces_local是集群级出现而非逐节点exchange_and_wrap.sh在继续前以复制安定门replication-settle gate见 runbook「The replication-settle gate」一节把关下面的 freeze 规则把 schema DDL 挡在偏斜最可能发生的窗口之外。候选的加固方案是把前置条件改为在clusterAllReplicas上评估、遇部分应答即失败——这尚未决定它改变 shipped 模式且中途报错的前置条件的失败语义需要想清楚。在那之前不要对未确认安定的集群发布 trace schema DDL。Freeze 规则soak 期间禁止 trace schema DDL当某安装处于EXCHANGE与 soak 结束之间traces_pre_cutover_backup仍被保留、回滚仍有可能的窗口不要发布 trace schema DDL。回滚会把停放的 pre-cutover 表提升回traces。soak 期间只应用到继任表的任何 DDL 都会随回滚丢失而它的 changeset 仍记为已应用——于是账本声称存在一个并不存在的列之后也没有迁移会补上它。在 cutover 开始前落地 trace schema 变更或在 soak 结束后落地。CI 门禁检查什么、怎么读失败门禁断言内容TracesSchemaParityPreCutoverTest像全新安装一样应用真实 changelog然后断言三方 paritytraces≅traces_local_v2shadow ≅ backfill 列清单TracesSchemaParityPostCutoverTest在000114之后停住 changelog拼接 runbook 的EXCHANGE 包装恢复应用——于是你的迁移在 post-cutover 拓扑上运行——然后断言包装恰好暴露分片的列TracesMigrationPreconditionLintTest快速、无容器的检查严格在000114之后新增的、变更traces的迁移必须在变更 changeset 自身上携带守卫并发布两个互补分支TraceMutationRoutingArchTest/TraceMutationSqlRoutingTest运行时 DAO 变更通过TraceDAOImpl#tracesMutationTable()解析其表永不直接命名traces/traces_local每道门禁还带负向测试注入粗心迁移产生的漂移因此没有任何断言会悄悄停止触发。Parity 门禁使用专用、不复用的容器因为负向测试会真实改动traces见两个测试类的类级注释。Lint 门禁是门禁前面的快路径TracesMigrationPreconditionLintTest.java 在毫秒级、无需容器的情况下指出文件和 changeset直接给出「迁移未携带守卫」的结论同时它扫描目录本身非空、000114拼接点存在防止扫描悄悄变成空操作。CI 不检查什么以上全部比较的是schema——名字、类型、以及构建其上的 select/表达式定义。没有任何一项移动一行数据因此没有任何一项能告诉你转换是否无损。特别是把列加入BASELINE_TYPE_DIFFERENCES会豁免其类型 parity之后没有任何东西验证 cutover 的转换是否保留其值——那是刻意的值保真是TracesLocalV2CutoverTest的职责、全量彩排是 QA 门禁的职责但这也意味着白名单条目是一个决策不是形式它断言你已经确认转换安全或损失有意。请在条目的 reason 里说明是哪一种。TracesSchemaParity.java中的白名单当前包含 6 个基线类型差异31 个共享列中的 6 个start_time/created_at纳秒 → 微秒、end_time/ttft/durationNullable→ 带 sentinel 的非空、id_atDateTime→DateTime64(0)诚实到 2106 之后使远未来 UUIDv7 正确分区。每个条目都在两侧钉死类型——仅要求「类型不同」会让任一侧漂移到无关类型仍被豁免条目两侧收敛了就必须删除让该列恢复常规类型检查。常见失败速查read-facing column parity—— 你改了一张表没改另一张。补上缺失的ALTER。cutover backfill parity—— 你加了保留列却没加进 backfill 列清单。wrapper column parity/ 某列不可读 —— 你的 post-cutover 分支改了分片没改包装。skip-index parity—— 你给traces加了索引没给 shadow 加。lint 失败—— 你的新迁移变更traces却完全没有前置条件守卫——从上面的模式开始写。Append-onlyshipped 迁移永不编辑Shipped 迁移从不编辑——不是为了修复也不是为了给早于 cutover 的迁移补前置条件。每个变更都是一个新的、追加的迁移。无守卫变更traces的迁移000091、000113等早于 cutover对运行过它们的安装是正确的lint 刻意只从000114起生效正是这个原因——补丁里的注释明确写着与其维护一份早晚会被追加的祖父豁免清单不如让 lint 从「安装可能已经 post-cutover 的第一个点」开始生效这个边界无需维护、也不可能被意外放宽。未决决策deferred全新安装是否会收敛到 post-cutover 拓扑全新与开源安装会收敛到 post-cutover 拓扑吗今天全新安装以 pre-cutover 起步并停留于此直到操作员运行 runbook——这意味着每个守卫迁移的 pre-cutover 分支无限期承重混合集群永远不会完全闭合。替代方案——让全新安装直接创建终态traces_local 包装——可让 pre-cutover 分支最终退役代价是绿场路径与迁移路径不同。这尚未决定。在决定之前请假设两种拓扑都是永久的并为每个 trace 迁移写下两个分支。相关绿场终态创建与 cutover 时 shadow 派生作为独立工作跟踪不随 OPIK-7772 一起。与运行时 flag 的联动三开关与一条路由虽然本页聚焦迁移规范但 cutover 的运维正确性依赖 DatabaseAnalyticsDataModelConfig.java 中的三个配置开关databaseAnalyticsDataModel.*对应ANALYTICS_DB_DATA_MODEL_*环境变量traceDeletionEventsCaptureEnabled默认 false为 true 时每次 trace 删除都会把(workspace_id, project_id, id)记入deletion_events_local供 cutover 的删除重放使用必须在 backfill 开始前部署并全程保持开启traceColumnsNonNullable默认 false继任表把end_time/ttft存为非空 sentinel 列此开关在写绑定与读/过滤/排序翻译两侧同时切换语义必须与EXCHANGE锁定同步翻转——其失败模式是静默的input_format_null_as_default会把null静默转成 sentinel需要主动正向检查而非盯错误日志tracesDistributedWrapEnabled默认 falseDistributed表不支持变更ClickHouse 26.3 实测DELETE FROM distributed→ code 36、ALTER TABLE distributed DELETE→ code 48此开关让TraceDAO的变更语句经tracesMutationTable()路由到traces_local必须与应用包装锁步自 OPIK-7773 起ClickHouseTracesTopologyHealthCheck 每次探针都会把该 flag 与 livetraces引擎对照不匹配即 fail-loud。这些 flag 与本文的迁移模式同属 cutover 工程的不同侧面迁移保证表结构双拓扑一致flag 保证运行时读写语义与当前拓扑一致。参考资源Cutover runbook 及参考 SQLdata-migrations/traces-local-v2-cutover 目录backfill / delta / replay / EXCHANGE / reconcile 五步序列含 batching、settle gate、final cutover window 等细节参考迁移双分支reference_topology_aware_change.sql负向对照本模式要防的错误unguarded_traces_change.sqlBackfill 参考语句保留列清单的单一权威000001_backfill_traces_local_v2.sqlParity 门禁实现TracesSchemaParity.java 及 PreCutover / PostCutover 两个测试Lint 门禁TracesMigrationPreconditionLintTest.java运行时变更路由TraceDAOImpl#tracesMutationTable()与 DatabaseAnalyticsDataModelConfig.javaCutover 数据正确性门禁与本页关注点不同TracesLocalV2CutoverTest【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价