面灵AI→

字节面经-字节跳动后端开发岗面经-17

轮次
面试合集
时间
2026-10
来源
牛客网

《面试题目》

(面经 01)

  1. 算法题:LeetCode 152 乘积最大子数组
  2. 请先做一个自我介绍,重点讲一下后端相关经历。
  3. 三个项目中,你参与最深的是哪一个?
  4. 原因是什么?
  5. 请讲一下项目整体架构,并按用户请求链路进行说明。
  6. 项目中的 12 个微服务是如何拆分的?
  7. 拆分思路是什么?
  8. 项目为什么同时使用 OpenFeign 和 Dubbo?
  9. 请介绍一下项目中的秒杀系统。
  10. Redis 扣库存成功后,如果后续订单创建失败,你会如何处理?
  11. RabbitMQ 在项目中解决了什么问题?
  12. 如何保证消息可靠性?
  13. RabbitMQ 出现大量消息积压时,处理方案是什么?
  14. 如果系统流量突增 10 倍,你会如何保障系统稳定?
  15. 请讲一下线程池的核心参数和执行流程。
  16. volatile 保证什么?
  17. 为什么无法保证 i++ 线程安全?
  18. ConcurrentHashMap 线程安全的原理是什么?
  19. JDK1.7 与 8 有哪些差异?
  20. Redis 为什么快?
  21. 单线程模型与 IO 多路复用原理是什么?
  22. 缓存穿透、击穿、雪崩分别是什么?
  23. 解决方案有哪些?
  24. MySQL 为什么选用 B+ 树?
  25. 什么是聚簇索引、回表、覆盖索引?
  26. 线上 SQL 耗时从 20ms 突增到 2s,排查思路是什么?
  27. 请设计一个 TikTok 直播间点赞系统。
  28. LeetCode 200:岛屿数量。
  29. 你有什么想要了解团队或岗位的问题?

(面经 02)

  1. 自我介绍
  2. 实习项目里,你负责了什么部分,你是独立开发还是也完成了需求对齐?
  3. 实习项目上线以后,减少了多少人工重复维护的任务,有具体数据吗?
  4. 是如何避免同步故障阻断核心业务的?
  5. 失败的任务,修改失败的原因一般会有哪些?
  6. 单号冲突检验、催办功能,催办只是发送信息吗?
  7. 外部服务降级是平台做的吗?
  8. 具体是怎么样的?
  9. 诊断工具开发和网易原有的工具相比怎么样?
  10. 你的项目里如果对消息队列进行选型和设计你会考虑哪些方面?
  11. 项目里如果在第一次发起请求,返回 429 错误,再切换模型时,怎么避免重复生成和重复计费?
  12. MCP、Skill、Harness 的理解
  13. 场景题:在浏览器里输入百度的域名,然后在百度搜索框输入关键词进行搜索,到最后页面显示,中间经过了哪些?
  14. 手撕:力扣 3 无重复字符的最长字串

(面经 03)

  1. RAG 项目召回的准确度有多高?
  2. 物流测试的文档整体有多大呢?
  3. 怎么再提升召回率?
  4. MySQL 数据库如果出现慢查询,你会怎么办?
  5. 讲一个你比较了解的一种设计模式在 Spring 里应用的。
  6. 你掌握几门语言?
  7. 现在让你学习新一门新语言,你会有什么路径去学习?
  8. 高并发内容互动营销平台这个项目里面,这里缓存是具体做什么功能的?
  9. 数据先存到缓存中,然后怎么同步到数据库?
  10. 实际的扣减,它的反馈可能是先从数据库里面加,然后再往 Redis 同步对吧?
  11. 如果这两个操作同时发生的话,就是会出现一些就是不一致的场景吗?
  12. 服务本身可能会承受很多很多流量,比如说秒杀一个商品它有 10 个库存,现在来了 1 万 QPS,你这个怎么保证你这服务的稳定性?
  13. 手撕:最长有效连续括号子串

(面经 04)

  1. 在性能测试中,你是如何与 AI 模型进行协作的?
  2. 使用了哪些具体的 Prompt 技巧?
  3. 为什么要选择 Plan-Execute-Replan 架构?

《参考解析》

秒杀:Redis 预扣减、缓存一致性、10 个库存扛 1 万 QPS

核心是把「库存」当成预占而不是扣减。Redis 用 Lua 脚本把「判断库存 + 预扣减」做成原子操作,避免高并发下的超卖;扣减成功的请求只负责把消息投进 MQ 并立刻给用户返回「排队中」,订单由消费者异步创建。如果订单创建失败,不能靠「把库存加回去」这种补救式操作,而要三段状态化:预占 → 确认 → 释放——失败进重试队列,超过上限发释放消息按幂等键回加;再叠一条超时未支付自动关单并回补库存的延时任务。缓存与数据库同步走 Cache Aside:读时先缓存后数据库再回填,写时先更新数据库、再删除缓存(不是更新缓存),删除失败靠重试或 binlog 订阅兜底。两个操作同时发生确实会不一致:读请求在「未命中 → 查库拿旧值 → 回填」的窗口里,写请求完成了更新和删缓存,旧值被写了回去;概率低的场景靠过期时间兜底,严格的场景延时双删或加版本号。

流量突增 10 倍的稳定性保障

分四层回答,从离用户近的地方往后排。① 入口层:CDN 挡住静态资源,网关按用户 / 接口 / 业务维度限流(令牌桶或滑动窗口),超限直接返回兜底页或排队页。② 应用层:无状态服务快速扩容,先把最容易被拖垮的依赖隔离(线程池或信号量),非核心链路(推荐、弹幕、个性化)降级关掉,只保下单主链路。③ 缓存层:热点数据多级缓存,防击穿用 singleflight 或互斥重建,防雪崩给过期时间加随机抖动并做预热。④ 存储层:读写分离、分库分表路由、把同步写改成消息异步化削峰。最后要落回容量摸底:压测出来的单机 QPS 上限乘机器数才是真实水位,超过就排队而不是硬扛——宁可让用户多等 200ms,也别让雪崩扩散到全站。

RabbitMQ 可靠性、积压处理与 MQ 选型

可靠性拆三段答:生产者不丢用 confirm 加本地消息表 / 事务消息,失败重发;Broker 不丢开持久化(队列持久化 + deliveryMode=2)并用镜像队列或 Quorum 队列;消费者不丢关掉自动 ack,业务成功后再手动 ack,失败进死信队列配重试与告警。消费侧必须幂等——MQ 只保证 at-least-once,重复投递是常态。积压先定位原因:消费端挂了就修并扩容;消费太慢就提并发、批量拉取、把重逻辑异步化;突发流量临时加机器并给队列设 TTL 加死信兜住过期消息;如果积压的是毒消息或超大消息,直接转死信别让它反复重投。选型维度:吞吐、延迟、顺序、投递语义、持久化与可靠性、堆积能力、延时消息、事务消息、运维成本与生态——Kafka 赢在吞吐与顺序写,RabbitMQ 赢在路由灵活和低延迟,RocketMQ 赢在事务与延时消息,Pulsar 赢在存算分离与多租户。

Java 并发:线程池、volatile 与 i++、ConcurrentHashMap

线程池七个核心参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。执行流程是「核心线程未满建核心线程 → 队列未满入队 → 未到最大线程数建非核心线程 → 再满触发拒绝策略」。要主动说队列选择的后果:用无界 LinkedBlockingQueue 时 maximumPoolSize 永远用不上,任务会一直堆到 OOM,生产上必须用有界队列配明确策略(CallerRunsPolicy 天然背压,AbortPolicy 配降级)。volatile 保证可见性与有序性(内存屏障禁止重排),不保证原子性。i++ 是「读—改—写」三步,两个线程可能同时读到 1 再各自写回 2,所以要用 AtomicInteger 的 CAS 或加锁。ConcurrentHashMap 1.8 是「CAS 插空桶 + synchronized 锁桶头」,读不加锁(Node 的 val 与 next 是 volatile),计数用 baseCount 加 CounterCell 分散热点;1.7 是 Segment 分段锁,并发度等于段数。整条演进主线就是锁粒度一路降低。

JDK 1.7 与 1.8 的差异

面试里几乎一定是问 HashMap 和 ConcurrentHashMap。HashMap:1.7 是数组加链表、头插法;1.8 引入红黑树(链表长度到 8 且数组长度 ≥ 64 才树化,退化阈值 6),改成尾插,扩容时用 hash & oldCap 把链表拆成高低位两条,不用重新算 hash。头插改尾插解决的是并发扩容成环导致 CPU 打满,但 1.8 并发 put 仍会丢数据。ConcurrentHashMap:1.7 用 Segment 继承 ReentrantLock 做分段锁,默认 16 段;1.8 丢掉分段锁,改成 CAS 加 synchronized 锁单个桶头,并发粒度降到桶级,并用 baseCount + CounterCell[] 分散计数热点,扩容还支持多线程协同迁移(ForwardingNode 标记已迁移的桶)。另外 1.8 的很多集合类内部从 Entry 换成了 Node,方法语义(比如 computeIfAbsent)也补齐了一批。

Redis 为什么快、IO 多路复用、缓存三大问题

快的来源有五个:纯内存操作、单线程避免锁竞争与上下文切换、基于 epoll 的 IO 多路复用、高度优化的数据结构(跳表、listpack、渐进式 rehash)、协议简单且支持 pipeline。IO 多路复用的原理是把「谁有数据可读」交给内核:epoll 用红黑树管理被监听的 fd、用就绪链表返回活跃连接,主线程只在事件循环里处理就绪连接,不必为每个连接开线程或轮询所有 fd。要补边界:Redis 6 之后网络读写改成了多线程,但命令执行仍是单线程,所以 keys、大 hgetall 这类慢命令照样阻塞整个实例。缓存三大问题:穿透是查不存在的数据,用空值缓存、布隆过滤器、参数校验挡;击穿是单个热 key 过期瞬间打穿到库,用逻辑过期、互斥重建、singleflight;雪崩是一批 key 同时失效或缓存层整体挂掉,用过期时间加抖动、多级缓存、限流熔断和预热。

MySQL 索引与慢 SQL 排查

选 B+ 树而不是 B 树或哈希,是因为它同时满足三件事:树矮(非叶子节点只存键和指针,16KB 页能放下几百个键,三层就覆盖千万级数据)、支持范围查询(叶子节点间有双向链表,between / order by 可顺序扫描)、查询稳定(数据全在叶子节点,任何一次查找 IO 次数相同)。InnoDB 的主键索引是聚簇索引,叶子节点直接放整行;二级索引叶子节点只放主键值,查非索引列时要拿主键回主键树再查一次,即回表;查询列全在索引里就不用回表,这是覆盖索引。慢 SQL 排查按「先定范围再分层收敛」:看监控定位拐点时间并与变更记录对齐 → EXPLAIN 看 type 是否掉到 ALL、key 是否选错、有没有 filesort / temporary → 常见根因是统计信息过期、隐式类型转换或对索引列做函数运算导致索引失效、数据量增长、锁等待、缓冲池命中率下降 → 先止血(加索引、改写、限流),再定位根因(拆表、加缓存、改结构),最后补监控与前后对比。

TikTok 直播间点赞系统设计

先明确量级与语义:热门直播间峰值每秒几十万次点赞,但点赞允许最终一致、容忍少量丢失,这是整套设计的起点。① 客户端聚合——前端把连点攒成批量(每 200ms 或每 20 次提交一次),从源头把 QPS 砍掉一到两个数量级,用户侧用本地计数立刻给出反馈。② 接入层削峰——网关只做鉴权与限流,把点赞写进 Kafka 这类高吞吐队列后立即返回。③ 聚合层——消费者按 roomId 分片,用 Redis INCRBY 累加增量,用分片 Set 或 HyperLogLog 做用户去重与每日次数上限校验。④ 落库与展示——增量按分钟窗口批量写回 MySQL / HBase,直播间总数从 Redis 读,弹幕与动效走另一路推送。要主动说的坑:热点房间会让单个分片打爆,所以按 roomId 哈希后再做一层本地预聚合;「一人一天只能点 N 次」这类校验必须用 Lua 或原子操作保证,不能放在应用层判。

微服务拆分、OpenFeign 与 Dubbo 并存、同步故障隔离

拆分依据是业务边界 + 变更频率 + 数据归属,不是按技术分层。讲清「按领域拆(用户、商品、订单、库存、支付、营销)、每个服务独占自己的库、服务间只通过接口通信」,再点出拆过细的代价(分布式事务、链路变长、联调成本)就够了。Feign 与 Dubbo 并存的合理解释是:Feign 走 HTTP + JSON,跨语言、易调试,适合对外或低频调用;Dubbo 走 TCP 自定义协议(3.x 也支持 Triple/gRPC),序列化紧凑、连接复用,适合内部高频调用;代价是两套注册发现与治理链路,所以按调用频次和团队习惯分组,而不是全都上。同步故障隔离的抓手是:显式超时(且上游 > 下游)、只对幂等读接口重试并配指数退避与抖动、用熔断器在失败率超阈值时快速失败、用线程池或信号量隔离不同依赖、非核心调用改异步消息、每个外部依赖都准备降级返回值。任务重试要按原因分类:超时与网络抖动可重试,参数错误和业务校验失败重试没意义,直接进人工队列。

429 切换模型时如何避免重复生成和重复计费

本质是分布式幂等 + 一次会话只允许一个有效结果。① 每次请求生成全局唯一的 requestId,把「用户 + 会话 + 轮次」当作幂等键;② 调模型前先落一条「生成中」的状态记录,重复请求先查状态,命中「生成中」就让前端重连已有流,而不是重新发起;③ 切换模型重试必须带同一个幂等键,由模型网关据此判断是否已产生过计费结果;④ 流式断点续传——已推给前端的 token 按 chunk 序号落盘,重试只在没有产出时重新生成,已产出部分既不重复生成也不重复计数;⑤ 计费以「最后一次成功结果」为准,用唯一约束(幂等键 + 状态=成功)在库层面挡住重复写入,失败的调用单独记账做对账。一句话总结:重试的是调用,不是结果。

AI 工程:RAG 召回率、MCP/Skill/Harness、Plan-Execute-Replan 与 ReAct

RAG 召回率先量化再优化:建「问题 → 正确 chunk」的评测集,分开看召回率与准确率,并报清文档规模(篇数、原始格式、切分后 chunk 数、总 token)。提升顺序是:按语义或标题层级切分并留重叠、向量加 BM25 的混合检索(专有名词靠关键词)、query 改写与 HyDE、加 rerank 精排、元数据过滤、多带几条邻接 chunk。召回上不去时先查数据有没有进库、切分有没有把答案切断,再谈换模型。MCP 是模型与外部工具之间的标准协议,解决工具如何被统一描述与调用;Skill 是写给模型的任务级作业指导(流程、知识、约束),本身不提供能力;Harness 是包在模型外面的运行外壳——循环、状态、上下文装配、工具执行、重试、预算与观测。ReAct 边想边做、每步依赖上一轮观测,灵活但长任务易跑偏、上下文膨胀快;Plan-Execute-Replan 先出计划再分步执行,失败时带着失败证据回到计划层重规划,适合步骤多、依赖强、可验收的任务,代价是多一次规划开销、对环境变化的反应慢一些。

浏览器从地址栏到搜索结果页的完整链路

分层说才不会漏。① URL 解析与本地缓存检查:查浏览器缓存、Service Worker、DNS 缓存,HSTS 列表决定是否强制 https。② DNS 解析:本地 hosts → 系统缓存 → 递归解析器 → 根域 → .com 顶级域 → baidu.com 权威服务器,拿到 IP(常见 CDN 的 CNAME 再到真实源)。③ 建立连接:TCP 三次握手,若为 https 再走 TLS 握手(ClientHello、证书链校验、密钥协商、Finished);HTTP/2 或 HTTP/3 会复用连接或直接走 QUIC。④ 发请求:带 Cookie、UA、Accept 等头,经 CDN / 负载均衡 / 网关到应用服务器,命中的缓存直接返回。⑤ 服务端处理:路由、鉴权、查询(缓存加数据库)、渲染 HTML 后响应。⑥ 浏览器渲染:解析 HTML 建 DOM、解析 CSS 建 CSSOM、合成渲染树、布局、绘制、合成上屏,JS 可能阻塞解析并触发二次渲染。⑦ 输入关键词搜索:前端再发一次异步请求到搜索接口,服务端走查询理解、召回、排序后返回结果,前端渲染结果页,同时埋点上报。