Files
token_thief/docs/compose/specs/2026-07-09-clickhouse-migration.md

55 lines
3.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ClickHouse Migration 安全修复规格
> [!NOTE]
> This document may not reflect the current implementation.
> See the final report for up-to-date state:
> [Final Report](../reports/reliability-security-fixes.md)
## 修订范围
本规格是现有 ClickHouse Migration 的增量修订。保留当前单表 `proxy_logs`、内存异步队列、`httputil.ReverseProxy` 和 best-effort 审计模型,不引入 PostgreSQL 兼容层、持久化 outbox 或 WebSocket 帧采集。
## 行为要求
### 队列与关闭
- `Submit` 始终非阻塞;与 `Stop` 并发、停止后提交和重复停止均不得 panic。
- 队列由条数和字节双重预算约束。默认 `LOG_QUEUE_SIZE=256``LOG_QUEUE_BYTES=67108864``MAX_BODY_BYTES=1048576`;任一预算不足即丢弃并计数。
- `Stop(ctx)` 使用调用方提供的单一总 deadline 排空;deadline 到期取消所有 worker I/O、丢弃剩余条目并返回错误。
- worker flush 后清空 batch 指针并释放条目的字节预留。
### ClickHouse 写入
- `PrepareBatch` 错误是确定未提交错误,可有限重试整个 batch。
- `Append` 错误是确定未提交错误,必须中止/关闭 batch,并允许逐条隔离坏记录;成功记录继续写入,失败记录明确计数。
- `Send` 错误视为提交结果不明,不自动重试或逐条重发,避免静默重复;该批计为 ambiguous drop 并标记连接不健康。
- 进程内 best-effort 方案不承诺跨进程 exactly-once。需要更强保证时必须另行引入持久化 outbox 与幂等协议。
### 代理完整性
- 请求体预读失败时返回固定 400,不调用 upstream,不转发已损坏请求。
- 502 客户端响应只包含固定 `bad gateway` 和 request ID;内部网络错误仅写服务端日志和 `LogEntry.Error`
- 只有 ReverseProxy 正常完成的普通/SSE 响应才提交完整日志。下游写失败、短写、客户端断开或响应复制中断不得提交成完整成功日志。
- SSE 终止检测只在响应 `Content-Type``text/event-stream` 时按完整 event 边界解析。终止事件仅用于状态判断,不触发提前提交;提交仍等待代理正常返回。
- 普通 HTTP 响应体使用可配置总 timeoutSSE 使用可配置 idle timeout,成功读取数据后重置;timeout 必须能关闭阻塞中的上游 Body。
- WebSocket 成功升级时记录一条 101 握手元数据日志,body 为空。Handler 跟踪已 hijack 连接,并提供受 context 限制的 shutdown 关闭能力;不采集帧。
- 默认不信任 `X-Forwarded-For`/`X-Real-IP`。仅当直接对端命中 `TRUSTED_PROXIES` CIDR 时,从 XFF 右向左剥离可信代理并选择最近的不可信地址。
### 配置与数据库边界
- 所有整数、布尔值和 duration 环境变量格式错误时启动失败;要求正值的 body、队列、batch、worker、重连和 timeout 配置必须严格大于零。
- `CLICKHOUSE_URL` 支持严格 `host:port``clickhouse://``clickhouses://`。仅允许 `secure``skip_verify``compress` 查询参数;未知参数、冲突 TLS 配置、fragment、空 host/port 均失败。
- 建表后校验 `system.columns``system.tables` 的必需列类型、引擎、分区键和排序键;不兼容 schema 拒绝标记健康,不自动重建或改类型。
### 启动与部署
- server 启动错误与 signal 进入同一清理路径;禁止 goroutine 内 `log.Fatalf` 绕过 defer。
- shutdown 总预算依次覆盖 HTTP、升级连接、日志队列、DB 和根 context。
- Compose 固定 ClickHouse 明确版本,不使用 `latest`;默认不发布 ClickHouse 端口;`CLICKHOUSE_PASSWORD` 必须显式设置,应用 DSN 使用独立 `CLICKHOUSE_URL`,避免弱默认和 URL 编码冲突。
## 验证
- 针对上述失败路径增加 config、logger、proxy、db 单元测试。
- 运行 `gofmt``go test ./...``go vet ./...`
- 使用 Git 提交保留完整变更证据;审查应以提交及其 diff 验证实现和验收项。