Files

9.0 KiB
Raw Permalink Blame History

Gen2D — Q&A

按模块分布编排,贴近实际答辩场景。每个 Answer 已精简适配 PPT 展示。


一、系统架构(Q1–Q4)

Q1:Gen2D 的整体架构是什么?

A:采用经典分层架构,从浏览器请求到外部依赖共六层:Gin HTTP Server → Handler → Service 层(Eino Pipeline)→ 基础设施层(协程池/队列/事件总线)→ 领域模型 → 外部依赖(MySQL/Redis/CDN/AI API)。各层职责清晰、可独立替换。

Q2:为什么选择异步任务 + SSE 推送的组合?

A:AI 生成耗时 10~120 秒,如果同步调用会耗尽服务器连接。异步提交让 API 快速返回 taskId,后续通过 SSE 长连接推送进度,客户端可以自由离开并在后台接收更新。

Q3:系统的依赖注入方式是什么?为什么没有使用 Wire/Fx 等框架?

A:采用轻量级的 Set*/Init* 函数注入,在 main.go 中约 220 行完成全部注入。项目规模可控,框架级 DI 的复杂度收益比不高。

Q4:配置管理是如何设计的?

A:使用 Viper 实现三层级联:环境变量 > YAML 配置文件 > 代码默认值。容器化部署时可通过环境变量覆盖,开发时使用 YAML 集中管理,零配置也可启动运行。


二、并发控制与协程池(Q5–Q8)

Q5:协程池的核心参数和默认值是什么?

A:Worker 数量 = NumCPU × 4,任务队列容量 = 100,单用户最大并发数 = 2。IO 密集型场景推荐 4 倍 CPU 核数。

Q6:什么是背压保护?Gen2D 为什么选择非阻塞拒绝而不是阻塞等待?

A:当协程池队列满时立即返回 ErrPoolFull 错误并返回 HTTP 503,而不是等待有空位。因为用户期望快速反馈,且 AI 生成场景中用户可以重新点击提交——这种短暂的操作成本远低于服务器因连接堆积导致的雪崩风险。

Q7:Per-user 限流的作用和实现机制是什么?

A:防止单个用户占满整个协程池。实现上在 Submit 时就增加 userActive 计数预留槽位,任务完成后释放。这样即使 channel 还未取出任务,也能保证槽位一致性。

Q8:协程池如何优雅关闭?

A:收到 SIGINT/SIGTERM 信号后,先停止接受新任务(consumeCancel),再通过 wg.Wait 等待所有正在执行的 Worker 完成,超时时间为 30 秒。超时则部分任务可能丢失。


三、任务队列(Q9–Q11)

Q9:任务队列的可插拔设计是什么意思?

A:定义了统一的 TaskQueue 接口(Submit/Consume/Close),支持 MemoryQueue 和 RabbitMQQueue 两种实现。通过配置中的 driver 字段一行切换,单机开发用内存队列,生产环境用 RabbitMQ。

Q10:MemoryQueue 和 RabbitMQQueue 的主要区别是什么?

A:MemoryQueue 零依赖但无持久化和重试,进程重启任务丢失;RabbitMQQueue 消息持久化到磁盘、支持失败重试和手动 ACK,适合多机部署的生产环境。

Q11:任务消息的结构中包含哪些关键字段?

A:包含 TaskID、UserID、ProjectID、Input(PipelineInput)、CreatedAt 和 RetryCount。其中 Input 直接嵌入管线输入结构,反序列化后可直接传入;RetryCount 用于判断是否超过最大重试次数。


四、生成管线(Q12–Q16)

Q12:生成管线的四个阶段分别是什么?

A:第一阶段 PromptOptimizer(提示词优化,纯 CPU <1ms),第二阶段 AssetGenerator(AI 出图,IO 密集 10-120s),第三阶段 QualitySupervisor(质量检查 1-5s),第四阶段 FormatAdapter(格式适配/Cut/GIF 1-3s)。

Q13:质量检测最多重试 3 次的策略依据是什么?

A:第 1 次失败通常是 LLM 波动或偶发噪声,重试大概率通过;第 2 次失败说明提示词不够精确,重新优化后改善;第 3 次仍失败表示当前参数确实无法生成合格图片。超过 3 次降级到 FormatAdapter——宁可降级不可阻塞。

Q14:AssetGenerator 的三级回退逻辑是什么?

A:优先使用任务级参考图进行图生图,其次使用工程级参考图 URL 下载后图生图,最后回退到纯文生图。任意一级失败都尝试下一级,确保任务不阻塞。

Q15:管线的安全机制有哪些?

A:包括三个层面——Eino Graph 设置 WithMaxRunSteps(20) 防止无限循环,WorkerPool 设置 context.WithTimeout(10min) 控制任务超时,以及 context.Canceled 支持优雅关闭时取消执行中的管线。

Q16:管线的全局状态是怎么管理的?

A:通过 Eino 的 WithGenLocalState 注入 PipelineState 全局状态对象,各节点通过 StatePreHandler / StatePostHandler 读写状态。状态包含原始输入、最终提示词、质检结果、重试次数和路由目标。


五、精灵图处理(Q17–Q19)

Q17:精灵图处理管线包含哪几个步骤?

A:背景移除(白底/绿幕)→ 投影检测分割 → MinFillRatio 过滤空白帧 → trimAlpha 裁剪透明边框 → padToLargest 底部居中对齐 → GIF 预览生成。

Q18:两阶段投影算法相比传统方法有什么优势?

A:传统全局投影会因为武器、尾巴、翅膀等突出物被其他行"稀释"导致切割不准。两阶段算法先用全局行投影检测水平间隙,再在每个行段内独立计算列密度——相当于把二维问题拆解为多个一维子问题,避免跨行干扰。

Q19:GIF Maker 的防鬼影机制如何实现?

A:设置 DisposalBackground,每帧渲染前清除前一帧的内容。同时设置调色板索引 0 为透明色,LoopCount=0 实现无限循环播放。


六、SSE 实时推送(Q20–Q22)

Q20:EventBus 的订阅模式有哪几种?

A:两种——Subscribe(taskID) 按任务订阅,Buffer 容量 16,用于单任务实时进度;SubscribeAll() 全局订阅,Buffer 容量 64,用于工程级查看所有任务的混合视图,在 Handler 层按 projectID 过滤。

Q21:为什么 EventBus 的 Publish 使用 non-blocking send?

A:使用 select default 模式,当消费者 channel 缓冲满时静默丢弃事件。这是为了防止慢消费者拖慢管线执行速度,保证 Pipeline 的处理效率不受 SSE 推送影响。

Q22:SSE 连接在什么条件下会自动关闭?

A:两种情况——收到终态事件(completed/failed)时自动关闭;客户端断开连接时通过 c.Request.Context().Done() 触发 Unsubscribe 并退出。


七、可观测性(Q23–Q25)

Q23:Gen2D 的可观测性体系覆盖哪些层面?

A:共 35 个 Prometheus 指标分为六大组——HTTP 层、限流层、任务队列层、协程池层、Pipeline 业务层、基础设施层。配套 3 个 Grafana 仪表盘(Overview/Pipeline/Infrastructure)和 10 条告警规则。

Q24:使用 FullPath() 而不是实际路径采集 HTTP 指标有什么用意?

A:使用路由模板 /api/v1/tasks/:taskId 而非实际路径 /api/v1/tasks/abc123,避免高基数标签导致 Prometheus 内存爆炸。

Q25:哪些告警是 Critical 级别需要立即处理的?

A:PipelineSuccessRateLow(成功率低于 90%)、RedisDown(连接池为零)、RabbitMQDisconnected(断连)和 HighErrorRate(5xx 错误率超 5%)。这些表示核心功能或服务健康度出现严重问题。


八、限流与降级(Q26–Q28)

Q26:双层限流的设计思路是什么?

A:全局限流在前先检查系统总体配额(如 24 小时 500 次),通过后检查用户限流(如 24 小时 15 次)。这样可以先防止单一用户耗尽全局资源,再在用户层面做精细控制。

Q27:为什么限流器选择 Fail-Open 而不是 Fail-Close?

A:在"偶尔超限"和"完全不可用"之间,优先保可用性。Redis 故障时放行请求,超出配额的用户后续可以通过账单追缴;如果选择 Fail-Close,Redis 故障会导致所有用户都无法使用服务。

Q28:三级降级链的第一、二、三级分别是什么?

A:第一级 TaskQueue(持久化排队 + 分布式能力),第二级 WorkerPool(有界并发 + 用户隔离),第三级 Legacy FIFO(零配置串行兜底)。每一级都是前一级功能的超集,降级过程渐进、服务始终可用。


九、提示词工程(Q29–Q30)

Q29:标签驱动提示词工程的工作原理是什么?

A:内置 40+ 预定义标签分为 7 大类别(内容类型、美术风格、色调配色、线条粗细、场景氛围、光照效果、情绪基调),每条标签映射到精确的图像生成指令。系统将这些指令与用户描述、风格约束和技术参数组装为三段式提示词。

Q30:为什么精灵图的网格布局需要特殊处理?

A:如果不指定间隙要求,AI 生成的图片往往人物之间几乎没有空隙——人类艺术家为了最大化利用画布这样做,但机器无法从中推断分割边界。强制纯白间隙等于人为制造"裂缝",让投影检测算法可以可靠地分离每帧内容。