字节跳动后端实习一面

字节跳动 · 后端实习生 · 一面 · 2026-04

面试题目

系统架构

  1. controller / service / repository 三层架构各自的功能是什么?
  2. 各层之间如何交互?(依赖注入)
  3. 鉴权如何实现?(Spring Security,基于身份授权)

缓存与数据库

  1. 缓存和数据库的数据一致性如何解决?
  2. 为什么不先删缓存,而是先改数据库再删缓存?
  3. 缓存删除失败了怎么办?
  4. 缓存有 TTL 吗?大量 key 同时过期怎么办?(缓存雪崩)

MySQL

  1. 讲一下 MySQL 索引。(主键索引、唯一索引、B+ 树实现)
  2. 为什么用 B+ 树而不是其他数据结构?

操作系统

  1. 进程和线程的区别?线程之间哪些资源可以共享,哪些不能?
  2. 死锁的四个必要条件是什么?有哪些解决方式?
  3. CAS 和普通加锁各有什么优劣?
  4. 互斥锁和自旋锁的区别?

计算机网络

  1. TCP 和 UDP 的区别?
  2. TCP 为什么是三次握手、四次挥手?

算法手撕

  1. 求数组的最大连续子数组和(Leetcode 53,Kadane 算法)

脑筋急转弯

  1. 100 只老虎和 1 只羊,老虎吃了羊就变成羊,最后羊会不会被吃?

反问

  1. 面试官反馈:操作系统、数据库、网络、编程语言基础不够扎实;算法撕得快但讲不清楚思路。

参考解析

缓存一致性:先改数据库再删缓存

  • 先删缓存再更新数据库:删除缓存后、数据库更新前,其他请求回写旧值到缓存,造成脏数据,且窗口期较长。
  • 先更新数据库再删缓存:不一致窗口极短(仅数据库写完到缓存删除之间),是业界更推荐的方案(Cache-Aside 模式)。
  • 缓存删除失败:引入重试机制,可借助消息队列(如 RocketMQ/Kafka)做异步重试,保证最终一致性;也可结合 binlog 订阅(Canal)触发补偿。

缓存雪崩

  • 大量 key 同时过期导致请求全部打到数据库。
  • 解决:① TTL 加随机偏移量,错开过期时间;② 双 key 策略(逻辑过期 + 后台异步刷新);③ 熔断降级;④ 互斥锁防止缓存击穿。

B+ 树索引优势

  • 非叶子节点只存 key,单页可存更多索引项,树高更低,磁盘 IO 次数少。
  • 叶子节点通过链表相连,支持高效范围查询。
  • 相比 B 树,所有数据都在叶子节点,查询路径稳定,性能更可预测。

CAS vs 普通加锁

  • CAS 优点:无锁,避免线程挂起/恢复的上下文切换开销,适合竞争不激烈的场景。
  • CAS 缺点:① ABA 问题(可用版本号/戳解决,如 AtomicStampedReference);② 自旋空转浪费 CPU;③ 只能保证单个变量原子性。
  • 互斥锁适合临界区较长或竞争激烈的场景;自旋锁适合临界区极短、不希望线程切换的场景(如内核中断处理)。

死锁

  • 四个必要条件:互斥、持有并等待、不可剥夺、循环等待。
  • 预防:破坏任一条件,如资源有序分配(破坏循环等待)。
  • 避免:银行家算法,动态判断分配后是否安全。
  • 检测+解除:允许死锁发生,定期检测资源图,发现环后抢占/终止进程。

TCP 三次握手 / 四次挥手

  • 三次握手:确认双方收发能力均正常,同步双方 ISN,防止旧连接请求被误接受。两次不够(服务端无法确认客户端能收)。
  • 四次挥手:TCP 全双工,两个方向需独立关闭。服务端收到 FIN 后可能还有数据要发,ACK 和 FIN 不能合并,故比握手多一次。

最大连续子数组和(Kadane 算法)

  • 维护 cur(当前子数组和)和 ans(全局最大值)。
  • 遍历每个元素:cur = max(num, cur + num),若 cur 加上当前元素还不如从当前元素重新开始,则抛弃前缀。
  • ans = max(ans, cur),时间复杂度 O(n),空间 O(1)。

脑筋急转弯:老虎与羊

  • 核心逻辑:老虎吃羊变羊后,自己成为猎物。
  • 奇偶分析:若只剩 1 只老虎,它会吃羊(无后顾之忧);2 只时都不吃(吃了变羊会被另一只吃);依此类推,老虎数量为奇数时羊会被吃,偶数时羊安全。
  • 100 只(偶数)→ 羊不会被吃。