拼多多测试开发面经(按一二三面拆分 · 可背诵标准回答版)
一、一面(45~60 分钟 · 项目 + 基础 + 手撕代码)
1. 自我介绍
面试官好,我叫 XXX,XX 学校 XX 专业硕士/本科在读。
我有 X 段测试相关经历:
- 在 XX 公司实习期间,负责 XX 模块的功能测试和接口自动化测试
技术栈方面,我熟悉 Python/Java、MySQL、Redis,能独立编写测试脚本。
拼多多的企业文化和发展速度我很认可,希望能加入拼多多团队。2. 项目介绍(会被深挖细节)
背景:该系统主要解决 XX 问题,用户规模 XX。
任务:我负责 XX 模块的测试用例设计和执行。
行动:
1. 用 Xmind 梳理测试点,设计测试用例 XX 条
2. 搭建接口自动化框架,覆盖核心接口
3. 接入 Jenkins,实现持续集成
结果:主流程覆盖率达到 XX%,回归时间从 X 小时缩短到 X 分钟。常见追问:
- "项目的技术难点是什么?怎么解决的?"
- "超卖问题遇到过吗?怎么处理的?"
- "缓存和数据库不一致怎么办?"
3. 缓存穿透、缓存击穿、缓存雪崩
缓存穿透:查询不存在的数据,每次都打到数据库
解决:布隆过滤器 / 缓存空值 / 参数校验
缓存击穿:热点 key 过期瞬间,大量请求打到数据库
解决:互斥锁 / 永不过期 + 异步更新 / 热点数据不过期
缓存雪崩:大量 key 同时过期,导致数据库压力过大
解决:过期时间加随机值 / 热点数据永不过期 / 服务熔断降级4. HashMap 线程安全吗?有哪些线程安全的 Map?
HashMap 线程不安全,JDK 1.7 并发下可能产生环形链表死循环。
线程安全的 Map:
1. Hashtable:全局锁,效率低
2. Collections.synchronizedMap:同样全局锁
3. ConcurrentHashMap:
- JDK 1.7:分段锁(Segment)
- JDK 1.8:CAS + synchronized,锁细化到单个桶5. ConcurrentHashMap 如何保证线程安全?
1. 使用 CAS(Compare-And-Swap)保证原子性操作
2. 对单个桶使用 synchronized 加锁,保证并发安全
3. 扩容时支持多线程并发扩容
4. 不允许 null 作为 key 或 value6. JVM 内存结构
1. 堆(Heap):对象实例、数组,GC 主要管理区域
2. 栈(Stack):方法调用、局部变量,每个线程独立
3. 方法区(Method Area):类信息、常量、静态变量
4. 本地方法栈:Native 方法调用
5. 程序计数器:记录当前线程执行位置
堆的分区:
- 年轻代:Eden + Survivor(From + To)
- 老年代:存放长期存活对象7. 数据库索引数据结构(B+ 树 vs Hash)
B+ 树:
- 多叉平衡树,树高一般 3~4 层,查找次数少
- 叶子节点存储所有数据,用双向链表连接,范围查询快
- 适合范围查询、排序查询
Hash 索引:
- 用 Hash 计算 key 的位置,直接定位
- 等值查询快,范围查询慢
- 不支持排序、不支持最左前缀匹配8. 幻读是什么?如何解决?
幻读:同一个事务中,两次查询结果不一致(因为其他事务插入了新数据)。
解决:
1. MVCC(多版本并发控制) + 间隙锁(Gap Lock)
2. RR(可重复读)隔离级别下,幻读会被抑制
3. SELECT ... FOR UPDATE 加锁9. 分布式锁的实现
Redis 实现:
SET key value NX PX timeout
- NX:只有 key 不存在时才设置(保证原子性)
- PX:设置过期时间,防止死锁
释放:用 Lua 脚本保证只有持有锁的人才能释放
为什么用 SETNX 而不是 SET?
SETNX 是原子操作,保证只有一个客户端能获取锁。10. 手撕代码:合并两个升序数组
python
def merge(nums1, m, nums2, n):
p1, p2, p = m - 1, n - 1, m + n - 1
while p2 >= 0:
if p1 >= 0 and nums1[p1] > nums2[p2]:
nums1[p] = nums1[p1]
p1 -= 1
else:
nums1[p] = nums2[p2]
p2 -= 1
p -= 111. 手撕代码:LRU 缓存
python
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.cache = OrderedDict()
def get(self, key):
if key not in self.cache:
return -1
self.cache.move_to_end(key)
return self.cache[key]
def put(self, key, value):
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)二、二面(45~60 分钟 · 项目深挖 + 场景题)
1. MySQL 索引如何建立?
1. 主键自动建立唯一索引
2. WHERE 条件字段、JOIN 连接字段建议建索引
3. 区分度高的字段优先建索引
4. 遵循最左前缀原则:WHERE a = AND b = AND c = 可以建联合索引 (a, b, c)
复合索引顺序:
- 区分度高的放前面
- 查询条件最频繁的放前面2. 深分页问题如何优化?
问题:SELECT * FROM t ORDER BY id LIMIT 100000, 10
会先扫描前 100010 条,再返回后 10 条,性能很差。
优化方案:
1. 延迟关联:先查 ID,再关联查数据
SELECT t.* FROM t JOIN (SELECT id FROM t LIMIT 100000, 10) AS tmp ON t.id = tmp.id
2. 游标分页:记录上一页最后一条的 ID
SELECT * FROM t WHERE id > last_id LIMIT 10
3. 禁止跳页查询:只支持首页 + 上一页 + 下一页3. 手撕代码:打牌,求最少出牌次数(LeetCode 403)
python
# 贪心 + DFS
def minCardPoints(cardPoints, k):
# 转化为求两端和最小的子数组
n = len(cardPoints)
total = sum(cardPoints)
window_size = n - k
window_sum = sum(cardPoints[:window_size])
min_window = window_sum
for i in range(window_size, n):
window_sum += cardPoints[i] - cardPoints[i - window_size]
min_window = min(min_window, window_sum)
return total - min_window4. 接口幂等性
幂等性:多次执行同一个操作,结果和执行一次是一样的。
需要幂等的场景:
1. 支付接口:重复支付
2. 下单接口:重复下单
3. 退款接口:重复退款
4. 扣库存接口:重复扣减
实现方案:
1. 数据库唯一索引
2. 分布式锁(SETNX)
3. Token 机制:提交前获取 Token,提交时验证并删除
4. 状态机:只有特定状态才能流转5. 手撕代码:两集合交集(给定左闭右开集合)
python
def intersection(nums1, nums2):
# 假设输入为已排序的左闭右开区间集合
result = []
i, j = 0, 0
while i < len(nums1) and j < len(nums2):
# 获取当前集合的范围
start1, end1 = nums1[i]
start2, end2 = nums2[j]
# 计算交集
overlap_start = max(start1, start2)
overlap_end = min(end1, end2)
if overlap_start < overlap_end:
result.append([overlap_start, overlap_end])
# 移动指针
if end1 < end2:
i += 1
else:
j += 1
return result三、三面(60 分钟 · 项目深挖 + 架构 + HR)
1. 实习转正情况
如实回答:
1. 目前有没有转正机会
2. 实习期间的主要成果
3. 团队氛围和导师评价2. 能否接受单休?
回答策略:
1. 如果确实能接受 → 直接说能接受
2. 如果有顾虑 → 说可以接受,并表示愿意适应公司文化
3. 追问工作强度和节奏
拼多多普遍工作强度大,回答前要想清楚。3. 秋招投递了哪些公司?
如实回答,可以说:
- 头部大厂:字节/腾讯/阿里等
- 同类型公司:快手/美团/京东等
不要说只投了拼多多,显得选择少。
不要说投了很多小公司,显得质量不够。4. 选 offer 的依据
1. 业务前景:业务是否有发展空间
2. 技术成长:能学到什么
3. 薪资福利:base + 奖金 + 股票
4. 团队氛围:直属 leader 和同事
5. 地点:城市和通勤5. 预期薪资
参考:
- 提前了解市场行情
- 说出期望值时给一个范围
- 不要说「根据公司标准」
可以说:「结合我的学历背景和实习经历,以及市场行情,期望月薪 XXK~XXK」6. 对拼多多的了解
1. 拼多多是中国最大的电商平台之一
2. 以 C2M(消费者直连制造商)模式著称
3. 增长速度快,用户规模大
4. 技术驱动:分布式系统、高并发、大数据
5. 拼多多企业文化:结果导向、执行力强四、拼多多高频手撕代码汇总
| 题目 | 难度 | 出现频率 |
|---|---|---|
| LRU 缓存 | ★★★ | ⭐⭐⭐⭐⭐ |
| 合并两个有序数组 | ★★ | ⭐⭐⭐⭐ |
| 集合交集(左闭右开) | ★★★ | ⭐⭐⭐⭐ |
| 深分页优化 | ★★ | ⭐⭐⭐ |
| 打牌最少次数 | ★★★ | ⭐⭐⭐ |
五、拼多多面试特点总结
拼多多一面:项目 + 缓存(穿透/击穿/雪崩)+ HashMap + JVM + 手撕代码
重点:基础知识要扎实,代码要能写出来
拼多多二面:项目深挖 + MySQL(索引/深分页)+ 架构 + 手撕代码
重点:项目细节要经得起追问,MySQL 要深入
拼多多三面:主管面(偏 HR)
重点:稳定性、动机、抗压能力
注意:拼多多工作强度大,面试时会问能否接受单休,要提前想好。