拼多多后端开发岗面经-06:三场面试题目合集
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
面经 01(面试时间 2026 年 9 月 13 日)
- Redis 分布式锁如何实现?
- 分库分表适用于哪些场景,使用时需要注意什么?
- 数据库主从同步如何使用?
- Binlog 是否存储在本地,使用时有哪些注意事项?
- 场景题:两个磁盘容量分别为 1 TB 和 2 TB,内存只有 8 GB,如何找出两者的共同数据?
- 手撕:求多个有序链表的元素交集。
- 日常开发流程包含哪些环节?
- 如何看待拼多多不设置独立测试岗位?
- 请介绍项目中遇到的一个难点及解决过程。
- 手撕:在旋转有序数组中搜索目标值。
- 场景题:设计一个支持高并发高 QPS 读取和新条目插入的 Cache。
面经 02(面试时间 2026 年 9 月 12 日)
- 手撕:课程表问题的变体。
- 项目中的数据表如何设计?
- 项目中的数据持久化如何实现?
- Agent 的多模式引擎如何实现,为什么这样设计?
- Agent 的记忆系统如何实现?
- 项目设计与市面现有方案有哪些区别,为什么做这些差异化设计?
- TCP 发生阻塞时如何处理?
- 请介绍 mmap 的工作机制。
- 请结合简历介绍项目经历。
- 商城项目的数据流如何设计,Redis 与 MySQL 分别承担哪些操作?
- 项目中的鉴权如何实现,JWT Token 中保存哪些信息?
- 用户密码如何存储?如果需要密文存储,应如何设计?
- 密码使用哈希存储时,用户忘记密码应如何处理?
- 请画出 TCP 三次握手过程,并分析一次握手失败的场景。
- 递归没有退出条件时会发生什么?
- 字段数据类型相同但排列顺序不同的结构体有什么区别?
- 手撕:在树中查找路径和大于指定阈值的路径。
- 场景题:如何设计路由定位系统的存储和查询?路由规则包含通配符时,存储和查询方案如何调整?
- 请介绍 Agent 项目的整体架构。
- 项目中的向量数据如何存储?HNSW 索引如何工作,怎样加速查询?
- 项目的主要难点或亮点是什么?
- Agent 的上下文如何管理?
- 如何处理 Git 版本控制中的冲突场景?
- 手撕:对有序数组原地去重,并设计测试用例。
面经 03(面试时间 2026 年 9 月 12 日)
- 请做一下自我介绍。
- 手撕:实现拓扑排序。
- 请介绍项目并说明关键技术细节。
原帖为连载合集,面经 03 之后的正文在牛客服务端即被截断,此处只保留已发布的部分。
《参考解析》
Redis 分布式锁
核心是 SET key value NX PX ttl 一条命令完成加锁,value 用唯一标识(比如 UUID + 线程 id)以便解锁时校验持有者。解锁必须用 Lua 脚本先比较 value 再删除,否则会出现「A 的锁超时自动释放、B 拿到锁、A 回来把 B 的锁删掉」这种误删。TTL 要覆盖业务最长耗时,但没法准确预估,所以生产上更常用 Redisson 的看门狗:加锁成功起一个定时续期任务,业务没结束就不断把过期时间往后推,进程挂掉后定时任务随之消失,锁到期自动释放。
分库分表
适用场景是单表数据量把 B+ 树高度顶上去、索引和 DDL 都变慢,或者单库写入已经打满磁盘 IOPS。顺序上应该先做读写分离、加缓存、冷热分离、归档,这些都做完还有压力才分片。分片要提前定好分片键,选那种能覆盖大多数查询条件、且分布均匀的字段(比如用户 id 或订单 id);分片键选错会出现跨库 join 和全路由扫描,性能比不分还差。跨片事务、全局唯一 id、跨片分页和聚合都是要额外付的成本。
1 TB 与 2 TB 找共同数据
内存放不下全量,思路是把「集合求交」转成「分治 + 位图/布隆」。一种做法是按哈希把两个磁盘的数据各自切成若干份,保证同一份数据落到同一组小文件里(hash 取模),然后逐组把小的那份读进内存建哈希表,再流式扫描对应的大份文件找命中——这样每组都能在内存里完成,代价是两次全量磁盘扫描。如果只要求近似判断,可以先对其中一个磁盘建布隆过滤器,再用它过滤另一个磁盘,能大幅减少比对量,但会有假阳性。
手撕:多个有序链表的元素交集
用最小堆维护每个链表当前的指针,堆里存 (值, 链表下标)。每次弹出最小值,如果弹出的值和上一次弹出的值相同、且这一轮所有链表都贡献了这个值,它就在交集里。更省事的写法是堆里始终只保留每个链表当前的最小值,每轮取堆顶,然后检查是否所有链表的当前值都等于堆顶:是就收进结果并把所有链表指针后移;不是就把取值小于堆顶的那些链表推进到不小于堆顶的位置。总复杂度 O(N log k),k 是链表条数。
旋转有序数组查找目标值
数组被旋转后存在一个分界点,两段各自有序。二分时取 mid,判断 mid 落在左半段还是右半段:如果 nums[low] <= nums[mid] 说明左段有序,此时看目标是否落在 [nums[low], nums[mid]) 区间内,是就收缩到左半边,否则去右半边;右段有序时对称处理。要注意重复元素会让 nums[low] == nums[mid],这时无法判断哪边有序,只能把 low 往前挪一位退化处理,最坏复杂度会到 O(n)。
设计高 QPS 读 + 新条目插入的 Cache
读多写少、还要持续插入新条目,直接上一把大锁会把读也串行化。分成两层更合适:用分片的方式把 key 空间切成 N 份,每份一把读写锁,写只锁自己那一片,读之间互不阻塞。淘汰策略上单纯的 LRU 需要给每次读都写链表,高并发下锁竞争严重,可以改成近似 LRU(分段 LRU 或 CLOCK),牺牲一点命中率换取吞吐。插入新条目走「先写后端存储、再失效缓存」,避免缓存里出现读不到源数据的新值;同时用单飞(singleflight)合并同一个 key 的并发回源请求,防止缓存击穿把后端打垮。
mmap 与 TCP 阻塞
mmap 把文件的一段映射进进程虚拟地址空间,读文件不再走 read 系统调用和内核缓冲区拷贝,而是直接访问页缓存,缺页时由内核触发缺页中断把磁盘数据读进来。适合随机读大文件,但不适合频繁写小文件,因为脏页回写时机不可控,而且映射期间文件被截断会触发 SIGBUS。TCP 发送阻塞时表现为发送缓冲区满,处理方向有三条:业务上做限流和背压,让上游别继续灌;协议上调大 SO_SNDBUF 或者启用 TCP_NODELAY 减少粘包等待;结构上把同步发送改成带确认的异步队列,堆积到阈值就降级或快速失败,而不是无限缓冲把内存吃满。
HNSW 索引
HNSW 是分层的近邻图,底层包含全部向量,越往上节点越稀疏。查询时从最上层的入口点出发,贪心地向距离目标更近的邻居走,走到局部最优就下沉到下一层继续,直到最底层得到结果。这样高层负责快速跳到大致的区域,底层负责精细搜索,把「遍历全量」变成「走几十条边」。代价是内存:除了向量本身还要存每层的邻居表,参数 M(每个节点的连接数)和 efConstruction 直接决定索引大小和构建时间;查询时 efSearch 越大召回越高、延迟也越高。
手撕:有序数组原地去重
双指针,慢指针指向已去重部分的最后一个位置,快指针扫描全数组;快指针的值和慢指针不同就先把慢指针前移再覆盖。返回慢指针下标加一即新长度。测试用例要覆盖空数组、只有一个元素、全部相同、全部不同、以及只有末尾重复这几种边界,另外还要验证返回长度之外的尾部空间不被当作有效数据。
哈希存储密码与忘记密码
密码永远不能明文或简单 MD5 存。正确做法是加盐的单向慢哈希,比如 bcrypt、scrypt 或 Argon2,每个用户独立随机盐,cost 参数调到单次校验耗时几十到几百毫秒,让离线爆破成本高到不可行。正因为是单向不可逆的,忘记密码时系统没法「找回」原密码,只能走「验证身份 → 重置为新密码」的流程:通过邮箱或短信发一次性 token,token 设置短有效期且用完即废,重置后使该用户所有已有会话失效。