Files
OpenFlare/docs/design/logstore.md
T
ryan 600a7acdfb docs: 核查并润色文档,对齐项目实际实现
- 删除未经验证的环境要求(Docker 版本号、浏览器条目)与括号废话
- 故障排查改为真实处理路径(升级→重新发布→强制同步→重建 Agent→提交 issue),删除仅开发时用的排障章节
- 删除设计文档中的测试与验收、实现检查清单、贡献者阅读建议等开发内容
- 修正与代码不符的事实:reset-passwd 命令名、证书续签窗口 7 天、Pages 检查间隔 1440 分钟、Relay vhost 端口 8080、SSO 仅支持 OIDC 等
- 去除口语化表述与无意义括号,改写「不是…而是…」句式
- 同步修正文档站链接锚点,构建验证通过
2026-08-16 17:49:57 +08:00

87 lines
4.3 KiB
Markdown
Raw 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,以及新增一张日志表时必须走哪条代码路径。
观测字段与上报协议仍以 [观测上报协议与表结构](./observability-data-model.md) 为准;本文只约定**存到哪、怎么切库**。
---
## 1. 目标
* **ClickHouse 可选**:不启用时,PostgreSQL(或关闭主库时的 SQLite)完整承接写入、查询、聚合与清理。
* **上层不碰底层库**:apps 只面向 `internal/repository/logstore`(或 `repository` 门面)。`repository/analytics` 与 `db.ChConn` / `db.ChDB` 仅供 logstore 的 ClickHouse 实现使用。
* **可切换**:任务管理里的「切换日志数据库」在 PostgreSQL/SQLite 与 ClickHouse 之间复制数据并翻转主库;迁移期间冻结写入,成功才切换,源数据不删。
---
## 2. 什么算日志表
同时满足才进 logstore:
* 追加写入,几乎不更新单行
* 按时间查询或聚合,允许按保留天数删除
* 关闭 ClickHouse 后仍要能写、能查
* 不参与网站 / 节点 / 证书等事务一致性
**不要**做成日志表:Zone、节点、配置版本、任务执行、上传元数据。这些走业务主库 `repository`。
当前日志域:
| 域 | 接口 | 表 |
| --- | --- | --- |
| 节点访问日志 | `AccessLogStore` | `of_node_access_logs` |
| 可观测时序 | `ObservabilityStore` | `of_node_metric_snapshots` / `of_node_edge_health` / `of_node_obs_frps` / `of_node_obs_frpc` |
| 用户访问审计 | `UserAccessLogStore` | `w_user_access_logs` |
ClickHouse 上的小时级物化视图(如 `of_access_log_hourly`)只服务 CH 查询加速。PostgreSQL / SQLite **不建**同构聚合表,查询时从原始日志实时聚合。
---
## 3. 分层
| 层级 | 路径 | 职责 |
| --- | --- | --- |
| 抽象 | `internal/repository/logstore` | 接口 + `Active` / `BuildForMigration`;按 `log_database` 选实现 |
| CH 实现 | `logstore/clickhouse_store.go` | 委托 `repository/analytics`(原生批量 + 现有聚合 SQL) |
| 主库实现 | `logstore/postgres_store.go` | PostgreSQL(高频表按月分区)与 SQLite(普通表)共用 GORM |
| Model | `internal/model/analytics` | 实体与批量 SQL,无 IO |
| 入队 | `chwriter` / `risk_control` + `batchwriter` | `FlushFunc` 调 `logstore.Active`;节点日志 / 可观测经 hooks 入队 |
| 约束 | `logstore/imports_test.go` | apps 禁止 import `repository/analytics` |
`log_database` 只有两种合法状态:**随业务主库**(`postgres` 或 `sqlite`)或 **`clickhouse`**。不存在「主库 PostgreSQL + 日志 SQLite」。`log_database` / `log_db_migration` 受保护,管理端不可改。
启动时:`log_database=clickhouse` 但 ClickHouse 未启用会拒绝启动,须先重新启用 ClickHouse 并切回主库后再关掉。
---
## 4. 切换协议
任务类型 `of_log_db_switch`(管理端名称「切换日志数据库」),参数 `target`。
1. 校验目标合法且不等于当前库。
2. 写 `log_db_migration=migrating`,排空在途 batchwriter(`Drain`,不要 `Stop` writer)。此后写入返回明确错误(HTTP 503),不排队积压。
3. 清空目标日志表后按 id 分页复制;复制前对 PostgreSQL 目标 `EnsurePartitions`。
4. 全部成功才写 `log_database=target` 并清除迁移标记;失败清除标记,写入继续走源库。
5. 源数据不删;重试前重新清空目标以保证幂等。
不要另起切换协议,也不要在任务里直连 `analyticsrepo`。
---
## 5. 新增一张日志表
列名必须在 ClickHouse / PostgreSQL / SQLite 三套 goose 迁移中一致。要点:
* 高频表:CH 用 `MergeTree` + `toYYYYMM`;PG 用 `PARTITION BY RANGE(时间列)`,主键含分区键;SQLite 普通表 + 索引。
* ID 用 snowflake `uint64`,迁移时原样保留。
* 写入走独立 `batchwriter`;flush 调 `logstore.Active`,不要 `analyticsrepo.BatchInsert`。
* 切换任务的 `copy*` 必须覆盖新表;清理走已有 `log_retention_days_*` 或 `metric_retention_days`,不要用错 TTL。
运行时配置见 [配置项参考 · 日志存储](../reference/configuration.md#8-日志存储log-database)。
---
## 6. 相关文档
* 观测字段与上报协议:[观测上报协议与表结构](./observability-data-model.md)