vault backup: 2026-06-12 15:36:35
This commit is contained in:
@@ -79,6 +79,7 @@ graph TB
|
||||
| 语言 | **Go** | 高并发 goroutine 模型,适合长连接管理 |
|
||||
| WebSocket | **gorilla/websocket** | Go 生态最成熟的 WebSocket 库 |
|
||||
| 会话存储 | **Redis** | 高速 KV 存储,适合会话状态和上下文缓存 |
|
||||
| 持久化存储 | **PostgreSQL** | 对话历史、用量统计、用户偏好(MVP 阶段可选) |
|
||||
| 配置管理 | **Viper** | 支持多格式配置,环境变量覆盖 |
|
||||
| 日志 | **Zap** | 高性能结构化日志 |
|
||||
|
||||
@@ -279,6 +280,109 @@ graph LR
|
||||
> [!tip] WebSocket 与负载均衡
|
||||
> WebSocket 是长连接,Nginx 需要配置 `proxy_set_header Upgrade` 和 `ip_hash` 或 sticky session,确保同一用户的请求始终路由到同一个 Gateway 实例。
|
||||
|
||||
### 存储与持久化策略
|
||||
|
||||
当前架构使用 Redis 做会话存储,但 Redis 是**内存数据库**,默认不做持久化——服务重启数据即丢。是否需要持久化,取决于业务阶段:
|
||||
|
||||
#### 分阶段策略
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A["MVP 阶段"] -->|"Redis 内存存储"| B["快速验证"]
|
||||
C["上线阶段"] -->|"Redis + PostgreSQL"| D["持久化对话与用量"]
|
||||
E["规模化阶段"] -->|"Redis + PG + 对象存储"| F["完整数据体系"]
|
||||
```
|
||||
|
||||
| 阶段 | 存储方案 | 持久化内容 | 理由 |
|
||||
|------|---------|-----------|------|
|
||||
| **MVP** | Redis only | 无 | 快速验证核心功能,重启丢数据可接受 |
|
||||
| **上线** | Redis + **PostgreSQL** | 对话历史、用户偏好、用量统计 | 用户需要查看历史,运营需要成本数据 |
|
||||
| **规模化** | Redis + PG + **对象存储** | 图像帧、音频片段归档 | 大文件不适合存关系库 |
|
||||
|
||||
#### 需要持久化的数据
|
||||
|
||||
| 数据类型 | 写入频率 | 查询模式 | 推荐存储 |
|
||||
|---------|---------|---------|---------|
|
||||
| 对话历史(文本) | 每轮对话 | 按用户+时间范围查询 | PostgreSQL |
|
||||
| 用量统计(tokens/成本) | 每次 API 调用 | 聚合统计(日/周/月) | PostgreSQL |
|
||||
| 用户偏好(语言/声音) | 低频 | 按 user_id 查询 | PostgreSQL |
|
||||
| 实时会话状态 | 高频读写 | 按 session_id 查询 | Redis(不变) |
|
||||
| 关键帧图像 | 按需 | 按对话 ID 关联 | 对象存储(S3/MinIO) |
|
||||
|
||||
#### PostgreSQL 表设计要点
|
||||
|
||||
```sql
|
||||
-- 对话会话表
|
||||
CREATE TABLE sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
-- 对话消息表
|
||||
CREATE TABLE messages (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
session_id UUID REFERENCES sessions(id),
|
||||
role VARCHAR(16) NOT NULL, -- "user" | "assistant"
|
||||
content TEXT NOT NULL,
|
||||
image_url TEXT, -- 关联的关键帧(可选)
|
||||
tokens_used INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
-- 用量统计表(按天聚合,方便成本分析)
|
||||
CREATE TABLE usage_daily (
|
||||
user_id UUID NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
llm_tokens BIGINT DEFAULT 0,
|
||||
stt_seconds REAL DEFAULT 0,
|
||||
tts_chars INTEGER DEFAULT 0,
|
||||
estimated_cost NUMERIC(10,4) DEFAULT 0,
|
||||
PRIMARY KEY (user_id, date)
|
||||
);
|
||||
```
|
||||
|
||||
> [!info] 为什么选 PostgreSQL 而不是 MySQL?
|
||||
> PostgreSQL 对 JSON 类型支持更好(对话上下文可直接存 JSONB),且有 `gen_random_uuid()` 等原生函数,更适合这类 AI 应用场景。当然,如果团队更熟悉 MySQL,替换成本也很低。
|
||||
|
||||
#### 更新后的存储层架构
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph App["Go Gateway"]
|
||||
SM["Session Manager"]
|
||||
HM["History Manager"]
|
||||
UM["Usage Monitor"]
|
||||
end
|
||||
|
||||
subgraph Cache["热数据 - Redis"]
|
||||
SESSION["会话状态"]
|
||||
CTX["对话上下文窗口"]
|
||||
end
|
||||
|
||||
subgraph DB["冷数据 - PostgreSQL"]
|
||||
HISTORY["对话历史"]
|
||||
USAGE["用量统计"]
|
||||
PREFS["用户偏好"]
|
||||
end
|
||||
|
||||
subgraph OSS["大文件 - 对象存储"]
|
||||
IMG["关键帧图像"]
|
||||
AUDIO["音频片段"]
|
||||
end
|
||||
|
||||
SM --> SESSION
|
||||
SM --> CTX
|
||||
HM --> HISTORY
|
||||
HM --> IMG
|
||||
UM --> USAGE
|
||||
SM --> PREFS
|
||||
```
|
||||
|
||||
> [!question] 思考
|
||||
> Redis 存"热数据"(当前对话上下文),PostgreSQL 存"冷数据"(历史记录)——这就是经典的**冷热分离**策略。实时对话走 Redis 微秒级读写,历史查询走 PostgreSQL,互不干扰。
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[视觉理解]]
|
||||
@@ -286,3 +390,4 @@ graph LR
|
||||
- [[成本控制]]
|
||||
- [[用户故事]]
|
||||
- [[项目架构与技术栈/技术名词解释]]
|
||||
- [[持久化技术选型]]
|
||||
|
||||
Reference in New Issue
Block a user