chore: docs

This commit is contained in:
ryan
2026-08-16 11:32:13 +08:00
parent fa689aedbc
commit 64fbaa7ef1
9 changed files with 194 additions and 25 deletions
+1
View File
@@ -138,6 +138,7 @@ function sidebarDesign(): DefaultTheme.SidebarItem[] {
{ text: '边缘可观测与业务流量统计', link: 'observability-design' },
{ text: '观测数据传输模型', link: 'observability-transport-model' },
{ text: '观测上报协议与表结构', link: 'observability-data-model' },
{ text: '日志存储解耦', link: 'logstore' },
{ text: 'Uptime Kuma 监控同步设计', link: 'kuma-design' },
{ text: '登录验证码设计', link: 'login-captcha' }
]
+1 -1
View File
@@ -2,7 +2,7 @@
你会学到:OpenFlare 的推荐部署方式、Server 与 Agent 的运行要求、源码启动方式、联调步骤、升级与卸载入口。
生产环境建议使用 PostgreSQL 作为 Server 数据库,并通过 `config.yaml` 或环境变量配置 `APP_SESSION_SECRET` 等参数。完整 Docker Compose 部署还需 Redis 与 ClickHouse(见仓库根目录 `docker-compose.yaml`)。Agent 部署方式推荐为 Docker 部署(即直接使用内置 OpenResty 的 Agent 镜像);亦支持通过安装脚本或手动本地运行。
生产环境建议使用 PostgreSQL 作为 Server 数据库,并通过 `config.yaml` 或环境变量配置 `APP_SESSION_SECRET` 等参数。完整 Docker Compose 部署需要 Redis;ClickHouse 可选,用于海量访问日志与观测时序(见仓库根目录 `docker-compose.yaml`)。Agent 部署方式推荐为 Docker 部署(即直接使用内置 OpenResty 的 Agent 镜像);亦支持通过安装脚本或手动本地运行。日志库判定与切换见 [日志存储解耦](../design/logstore.md)。
## 部署拓扑
+1 -1
View File
@@ -145,7 +145,7 @@ OpenResty access.log(业务事实)
|
| Agent tail 增量明细(不 sum/count/uniq)
v
Server 入库 ClickHouse
Server 经 logstore 入库(当前日志主库:PostgreSQL / SQLite / ClickHouse)
|
+---> 全局聚合 --> 看板「已提供数据 / 请求 / UV」
+---> host∈Zone --> Zone「已提供数据」等(同一套语义)
+4 -2
View File
@@ -32,6 +32,7 @@ OpenFlare 适合需要统一管理多台 OpenResty 代理节点的团队,具
| **Pages 静态托管** | 支持上传或从 Remote URL、公开 GitHub Release 同步预构建产物;GitHub latest 可定时检查并可选自动发布。不可变部署由边缘节点拉取并由 OpenResty 本地服务,支持回滚、API 反代与 SPA Fallback | [Pages 静态托管设计](./pages-design.md) / [Pages 使用指南](../guide/pages-usage.md) |
| **TLS 证书自动续期** | 将证书显式绑定到 Zone 域名,并通过 ACME 协议向 Let's Encrypt 申请/续期证书 | [Zone 与域名资源设计](./zone-design.md) |
| **多节点监控与观测** | 访问日志为业务流量唯一真相;Agent 只上报明细与主机读数,Server 统一聚合;与 Zone/看板对账 | [观测数据传输模型](./observability-transport-model.md) / [边缘可观测与业务流量统计](./observability-design.md) / [上报协议与表结构](./observability-data-model.md) / [系统架构](./architecture.md) |
| **日志存储** | 访问日志与可观测时序走可切换日志主库(随业务主库或 ClickHouse);关闭 ClickHouse 后仍可写可查 | [日志存储解耦](./logstore.md) |
---
@@ -62,7 +63,7 @@ OpenFlare 适合需要统一管理多台 OpenResty 代理节点的团队,具
### 5. 系统与版本边界
* **全局单一激活版本**:所有节点拉取并消费同一份全局激活配置。不进行按节点分组的差异化配置发布。
* **单租户架构**:OpenFlare 仅供单团队在受信任的内部网络部署使用。采用单租户设计,不支持细粒度的多用户角色或多租户资源隔离。
* **外部基础设施依赖性**:Server 虽支持 SQLite 作为本地轻量关系数据库,但**系统必须强制依赖外部 Redis(或 Valkey)及 ClickHouse 实例**。Redis 用于处理分布式协调、后台异步队列(Asynq 框架)及系统级全局缓存;ClickHouse 用于接收海量节点访问日志与基础观测的异步 Flush。系统不支持完全脱离这两个组件运行。
* **外部基础设施依赖性**:Server **必须依赖**外部 Redis(或 Valkey),用于分布式协调、Asynq 队列与系统缓存。关系库为 PostgreSQL,或关闭 `database.enabled` 时使用 SQLite。ClickHouse **可选**:不启用时,访问日志与可观测时序由当前日志主库(随业务主库)承接;启用后可通过「切换日志数据库」任务迁到 ClickHouse。系统不支持脱离 Redis 运行。详情见 [日志存储解耦](./logstore.md)。
---
@@ -98,7 +99,7 @@ OpenFlare 已收敛为**单 monorepo**(Go 模块 `github.com/Rain-kl/Wavelet`
| `internal/apps/openflare/{agent,relay,flared}/` | **Server 侧**边缘协议处理器(鉴权、心跳、WS) |
| `internal/model/` | GORM 实体 / DTO / 无 IO 领域规则(`openflare_*.go` + 平台模型);**不含** DB 访问 |
| `internal/infra/persistence/migrator/goose/` | goose SQL 迁移(PostgreSQL / SQLite / ClickHouse) |
| `internal/repository/` | 数据访问层(平台 + OpenFlare 业务 CRUD、缓存、ClickHouse 分析读写);**唯一**持久化入口 |
| `internal/repository/` | 数据访问层(平台 + OpenFlare 业务 CRUD、缓存、`logstore` 日志读写);**唯一**持久化入口 |
| `internal/infra/task/` | Asynq 异步任务(Worker + Scheduler) |
| `internal/infra/config/` | Viper 配置加载 |
| `internal/shared/` | 统一 API 响应封装(`response/`) |
@@ -191,6 +192,7 @@ OpenFlare 已收敛为**单 monorepo**(Go 模块 `github.com/Rain-kl/Wavelet`
## 文档维护原则
* 产品范围或系统边界变化:更新本文档([产品边界](./index.md))。
* 日志存储、日志表判定或切换协议变化:更新 [日志存储解耦](./logstore.md)。
* 系统结构、组件分工变化:更新 [系统架构](./architecture.md)。
* 发布、同步、回滚与 Agent 模型变化:更新 [Agent 与发布模型](./agent-design.md)。
* 部署方式变化:更新 [部署说明](../deployment/deployment.md) 与 README。
+89
View File
@@ -0,0 +1,89 @@
# 日志存储解耦
你会学到:哪些表属于日志用途、为什么不能绑死 ClickHouse,以及新增一张日志表时必须走哪条代码路径。逐步落地步骤见 `.agents/skills/logstore/SKILL.md`。
观测字段与上报协议仍以 [观测上报协议与表结构](./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 中一致。顺序与禁止项见 `logstore` skill。要点:
* 高频表: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. 相关文档
* 开发步骤:`.agents/skills/logstore/SKILL.md`
* DDL:`.agents/skills/database-migration/SKILL.md`
* 批量写入:`.agents/skills/clickhouse-batchwriter/SKILL.md`
* 实现前设计稿(历史):[日志数据库解耦设计](../superpowers/specs/2026-08-08-log-database-decoupling-design.md)