Skip to content

fix(perf_metrics): 修复 PG 下 upsert 列引用歧义并加固 flush 重试#17

Merged
reputationly merged 1 commit into
mainfrom
fix/perf-metrics-upsert-ambiguous-column
Jun 23, 2026
Merged

fix(perf_metrics): 修复 PG 下 upsert 列引用歧义并加固 flush 重试#17
reputationly merged 1 commit into
mainfrom
fix/perf-metrics-upsert-ambiguous-column

Conversation

@reputationly

Copy link
Copy Markdown
Owner

背景 / 现象

现网 RDS(PostgreSQL 14.17)错误日志两周内刷出约 13.8 万条 同一错误:

ERROR: column reference "generation_ms" is ambiguous
STATEMENT: INSERT INTO "perf_metrics" (...) VALUES (...)
  ON CONFLICT ("model_name","group","bucket_ts")
  DO UPDATE SET "generation_ms"=generation_ms + $11, ...

占全部错误的 99.998%(另有 2 条 cached plan must not change result type、1 条用户名唯一约束冲突,均为偶发且无害)。

根因

UpsertPerfMetricON CONFLICT DO UPDATE 右侧列名未加表名限定(裸 generation_ms + ?)。PostgreSQL >=14.4 会把这种未限定列引用判定为「目标行 vs excluded 行」之间的歧义(column reference is ambiguous),导致所有走 DO UPDATE 路径的写入失败

  • 单实例首次写桶是纯 INSERT,不触发;一旦行已存在(多写入源并发)即走 DO UPDATE → 必失败。
  • 本次现网是某测试环境实例被误配成生产 SQL_DSN,形成第二写入源,与生产实例抢同一批 (model,group,bucket) 行 → 持续冲突。
  • flush.go 失败分支「退回内存 + 无限重试 + 永不删桶」,把单次冲突放大成持续刷错 + 内存只增不减

影响范围

  • 仅影响模型广场/定价页性能徽章、模型详情性能趋势图、Dashboard 模型性能概览的数据准确性:请求量系统性偏低、多次刷新数值跳变、重启后近期数据缩水。
  • 计费、relay、用户等核心业务不受影响,接口不报错(始终返回 200)。

改动

  1. model/perf_metric.go:7 个累加列全部加 perf_metrics. 表名限定。SQLite/MySQL/PostgreSQL 通用(Rule 2),并发 upsert 可原子正确累加 → 单实例 / 多节点(CCE) 均安全,根治。
  2. pkg/perf_metrics/flush.go:flush 失败分支增加 24h 年龄兜底(复用既有阈值),超期 stuck 桶直接丢弃,避免内存泄漏与日志无限刷;24h 内失败仍退回重试,不丢数据(可扛 DB 短暂抖动)。

验证

  • go build ./... 全量编译通过
  • go vet ./model/ ./pkg/perf_metrics/ 通过
  • ✅ SQLite 3.51 实测 perf_metrics.<col> + N 累加正常

发版注意

  • ⚠️ 部署前需先停掉/改回测试环境那个误连生产库的实例(独立运维动作,在线升级生产不会自动停它)。
  • 重启生产实例会清掉内存中已 stuck 的桶,错误即清零。
  • 历史脏数据无需手动清理,约 24h 后自然滚出展示窗口。

UpsertPerfMetric 的 ON CONFLICT DO UPDATE 右侧列名未加表名限定,
PostgreSQL (>=14.4) 会判定为目标行与 excluded 行之间的列引用歧义
(column reference is ambiguous),导致所有走 DO UPDATE 的写入失败。
多实例/多写入源并发时每个冲突桶都会报错并被无限重试。

- model/perf_metric.go: 7 个累加列全部加 perf_metrics. 表名限定
  (SQLite/MySQL/PostgreSQL 通用),并发 upsert 可原子正确累加。
- pkg/perf_metrics/flush.go: flush 失败分支增加 24h 年龄兜底,
  超期 stuck 桶直接丢弃,避免内存只增不减与日志无限刷。
@reputationly reputationly merged commit fb34b1c into main Jun 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant