Skip to content

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 个用户)→ 幂等判断只查了一半凭证

三、十个必答(一问一答,脱口而出) ​

  1. "讲一下这个项目" → 见第一节 90 秒版。
  2. "最难的问题是什么" → 「假 DDoS」:轮询没有终止条件 + 前端 3 秒轮询放大器,我们自己把 Redis/DB 打满(见 09 故事 1)。
  3. "为什么提交和轮询要拆两条队列" → 时间尺度差两个数量级:提交几秒、结果几分钟。混在一起,并发 2 就意味着全站同时只能有 2 个视频在生成。拆分的本质是让占用槽位的时长和任务真实耗时解耦。
  4. "怎么防重复扣费" → 数据库约束:credit_holds 部分唯一索引 + ON CONFLICT ... WHERE status='held' DO NOTHING,冲突就整事务回滚;结算/退款是 WHERE status='held' 的 CAS,天然幂等。
  5. "并发怎么不超扣" → Redis 分布式锁只是护栏(拿不到不阻断),真正串行化靠 PG 行锁 SELECT ... FOR UPDATE;隔离级别用默认的 READ COMMITTED,因为行锁会重读最新版本,够用。
  6. "崩溃恢复怎么做" → 扫非终态任务,按有无外部任务号分支;重投前先给 5 分钟新鲜度保护;supplier 状态 processing 时不做重活,只转轮询;启动强制覆盖、周期跳过 active。
  7. "那些自管任务为什么不能进恢复逻辑" → 状态在内存里、占位行长得一样,落进去会被标失败清积分、或拿空 prompt 烧钱出废片。
  8. "多段一致性怎么保证" → 四层:尾帧→首帧锚、尾帧定格约束、音色锚、提示词承接块。但要补:腾讯通道在有参考图时会把首尾帧降级成参考图。
  9. "钱和状态怎么保证都对" → 三层:加锁层(Redis + 行锁)、约束层(部分唯一索引 + 流水)、巡检层(五类异常只读对账)。外加一条硬顺序:先写业务终态,最后才动钱。
  10. "有没有做过什么小而有价值的改进" → 失败原因:原来固定写"供应商返回任务失败",是生产 error_message 里出现最多的一条(近 60 天 21 次),真实原因全丢;改成失败时再问一次上游取原文 + 前端用前后端共用词典翻译成"审核/素材/我们的/计费"四类。

四、六个缺陷(主动交底,别等人挖) ​

  1. 没有备份、没有 PITR —— 而这张库是资金账本,单卷丢失 = 不可恢复。(最大的一个)
  2. CI 停摆 —— 只有后端单测一个 job,且因账户欠费从 2026-08-08 起实际未执行;pre-push hook 因 core.hooksPath 未设置也没装。测试资产不缺,缺卡口。
  3. 没有可观测性基建 —— 无 metrics / 无 request id / 无 APM,pm2 日志 1.8GB 无轮转,告警靠人肉 grep [ALERT]。
  4. 两套冻结语义并存 —— holdCredits 是真冻结,consumeUserCredits 是立即扣减 + 事后补日志,后者有"已扣款未建任务"的追不回窗口。
  5. 流水表的 ON CONFLICT 是空转 —— 缺唯一索引支撑,真幂等只靠 credit_holds。
  6. 支付侧无退款、无上游对账;微信回调缺金额校验(支付宝有,不对称)。
  7. 自管链路靠 if 分支维持清单 —— 应改为显式的执行类型标识。
  8. 内存自管任务无法水平扩展 —— 多副本部署会状态不一致。

(挑 3 条讲,剩下的留给面试官挖。)


五、三个反问(收尾用) ​

  1. 「你们 AI 视频链路单条成片的 P99 延迟是什么量级?瓶颈在模型侧还是后处理拼接这一侧?」
  2. 「长耗时异步任务,你们是自研编排还是用现成队列?失败任务的额度/积分回滚怎么保证不重不漏?」
  3. 「如果我进来,前三个月你们最希望我补的是哪一块?」

六、雷区表(念错就翻车) ​

❌ 不能说✅ 应该说
"数据库用 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 做的""团队项目,我主导任务恢复与巡检、轮询队列、积分冻结内核、微信支付/登录这几块"
"我们做了充分的对账""内部对账巡检做了(五类异常);与上游渠道的对账单没做"

七、三个记忆锚点(任何问题都能往回收) ​

  1. 提交与轮询分离 —— 队列并发度必须匹配任务的资源占用模型。
  2. 部分唯一索引防重复扣费 —— 用数据库约束而不是应用层判断来兜住不变式。
  3. 权威状态在服务端,不在浏览器 —— 一次 68 小时事故换来的结论。

八、答不上来时的三句话 ​

  1. 真不会 → 「这一层我没做到源码级。我知道的边界是 X,回去我会先看 Y。」(绝不硬编)
  2. 数字类 → 「我没有可信基线,所以不编数字——但我可以说清怎么设计评估、瓶颈在哪。」
  3. 质疑 AI 生成 → 「是 AI 辅助。我把住的是设计决策和验证责任——轮询超时、部分唯一索引、启动/周期的恢复差异,这些是从踩坑里长出来的判断。」

九、考前最后 5 分钟 checklist ​

  • [ ] 90 秒主线能一口气讲完,不卡壳
  • [ ] 12 个数字能说出"所以呢"
  • [ ] 三个记忆锚点能脱口而出
  • [ ] 雷区表 9 条都记住了(尤其 PostgreSQL 和 6 家/1 家)
  • [ ] 三个缺陷能主动交底(没备份 / CI 停摆 / 没可观测性)
  • [ ] 两个故事讲透(假 DDoS、68 小时悬挂)
  • [ ] 反问准备了 2 个
  • [ ] 想好"我负责哪几块"的边界说法

持续学习,持续构建。