字节跳动暑期后端一面(移动OS部门)
面试题目
基本情况
- 部门:移动 OS
- 面试时长:约1小时
自我介绍与项目
- 自我介绍
- 介绍一段实习经历
- 用的都是 Java 开发,字节内部大部分是 Go,转语言学习大概需要多久?
- 实习时间安排?
- 深挖实习项目细节
MySQL
- MySQL 聚簇索引与非聚簇索引的区别是什么?
- MySQL 事务隔离级别有哪些?
- 可重复读(RR)解决了什么问题?
- 间隙锁是什么,发挥什么作用?
- MySQL 的 int 占几个字节,bigint 占几个字节?
- utf8 编码下,varchar(20) 最多放几个字符?
- int(11) 是什么意思?
- 如何解决大数据量下的深分页问题?
Redis
- Redis 在项目中主要起什么作用?
- Redis 热 key 可能会出现什么问题,如何解决?
- Redis 常见数据结构,分别有什么作用?
- zset 为什么可以做排行榜?
- zset 底层跳表是什么结构,是如何根据 score 排序的?
网络
- 项目中都是单体部署的吗?
- 小程序端发送请求到服务端的完整过程(网络链路)?
- TCP 三次握手的过程,为什么需要三次?
消息队列
- 有用过消息队列吗?
手写题
SQL题: 有员工表 e,部门字段 d,查询部门人数多于 50 的部门。
SELECT d FROM e GROUP BY d HAVING COUNT(*) > 50;
算法题: [LeetCode 131] 分割回文串(回溯)
- 思路:回溯枚举所有分割方式,判断每段是否为回文串(双指针头尾遍历)
- 追问:判断回文串的时间复杂度?能否优化?(面试官引导方向为动态规划预处理)
参考解析
MySQL 聚簇索引 vs 非聚簇索引
- 聚簇索引:叶子节点直接存储完整行数据,InnoDB 默认主键为聚簇索引,一张表只能有一个。
- 非聚簇索引(二级索引):叶子节点存储主键值,查询非索引列时需要回表到聚簇索引再查一次。
- 覆盖索引可避免回表,是常见优化手段。
事务隔离级别
| 级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | ✓ | ✓ | ✓ |
| 读已提交 | ✗ | ✓ | ✓ |
| 可重复读(默认) | ✗ | ✗ | 部分解决 |
| 串行化 | ✗ | ✗ | ✗ |
- InnoDB 在 RR 级别通过 MVCC + 间隙锁 基本解决幻读。
间隙锁(Gap Lock)
- 锁定索引记录之间的间隙,防止其他事务在该范围内插入新记录,从而防止幻读。
- 只在 RR 及以上隔离级别生效,范围查询时自动加间隙锁。
- Next-Key Lock = 行锁 + 间隙锁,是 InnoDB 防幻读的核心机制。
int(11) 的含义
- 括号内的数字是显示宽度,与存储大小无关,int 始终占 4 字节。
- 显示宽度配合
ZEROFILL使用,不足位数补零。 - MySQL 8.0.17 起已废弃整数类型的显示宽度属性。
深分页优化
- 问题根因:
LIMIT 100000, 10会扫描并丢弃前 10 万行,效率极低。 - 方案1 - 子查询/延迟关联:先用覆盖索引查出主键,再 JOIN 取完整数据。
SELECT * FROM t JOIN (SELECT id FROM t ORDER BY id LIMIT 100000,10) tmp USING(id); - 方案2 - 游标分页:记录上一页最后一条的 id,用
WHERE id > last_id LIMIT 10,适合顺序翻页。 - 方案3:业务上限制最大分页深度,超深分页引导用户搜索。
Redis 热 key 问题
- 问题:单个 key 请求量过大,集中打到同一节点,造成该节点 CPU/带宽瓶颈,甚至宕机。
- 解决方案:
- 本地缓存:在应用层用 Caffeine/Guava 缓存热 key,减少 Redis 请求。
- key 拆分:将热 key 复制为
key_0~key_N,随机读取分散压力。 - 读写分离:扩展 Redis 只读副本分摊读流量。
zset 跳表结构
- 跳表是多层链表,底层包含所有节点,上层为索引层(按概率抽取)。
- 每个节点存储
score和member,所有节点按 score 升序排列。 - 查找时从最高层开始,逐层向右跳跃,时间复杂度 O(log N)。
- zset 支持按 score 范围查询、排名查询,天然适合排行榜场景。
分割回文串 - 判断回文串优化
- 面试官引导的优化方向:DP 预处理所有子串是否为回文串,时间 O(n²),之后回溯时 O(1) 查询,避免每次双指针 O(n)。
# 预处理 dp[i][j] 表示 s[i..j] 是否为回文 dp[i][j] = (s[i] == s[j]) and dp[i+1][j-1] - 总体时间复杂度:O(n · 2ⁿ),预处理不改变回溯部分的指数复杂度,但常数更优。