-
[OPIK-7455] [BE] feat: retarget trace mutation DAOs to traces_local behind a wrap toggle (#7713)
发布于
2026-08-04 13:23:41 +00:00 - [OPIK-7455] [BE] feat: retarget trace mutation DAOs to traces_local behind a wrap toggle
The traces cutover's final, deferred step wraps
tracesas a Distributed table
over thetraces_localshard. A Distributed table supports SELECT/INSERT but
not mutations (ClickHouse: DELETE -> code 36, ALTER ... DELETE -> code 48), so
every trace DELETE would return 500 the instant the wrap is applied. This ships
the code prerequisite before the wrap is enabled.TraceDAO's three mutation paths — DELETE_BY_PROJECT_ID_TRACE_ID_PAIRS
(delete-by-id), DELETE_FOR_RETENTION, and the dynamic deleteForRetentionBounded
— now carry both table names in an<if(distributed_wrap)>traces_local<else> traces<endif>branch, gated by the new
databaseAnalyticsDataModel.tracesDistributedWrapEnabled toggle. Default false
keeps mutations ontraces(still a MergeTree pre-wrap); set true in lockstep
with applying the wrap to route them attraces_local. Reads and inserts always
stay on the Distributedtraces. A repo-wide audit confirmed these are the only
DELETE/ALTER/OPTIMIZE paths ontraces.The toggle is wired through config.yml, config-test.yml, docker-compose, and the
Helm chart (values, configmap, and its unittest), mirroring the sibling cutover
toggles so operators can actually set it. The accessor Javadoc documents the
general rule (future mutation/ALTER/OPTIMIZE paths and migrations switch tables
the same way) and why single-shard mutations need no ON CLUSTER; the cutover
runbook and exchange_and_wrap.sh name the flag as the concrete prerequisite for
the wrap.Add TracesDistributedWrapMutationTest: a black-box suite on dedicated containers
that builds the post-wrap Distributed topology and proves, through the public
trace API, that delete-by-id and both retention paths run againsttraces_local
while reads/inserts flow through the Distributedtraces, with a guard test
asserting a direct mutation on the Distributedtracesis rejected.Implements OPIK-7455.
- chore(helm): regenerate chart README for tracesDistributedWrapEnabled
The helm-docs pre-commit hook failed in CI because values.yaml gained the
tracesDistributedWrapEnabled entry without the generated README values table
being refreshed. Regenerated via jnorwood/helm-docs (same image as CI).- refactor(traces): centralize wrap-table ST attribute + document rollback flag reset
Address Baz PR review:
- Extract addTracesMutationTable(ST) so the <if(distributed_wrap)> branch is
applied from one place by both ST delete templates (the flag decision already
lived in the single tracesDistributedWrapEnabled() accessor). - Document the symmetric rollback prerequisite: Stage C makes
tracesa
MergeTree again and parkstraces_local, so tracesDistributedWrapEnabled must
be set back to false before backends resume — added to the runbook Rollback
section and the 000004_rollback_stage_c comment.
- docs(cutover): refresh runbook references after OPIK-7483 and the flag reframing
Address JetoPistola's review (documentation-only, non-blocking):
- Delta/replay section no longer describes the workspace-scoped, empty-project
delete fallback as current: OPIK-7483 removed it, so TraceService.delete always
carries project_id and the empty-project replay branch now covers only legacy
pre-OPIK-7483 bridge rows. Drops the stale TraceDAO.DELETE_BY_ID reference. - "once the sharding-aware DAO has shipped" -> the retarget flag being live across
the fleet, matching the flag-based framing this PR introduced. - Go/No-Go exit criteria phrased the same way (retarget flag live and healthy).
- docs(cutover): carve schema ALTERs out of the general rule + note partition-metrics relabel
Address Thiago's review (documentation-only, non-blocking):
- The "target traces_local" general rule was wrong for schema migrations. Split
it by kind across all five sites (README, DatabaseAnalyticsDataModelConfig,
TraceDAO accessor, config.yml, config-test.yml): row mutations + MATERIALIZE
COLUMN / ADD INDEX / MODIFY TTL go to traces_local only (the Distributed traces
rejects them, code 36/48); ADD/DROP/MODIFY COLUMN must hit both traces_local and
the Distributed traces, since the wrapper takes them as metadata-only and
traces_local alone leaves reads unable to see the column (code 47). - Note the monitoring consequence in the flip checklist and its Stage C inverse:
the opik.clickhouse.partition.* parts gauges relabel traces<->traces_local at
the wrap/rollback while the LWD-mask gauge stays labelled traces.
- refactor(traces): rename addTracesMutationTable -> selectTracesMutationTable
Address Baz: the helper adds the distributed_wrap template attribute (which
selects the mutation table via the branch) rather than "adding a table";
the intent-based name reads correctly at the two call sites.
下载附件