--- 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["中间件链
Logger / Recovery / Metrics / Auth / RateLimit"] end subgraph Handler["Handler 层"] GH["Generate"] SH["SSE"] PH["Prompt"] OH["其他 Handler"] end subgraph Infra["基础设施层"] WP["WorkerPool
协程池"] TQ["TaskQueue
Memory / RabbitMQ"] EB["EventBus
Pub/Sub"] RL["RateLimiter
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["环境变量
GEN2D_*"] -->|"最高优先级"| VIPER["Viper"] YAML["YAML 配置文件
config.yaml"] -->|"中等优先级"| VIPER DEFAULT["代码默认值
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["浏览器
POST /api/v1/generate"] --> GIN["Gin中间件链"] GIN --> HANDLER["Handler.Generate"] HANDLER --> VALIDATE["参数绑定校验"] HANDLER --> MYSQL["保存任务MySQL
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
质检最多重试3次"] PIPELINE --> FORMAT["FormatAdapter
精灵表切割GIF预览"] PROGRESS --> UPLOAD["上传素材七牛云"] QUALITY --> UPLOAD UPLOAD --> STATUS["更新MySQL状态"] STATUS --> EVENTBUS["EventBus.Publish"] EVENTBUS --> SSE["SSE推送"] SSE --> BROWSER_SSE["浏览器EventSource
实时接收进度"] ``` ### 关键设计决策 > [!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 阶段管线与质量回退