01. 企业场景题:项目追问与八股延伸(综合实战版)¶
面试里最难的不是八股本身,而是面试官从你的项目或者一道八股延伸出来的场景题。
这类题没有标准答案,但有标准的回答结构:
- 拆问题 — 这个场景本质在考什么?
- 分层答 — 从系统全局到局部细节,逐层展开
- 串知识 — 把涉及的知识点串起来,体现你的知识网络
- 提风险 — 主动补边界情况、异常路径和工程代价
下面按"系统设计类 → 性能优化类 → 故障排查类 → 数据一致性类"组织。
先把这一章的知识骨架搭起来¶
企业场景题的关键,不在于背标准答案,而在于形成一种稳定的拆题方法。因为这类题通常都是“项目 + 八股 + 系统设计 + 排障”混在一起,考的是 你如何在信息不完整的情况下做分析和决策。
因此这章建议你始终按“明确目标 → 找瓶颈或风险点 → 给分层方案 → 说明验证手段 → 讲清副作用和回滚”来应对。只要结构稳,场景再变,你也不至于被问乱。
进入场景题之前,先把答题框架固定下来¶
场景题最大的坑不是不会某个知识点,而是临场被问题带着跑。更稳的办法,是先把自己的答题骨架固定住:目标是什么、系统瓶颈或风险点在哪、有哪些分层方案、用什么指标验证、出了问题怎么回滚。
只要这套骨架稳定,你面对系统设计、性能优化、故障排查、一致性场景时,叙事都会比纯凭感觉更稳。
一、系统设计类场景题¶
场景 1:设计一个短链接服务¶
题目: 如何设计一个短链接生成和跳转服务?
回答思路:
1. 核心功能拆解:
- 长链接 → 短链接的映射生成
- 短链接 → 长链接的快速查询和 302 跳转
- 短链接的唯一性保证
- 过期和清理
2. 关键设计决策:
| 决策点 | 方案 | 理由 |
|---|---|---|
| ID 生成 | 自增 ID + Base62 编码 或 哈希截取 | Base62 编码短、可读;哈希截取要处理冲突 |
| 存储 | MySQL(持久化)+ Redis(热点缓存) | 写入量不大用 MySQL,读远大于写所以加缓存 |
| 跳转方式 | 301 永久重定向 或 302 临时重定向 | 302 更灵活(方便统计点击量),301 对 SEO 更友好 |
| 过期机制 | 记录创建时间 + TTL,定时清理 | 避免无限膨胀 |
3. 串联知识点:
- 哈希与冲突:如果用哈希方案,怎么处理冲突?→ 数据结构与算法
- 数据库索引:短链接字段需要唯一索引 → MySQL 索引
- 缓存策略:热点短链接走 Redis,缓存穿透怎么防?→ Redis 高可用
- HTTP 重定向:301 vs 302 的区别 → HTTP 详解
4. 主动补充:
- 高并发下 ID 生成怎么保证唯一?分布式 ID 方案(Snowflake 等)
- 防止恶意刷短链接:限流、黑名单
- 统计需求:点击量、地域分布、时间分布
场景 2:设计一个消息推送系统¶
题目: 如果让你设计一个支持千万级用户的消息推送系统,你怎么做?
回答思路:
1. 核心模块:
- 连接管理层:维护客户端和服务端的长连接(WebSocket / 自定义协议)
- 路由层:知道用户当前连接在哪台机器上
- 消息分发层:把消息投递到正确的连接
- 离线存储:用户不在线时消息暂存
- 补偿机制:消息发送失败的重试和确认
2. 关键难点:
| 难点 | 解决思路 |
|---|---|
| 连接管理 | 每台机器维护 N 个连接,用户上下线时更新路由表 |
| 路由发现 | Redis / etcd 存储 user_id → server_id 映射 |
| 消息可靠性 | ACK 确认 + 重试 + 消息 ID 去重 |
| 离线消息 | 写入消息队列或数据库,用户上线时拉取 |
| 推送顺序 | 单用户维度有序(用消息序列号),跨用户不保证全局序 |
3. 串联知识点:
场景 3:设计一个分布式定时调度系统¶
回答思路:
| 组件 | 职责 |
|---|---|
| 调度器 | 扫描到期任务,分发执行 |
| 执行器 | 实际运行任务逻辑 |
| 锁服务 | 保证同一时刻只有一个实例执行某个任务(Redis 分布式锁 / 数据库行锁) |
| 日志与监控 | 记录执行结果、耗时、失败原因 |
串联知识点:
二、性能优化类场景题¶
场景 4:接口 RT 从 50ms 涨到 500ms,怎么排查?¶
回答结构(从全局到局部):
- 先看监控大盘 — 个别接口还是全局?突发还是逐渐?有没有发布变更?
- 检查下游依赖 — 数据库慢查询?Redis 延迟?下游 RPC 超时?
- 检查应用层 — 线程池积压?内存分配异常?锁竞争?(火焰图 /
perf) - 检查基础设施 — 网络抖动?CPU/内存/磁盘 IO 打满?容器资源限制?
串联知识点:
- 进程、线程、内存 — 上下文切换
- IO 多路复用 — epoll 是否阻塞
- MySQL 事务与索引 — 慢查询和锁等待
场景 5:数据库查询特别慢,怎么优化?¶
- 定位 —
EXPLAIN看执行计划:type 是 ALL?扫描行数远大于结果集? - 索引层面 — 缺索引?索引失效?(函数操作列、隐式类型转换、OR、LIKE '%xxx')联合索引最左前缀?
- SQL 层面 — 减少 JOIN 表数?覆盖索引避免回表?深度 OFFSET 改游标分页?
- 架构层面 — 读写分离、缓存热点数据、大表水平拆分
串联知识点:
- SQL 基础 — SQL 语句优化
- MySQL 索引原理 — B+ 树、聚簇索引
- MySQL 事务与锁 — 锁等待、死锁
场景 6:QPS 突然翻倍,系统扛不住了¶
- 止血 — 限流(令牌桶/滑动窗口)、降级(非核心功能返回默认值)、熔断(下游不可用时快速失败)
- 定位 — 正常增长还是异常流量(爬虫、攻击)?哪个接口 QPS 最高?
- 扩容 — 水平扩容、缓存预热、异步化能异步的操作
三、故障排查类场景题¶
场景 7:线上 CPU 飙到 100%¶
top找 CPU 最高的进程top -Hp <pid>找 CPU 最高的线程perf top/ 火焰图 定位热点函数- 常见原因: 死循环、自旋锁竞争、频繁内存分配释放、正则回溯、CPU 密集计算
串联知识点:
场景 8:内存持续增长,疑似泄漏¶
top/ps确认 RSS 持续增长不回落- 工具: Valgrind(精确但慢)、AddressSanitizer(推荐 C++)、
pmap//proc/<pid>/smaps - 常见原因: new 没 delete、容器只增不删、缓存没淘汰、shared_ptr 循环引用、文件句柄没关
串联知识点:
四、数据一致性类场景题¶
场景 9:缓存和数据库数据不一致¶
| 策略 | 做法 | 问题 |
|---|---|---|
| Cache Aside | 读:先缓存 miss 查 DB 再写缓存;写:先更新 DB 再删缓存 | 并发下有短暂不一致窗口 |
| Write Through | 写入时同时更新缓存和 DB | 写延迟增加 |
| Write Behind | 写入缓存后异步刷 DB | 数据可能丢失 |
为什么"先删缓存再更新 DB"不好? 并发场景下另一个读请求可能在删缓存后、更新 DB 前读到旧数据写回缓存。
工程做法: Cache Aside + 合理 TTL 是最常见折中;高一致性场景用延迟双删或订阅 binlog。
场景 10:分布式事务怎么保证一致性?¶
| 方案 | 原理 | 适用场景 |
|---|---|---|
| 2PC | 协调者+参与者,先 Prepare 再 Commit | 强一致性,性能差 |
| TCC | Try-Confirm-Cancel,业务层实现 | 灵活但开发成本高 |
| Saga | 每步有补偿操作,失败逆序补偿 | 长事务,最终一致 |
| 消息事务 | 本地事务+消息队列 | 最常见的互联网方案 |
如何回答场景题的通用方法论¶
- 先确认问题边界 — "这个系统的 QPS 大概是多少级别?""需要强一致还是最终一致?"
- 从高到低分层讲 — 架构 → 核心模块 → 关键细节
- 主动提 Trade-off — "这个方案的优点是 XXX,代价是 XXX"
- 串联已有知识 — 让面试官看到你的知识不是孤立的
- 不要装 — 不确定的就说"这一块我了解有限,但我的理解是 XXX"