12 口袋速背卡片(考前只看这一篇)
用法:面试前 30 分钟只看这页。全部是"能直接念出口"的短句,不要背细节,背骨架和数字。 细节想不起来时,回忆它属于哪张卡片,用骨架把话讲圆。
一、主线口述(90 秒,必须能一口气说完)
我做的项目是鲨堂 AI,一个电商 AI 视频生成平台,已上线 shatang.top。 业务上是"上传商品图 + 文案 → 出成片短视频",支持 14 种生成方式。 技术上它的本质是个调度器——自己不生产视频,而是把任务编排到外部 AI 供应商上,所以核心是三件事:任务别丢、状态别乱、钱别错。 我负责三块: 一是任务编排:把视频状态轮询从进程内定时器改成 BullMQ 队列,提交和轮询分成两条队列(提交几秒、轮询几分钟,拆开才不会占死并发槽位);轮询间隔用前密后疏的间隔表退避,并加了 2 小时硬超时——之前没有终止条件,是我们一次线上"假 DDoS"的成因之一。 二是任务全生命周期:状态机落库(
pending/queued/processing/done/failed/cancelled+phase细分),加启动 + 每 10 分钟双轨崩溃恢复:按"有没有拿到供应商任务号"分两条路处理,并且启动时强制覆盖僵尸 job、周期巡检时跳过活跃 job。 三是积分一致性:每次生成前冻结积分,credit_holds上有一条部分唯一索引(task_id) WHERE status='held'——同一任务最多一条活跃冻结,从数据库层面杜绝重复扣减;另外有小时级对账巡检抓五类异常。 规模上是 2,500+ 提交、后端 15 万行 TypeScript、135 组数据库迁移、349 个测试文件。
二、12 个数字卡(报数字时一定要带"所以")
| 数字 | 说法(带上下文,不要干报) |
|---|---|
| 9 条 | 9 条 BullMQ 队列;最关键是 video-generate(提交,并发 2)和 video-poll(轮询,并发 10) |
| 2 小时 | 轮询硬超时,且由间隔表反推(MAX_POLL_ATTEMPTS = 243)——因为改间隔表不能让超时悄悄变成别的值 |
| 10 分钟 | 周期巡检间隔(兜底层,正常路径不该依赖它) |
| 5 分钟 | 恢复时的"新鲜度保护":updated_at 在 5 分钟内的任务一律跳过,不误杀刚提交的任务 |
| 10 / 30 秒 | 冻结悬空判定 10 分钟;对账巡检把"held 超 30 分钟"算悬挂 |
| 1 条 | credit_holds 上的部分唯一索引:同一任务最多 1 条 held |
| 6 / 1 | 历史接入过 6 家视频供应商,当前新任务只走 1 家(腾讯云 VOD) |
| 14 种 | 独立生成方式(导航 19 个标签里) |
| 135 组 | 数据库迁移(.up/.down 成对),自研迁移系统带 checksum 校验 |
| 349 个 | 后端测试文件(约 3200 用例);前端 221 个、后台 18 个 |
| 1348 次 | PixelCountTooSmall 在生产日志里的出现次数,是第二名的 70 倍 → 最大损耗是素材预处理而不是模型 |
| 37 单 / 370 分 | 一次重复扣费事故的量级(14 个用户)→ 幂等判断只查了一半凭证 |
三、十个必答(一问一答,脱口而出)
- "讲一下这个项目" → 见第一节 90 秒版。
- "最难的问题是什么" → 「假 DDoS」:轮询没有终止条件 + 前端 3 秒轮询放大器,我们自己把 Redis/DB 打满(见
09故事 1)。 - "为什么提交和轮询要拆两条队列" → 时间尺度差两个数量级:提交几秒、结果几分钟。混在一起,并发 2 就意味着全站同时只能有 2 个视频在生成。拆分的本质是让占用槽位的时长和任务真实耗时解耦。
- "怎么防重复扣费" → 数据库约束:
credit_holds部分唯一索引 +ON CONFLICT ... WHERE status='held' DO NOTHING,冲突就整事务回滚;结算/退款是WHERE status='held'的 CAS,天然幂等。 - "并发怎么不超扣" → Redis 分布式锁只是护栏(拿不到不阻断),真正串行化靠 PG 行锁
SELECT ... FOR UPDATE;隔离级别用默认的 READ COMMITTED,因为行锁会重读最新版本,够用。 - "崩溃恢复怎么做" → 扫非终态任务,按有无外部任务号分支;重投前先给 5 分钟新鲜度保护;supplier 状态
processing时不做重活,只转轮询;启动强制覆盖、周期跳过 active。 - "那些自管任务为什么不能进恢复逻辑" → 状态在内存里、占位行长得一样,落进去会被标失败清积分、或拿空 prompt 烧钱出废片。
- "多段一致性怎么保证" → 四层:尾帧→首帧锚、尾帧定格约束、音色锚、提示词承接块。但要补:腾讯通道在有参考图时会把首尾帧降级成参考图。
- "钱和状态怎么保证都对" → 三层:加锁层(Redis + 行锁)、约束层(部分唯一索引 + 流水)、巡检层(五类异常只读对账)。外加一条硬顺序:先写业务终态,最后才动钱。
- "有没有做过什么小而有价值的改进" → 失败原因:原来固定写"供应商返回任务失败",是生产
error_message里出现最多的一条(近 60 天 21 次),真实原因全丢;改成失败时再问一次上游取原文 + 前端用前后端共用词典翻译成"审核/素材/我们的/计费"四类。
四、六个缺陷(主动交底,别等人挖)
- 没有备份、没有 PITR —— 而这张库是资金账本,单卷丢失 = 不可恢复。(最大的一个)
- CI 停摆 —— 只有后端单测一个 job,且因账户欠费从 2026-08-08 起实际未执行;
pre-pushhook 因core.hooksPath未设置也没装。测试资产不缺,缺卡口。 - 没有可观测性基建 —— 无 metrics / 无 request id / 无 APM,pm2 日志 1.8GB 无轮转,告警靠人肉 grep
[ALERT]。 - 两套冻结语义并存 ——
holdCredits是真冻结,consumeUserCredits是立即扣减 + 事后补日志,后者有"已扣款未建任务"的追不回窗口。 - 流水表的
ON CONFLICT是空转 —— 缺唯一索引支撑,真幂等只靠credit_holds。 - 支付侧无退款、无上游对账;微信回调缺金额校验(支付宝有,不对称)。
- 自管链路靠 if 分支维持清单 —— 应改为显式的执行类型标识。
- 内存自管任务无法水平扩展 —— 多副本部署会状态不一致。
(挑 3 条讲,剩下的留给面试官挖。)
五、三个反问(收尾用)
- 「你们 AI 视频链路单条成片的 P99 延迟是什么量级?瓶颈在模型侧还是后处理拼接这一侧?」
- 「长耗时异步任务,你们是自研编排还是用现成队列?失败任务的额度/积分回滚怎么保证不重不漏?」
- 「如果我进来,前三个月你们最希望我补的是哪一块?」
六、雷区表(念错就翻车)
| ❌ 不能说 | ✅ 应该说 |
|---|---|
| "数据库用 MySQL" | PostgreSQL 17;早期短暂用过 MySQL,5 月中旬整体切换(因为要部分唯一索引 / JSONB / plpgsql 触发器) |
| "6 个供应商都在用" | "历史接入过 6 家,当前新任务只走腾讯云 VOD;老实现保留是为了在途任务能轮询" |
| "所有生成都走 BullMQ" | "统一的任务队列与轮询调度;主流链路是路由直接调供应商 + 进轮询队列,还有 3 条链路是内存自管" |
| "Docker Compose 一键部署" | "PG/Redis 用 compose 起,应用是 pm2 + nginx,发布走自研的零静默失败脚本" |
| "引用计数保护" | "引用存在性判定(oss_key_in_use() 跨十几张表)+ 触发器 + 唯一约束 + 30 天延迟删除" |
| "首尾帧桥接保证连贯" | "接口支持;但腾讯通道有参考图时会降级成参考图,爆款复刻链路是显式关闭的" |
| "TS 全栈类型安全 / 零错误" | "全栈统一 TypeScript,类型强度分层:只有管理后台开 strict 并挂构建,后端还有 54 个 @ts-nocheck" |
| "我独立从 0 到 1 做的" | "团队项目,我主导任务恢复与巡检、轮询队列、积分冻结内核、微信支付/登录这几块" |
| "我们做了充分的对账" | "内部对账巡检做了(五类异常);与上游渠道的对账单没做" |
七、三个记忆锚点(任何问题都能往回收)
- 提交与轮询分离 —— 队列并发度必须匹配任务的资源占用模型。
- 部分唯一索引防重复扣费 —— 用数据库约束而不是应用层判断来兜住不变式。
- 权威状态在服务端,不在浏览器 —— 一次 68 小时事故换来的结论。
八、答不上来时的三句话
- 真不会 → 「这一层我没做到源码级。我知道的边界是 X,回去我会先看 Y。」(绝不硬编)
- 数字类 → 「我没有可信基线,所以不编数字——但我可以说清怎么设计评估、瓶颈在哪。」
- 质疑 AI 生成 → 「是 AI 辅助。我把住的是设计决策和验证责任——轮询超时、部分唯一索引、启动/周期的恢复差异,这些是从踩坑里长出来的判断。」
九、考前最后 5 分钟 checklist
- [ ] 90 秒主线能一口气讲完,不卡壳
- [ ] 12 个数字能说出"所以呢"
- [ ] 三个记忆锚点能脱口而出
- [ ] 雷区表 9 条都记住了(尤其 PostgreSQL 和 6 家/1 家)
- [ ] 三个缺陷能主动交底(没备份 / CI 停摆 / 没可观测性)
- [ ] 两个故事讲透(假 DDoS、68 小时悬挂)
- [ ] 反问准备了 2 个
- [ ] 想好"我负责哪几块"的边界说法