202 lines
7.7 KiB
Markdown
202 lines
7.7 KiB
Markdown
---
|
||
tags: [architecture, system-design, go, gin, dependency-injection, viper, config]
|
||
create time: 2026-06-03 10:00
|
||
---
|
||
|
||
# 01. 系统总览
|
||
|
||
## 概述
|
||
|
||
Gen2D 采用经典分层架构,数据流自上而下贯穿 Gin HTTP Server → Handler → Service → 基础设施 → 外部依赖,各层职责清晰、可独立替换。
|
||
|
||
> **一句话概括**:分层架构,职责分离,轻量 DI,零配置可启动。
|
||
|
||
## 正文
|
||
|
||
### 架构全景
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph Browser["浏览器 (React)"]
|
||
UI["三栏工作台"]
|
||
end
|
||
|
||
subgraph Gin["Gin HTTP Server"]
|
||
MW["中间件链<br/>Logger / Recovery / Metrics / Auth / RateLimit"]
|
||
end
|
||
|
||
subgraph Handler["Handler 层"]
|
||
GH["Generate"]
|
||
SH["SSE"]
|
||
PH["Prompt"]
|
||
OH["其他 Handler"]
|
||
end
|
||
|
||
subgraph Infra["基础设施层"]
|
||
WP["WorkerPool<br/>协程池"]
|
||
TQ["TaskQueue<br/>Memory / RabbitMQ"]
|
||
EB["EventBus<br/>Pub/Sub"]
|
||
RL["RateLimiter<br/>Redis 令牌桶"]
|
||
end
|
||
|
||
subgraph Pipeline["Service 层 (Eino Pipeline)"]
|
||
PO["PromptOptimizer"]
|
||
AG["AssetGenerator"]
|
||
QS["QualitySupervisor"]
|
||
FA["FormatAdapter"]
|
||
end
|
||
|
||
subgraph External["外部依赖"]
|
||
DB["MySQL"]
|
||
CDN["七牛云 Kodo"]
|
||
REDIS["Redis"]
|
||
LLM["LLM / Image API"]
|
||
end
|
||
|
||
UI -->|"HTTP / SSE"| MW
|
||
MW --> Handler
|
||
GH --> TQ
|
||
GH --> WP
|
||
SH --> EB
|
||
TQ -->|"Consumer"| WP
|
||
WP --> Pipeline
|
||
PO --> AG --> QS --> FA
|
||
AG --> LLM
|
||
FA --> CDN
|
||
Handler --> DB
|
||
RL --> REDIS
|
||
Pipeline -->|"Progress"| EB
|
||
```
|
||
|
||
### 分层详解
|
||
|
||
| 层级 | 目录 | 核心职责 | 代表组件 |
|
||
|------|------|----------|----------|
|
||
| **Entry / DI** | `cmd/main.go` | 启动入口、依赖注入、信号处理 | `main()` |
|
||
| **HTTP 层** | `internal/handler/` | 请求绑定、参数校验、响应封装 | `Generate`, `SSEHandler`, `PromptOptimize` |
|
||
| **中间件** | `internal/mildware/` | 日志、恢复、指标采集、认证、限流 | `Logger`, `Recovery`, `Metrics`, `AuthMiddleware` |
|
||
| **业务层** | `internal/service/` | 生成管线、提示词优化、质检、推理调用 | `RunPipeline`, `CheckQuality`, `GenerateImages` |
|
||
| **领域模型** | `internal/model/` | 数据库实体、响应体定义 | `User`, `Project`, `Task`, `Asset` |
|
||
| **基础设施** | `internal/pkg/` | 协程池、任务队列、事件总线、限流器 | `workerpool.Pool`, `taskqueue.TaskQueue`, `eventbus.Broker` |
|
||
| **精灵处理** | `pkg/splitsprite/`, `pkg/gifmaker/` | 精灵表切割、GIF 预览生成 | `splitsprite.Process`, `gifmaker.Encode` |
|
||
| **配置** | `internal/config/` | YAML 加载、环境变量绑定、默认值 | `config.Load()` |
|
||
|
||
### 依赖注入模式
|
||
|
||
Gen2D 采用轻量级的 **Set*/Init* 函数注入** 模式,避免引入 DI 框架。
|
||
|
||
```
|
||
main.go 中的注入链路:
|
||
|
||
config.Load() → 加载全局配置
|
||
handler.InitAuthService() → 注入 JWT 配置
|
||
service.InitLLMConfig() → 注入 LLM 配置
|
||
service.InitImageGenConfig() → 注入文生图配置
|
||
handler.InitStorageService() → 注入存储服务
|
||
handler.SetWorkerPool() → 注入协程池
|
||
handler.SetTaskQueue() → 注入任务队列
|
||
eventbus.Init() → 初始化事件总线
|
||
```
|
||
|
||
**设计要点**:
|
||
|
||
- Handler 层不直接 import `workerpool`、`taskqueue` 等基础设施包,仅通过注入的接口交互
|
||
- `service.InitImageGenConfig()` 将配置缓存为包级变量,避免在函数签名中传递大量参数
|
||
- 每个 `Set*` 函数对应一个包级全局变量,简单但足够清晰
|
||
|
||
> [!tip] 为什么不用 Wire / Fx?
|
||
>
|
||
> 项目规模可控,`cmd/main.go` 约 220 行即可完成全部注入,框架级 DI 的复杂度收益比不高。
|
||
|
||
### 配置级联
|
||
|
||
Gen2D 使用 Viper 实现三层配置覆盖,优先级从高到低:
|
||
|
||
```mermaid
|
||
graph LR
|
||
ENV["环境变量<br/>GEN2D_*"] -->|"最高优先级"| VIPER["Viper"]
|
||
YAML["YAML 配置文件<br/>config.yaml"] -->|"中等优先级"| VIPER
|
||
DEFAULT["代码默认值<br/>SetDefault()"] -->|"最低优先级"| VIPER
|
||
VIPER --> CONFIG["Config 结构体"]
|
||
```
|
||
|
||
**覆盖规则**:`环境变量 > YAML 文件 > 默认值`
|
||
|
||
| 配置源 | 示例 | 说明 |
|
||
|--------|------|------|
|
||
| 环境变量 | `GEN2D_PORT=9090` | 部署时覆盖,适合容器化场景 |
|
||
| YAML 文件 | `server.port: 8080` | 开发时配置,集中管理 |
|
||
| 默认值 | `v.SetDefault("server.port", 8080)` | 代码内置,零配置即可启动 |
|
||
|
||
配置结构体涵盖 10 个子模块:
|
||
|
||
| 配置块 | 对应环境变量前缀 | 关键字段 |
|
||
|--------|------------------|----------|
|
||
| `server` | `GEN2D_*` | port, mode, max_file_size |
|
||
| `database` | `GEN2D_DSN` | dsn |
|
||
| `jwt` | `GEN2D_JWT_*` | secret, expire |
|
||
| `log` | `GEN2D_LOG_*` | level, format |
|
||
| `redis` | `GEN2D_REDIS_*` | addr, password, db |
|
||
| `llm` | `GEN2D_LLM_*` | base_url, api_key, model |
|
||
| `image_gen` | `GEN2D_IMAGE_*` | base_url, api_key, model, timeout, max_retries |
|
||
| `qiniu` | `GEN2D_QINIU_*` | access_key, secret_key, bucket, cdn_host |
|
||
| `workerpool` | `GEN2D_WORKERPOOL_*` | workers, queue_size, max_per_user |
|
||
| `taskqueue` | `GEN2D_TASKQUEUE_*` | driver, memory.buffer_size, rabbitmq.* |
|
||
|
||
### 请求全链路
|
||
|
||
一个素材生成请求的完整生命周期:
|
||
|
||
```mermaid
|
||
graph LR
|
||
BROWSER["浏览器<br/>POST /api/v1/generate"] --> GIN["Gin中间件链"]
|
||
GIN --> HANDLER["Handler.Generate"]
|
||
HANDLER --> VALIDATE["参数绑定校验"]
|
||
HANDLER --> MYSQL["保存任务MySQL<br/>status=pending"]
|
||
HANDLER --> MSG["构建TaskMessage"]
|
||
MSG --> TQ{"提交目标"}
|
||
TQ -->|"优先"| TASKQUEUE["TaskQueue队列排队"]
|
||
TQ -->|"Fallback"| WORKERPOOL["WorkerPool直连"]
|
||
VALIDATE --> TQ
|
||
MYSQL --> TQ
|
||
TASKQUEUE --> CONSUMER["Consumer消费"]
|
||
WORKERPOOL --> SUBMIT["WorkerPool.Submit"]
|
||
CONSUMER --> SUBMIT
|
||
SUBMIT --> WORKER["Worker执行"]
|
||
WORKER --> PROGRESS["注入ProgressReporter"]
|
||
WORKER --> PIPELINE["Eino Pipeline执行"]
|
||
PIPELINE --> PROMPT["PromptOptimizer"]
|
||
PIPELINE --> ASSET["AssetGenerator"]
|
||
PIPELINE --> QUALITY["QualitySupervisor<br/>质检最多重试3次"]
|
||
PIPELINE --> FORMAT["FormatAdapter<br/>精灵表切割GIF预览"]
|
||
PROGRESS --> UPLOAD["上传素材七牛云"]
|
||
QUALITY --> UPLOAD
|
||
UPLOAD --> STATUS["更新MySQL状态"]
|
||
STATUS --> EVENTBUS["EventBus.Publish"]
|
||
EVENTBUS --> SSE["SSE推送"]
|
||
SSE --> BROWSER_SSE["浏览器EventSource<br/>实时接收进度"]
|
||
```
|
||
|
||
### 关键设计决策
|
||
|
||
> [!question] 思考:为什么 Gen2D 选择了异步任务 + SSE 推送的组合?
|
||
>
|
||
> 如果直接同步调用 Eino Pipeline,一个生成请求可能要等待 10~120 秒。在 HTTP 模型下,长时间占用的连接会耗尽服务器的并发能力。**异步提交 + SSE 推送**把「等待时间」从连接持有中解放出来——客户端收到 taskId 后可以自由离开,后续通过 SSE 长连接接收进度更新。这也是 Web 应用在 AI 场景下的标准模式。
|
||
|
||
| 决策 | 选择 | 理由 |
|
||
|------|------|------|
|
||
| 分层架构 | Handler-Service-Infra 三层 | 解耦各层职责,便于独立测试和替换 |
|
||
| 依赖注入 | Set*/Init* 函数 | 轻量、零依赖,项目规模可控 |
|
||
| 配置管理 | Viper 三层级联 | 容器化友好,零配置可启动 |
|
||
| 异步任务 | 提交-队列-消费-执行 | API 快速返回,长任务不阻塞请求 |
|
||
| 事件推送 | EventBus + SSE | 比 WebSocket 轻量,HTTP 原生支持 |
|
||
| 限流 | Redis 令牌桶 | 分布式一致,Fail-Open 保可用性 |
|
||
|
||
## 关联文档
|
||
|
||
- [[00-索引]] — 文档导航与架构总览图
|
||
- [[02-协程池]] — 有界并发与 per-user 限流
|
||
- [[03-任务队列]] — 可插拔队列接口与双实现
|
||
- [[04-RabbitMQ集成]] — 持久化消息与重试机制
|
||
- [[05-生成管线]] — Eino 4 阶段管线与质量回退
|