面灵AI→

多公司后端与全栈面经合集:字节、百度、美团、B站、米哈游

时间
2026-09
来源
牛客网

《面试题目》

米哈游 · 平台研发(Go)

  1. 手撕:二分查找。
  2. Go 语言相关八股(问得比较深)。
  3. 数据库相关八股。
  4. 实习经历相关的问题。

bilibili · 服务端开发

  1. 你的论文是什么时候开始做的,现在是什么状态?
  2. 论文具体解决什么问题,方法是怎么做的?
  3. 你的方案为什么可以说和 Agent 有关系?
  4. 如果换一个能力比较弱的大模型,这套方法还能工作吗?
  5. 大模型生成的算法不合法怎么办,会修复吗?
  6. 你怎么保证换模型以后整个 Workflow 还能运行?
  7. 介绍一下你接触 AI / 大模型以来的发展过程,最近有没有关注 Agent 方向的论文或者技术?
  8. 为什么 Go 适合高并发?
  9. Go 里面有没有遇到并发安全问题,怎么处理?
  10. 你了解 sync.Map 的底层实现吗?
  11. 你了解操作系统的内存管理吗?常见的内存分配策略有哪些?
  12. 怎么判断一个内存分配算法好不好?
  13. 如果让你实现空闲内存管理,你会怎么做?
  14. 介绍一下你实习期间主要做了什么。
  15. 实习中做过什么性能优化?为什么当时不通过加索引解决?你们看过 EXPLAIN 吗,查询有没有走索引?
  16. MySQL 有哪些索引?索引是不是越多越好,加太多索引有什么问题?
  17. 设计索引时有哪些原则?
  18. MySQL 除了 B+ 树索引,还有什么索引结构?Hash 索引和 B+ 树索引有什么区别?
  19. 讲一下 MySQL 的 B+ 树索引,为什么不用普通二叉搜索树而使用 B+ 树?
  20. 如果让你设计短链接系统,你会怎么做?短链接和长链接应该是什么关系?
  21. 怎么进一步缩短 URL?
  22. 手撕:链表反转。你刚才这段链表反转代码有什么问题?

百度 · 北京后端

  1. 平时刷算法题和做项目分别使用什么语言?为什么项目更倾向使用 Go?
  2. Go 中 make 和 new 有什么区别?make 可以初始化哪些类型?
  3. Go 中数组和切片有什么区别?切片的底层结构是什么,len 和 cap 分别表示什么?
  4. append 时容量不足会发生什么?切片的扩容机制是怎样的?
  5. 什么是 Goroutine?为什么它比操作系统线程更轻量?
  6. Go 的 GMP 调度模型是什么?Goroutine 和线程的上下文切换有什么区别?
  7. 进程、线程和协程三者有什么区别和联系?
  8. 线程之间有哪些同步或通信方式?
  9. 操作系统如何管理物理内存?为什么需要虚拟内存?
  10. 虚拟地址如何通过页表转换为物理地址?页和页框分别是什么?
  11. 什么是生产者—消费者模型?多线程下如何保证生产者和消费者访问共享数据的并发安全?
  12. 什么是读写锁?它相比普通互斥锁有什么优势?
  13. HTTP 和 HTTPS 有什么区别?HTTPS 如何实现防窃听、防篡改和身份认证?
  14. 数字证书在 HTTPS 中有什么作用?TLS 握手的大致流程是什么?
  15. DNS 中的 A 记录和 CNAME 记录分别是什么,有什么区别?
  16. TCP 连接建立后如果一端突然断网,另一端继续发送数据会发生什么?一直收不到 ACK 时会如何处理?
  17. TCP 的超时重传和滑动窗口机制是什么?TIME_WAIT 状态有什么作用?
  18. Redis 有哪些常见数据结构?Redis 为什么快?
  19. 多个客户端并发操作 Redis 时如何保证安全?Lua 脚本为什么可以保证多个操作的原子执行?
  20. 什么是缓存穿透?会带来什么问题,如何解决?
  21. Redis 事务的 MULTI/EXEC 是如何工作的?Redis 事务支持回滚吗,它和传统数据库事务有什么区别?
  22. 什么是 Redis 分布式锁?如何使用 SET NX EX 实现?
  23. 释放分布式锁时为什么通常需要 Lua 脚本?
  24. 算法题:小于 n 的最大数。

字节跳动 · 飞书/飞书云文档后端 · 一面

  1. 算法题:缺失的第一个正数。
  2. 场景题:几十 TB 数据的用户 id,内存只有 4G,如何找出出现频率最高的 Top 10 id?
  3. 竞赛项目里 Redis Lua 起什么作用,为什么要用?Lua 的原子性如何理解和保证?
  4. Lua 执行失败会不会回退,为什么不回退?
  5. 实习时 SQL 优化是怎么做的?讲讲索引,为什么要用 B+ 树?
  6. 索引越多越好吗,为什么?
  7. 讲讲 TCP 的三次握手和四次挥手,目的是什么?
  8. 一次 URL 到页面返回渲染的全过程是怎样的?DNS 解析如何做的,每次都要走完整流程吗,缓存怎么实现?
  9. HTTPS 怎么实现安全?数字证书怎么实现?如果我伪造一个证书说自己是百度会怎样?
  10. CPU 满了怎么办?火焰图之前看什么,了解 load 吗?
  11. 内存满了怎么办,怎么检测?

字节跳动 · 飞书/飞书云文档后端 · 二面

  1. 实习项目跟 AI 搜索有什么关系?
  2. 搜索引擎相关的问题。
  3. MySQL 架构、数据库架构相关问题。
  4. 集群哨兵、Redis 各种架构相关问题。
  5. Go 的 GC 是怎么做的?什么是 STW?
  6. AI 方面问了 RAG 相关内容;场景题:点杀黑产灰产、秒杀。
  7. 手撕:不重复最长子串。

字节跳动 · 生态 Agent 后端开发工程师(火山引擎)

  1. 你最有代表性的项目是什么?介绍一下这个 AI 全栈挑战赛项目。
  2. 你在项目里主要负责什么?这个项目最大的难点和亮点是什么?
  3. 整体系统架构是怎样的?权限系统怎么设计?
  4. 为什么使用 WebSocket 而不是普通 HTTP?WebSocket 房间是怎么设计的?
  5. 一次用户加价请求是怎么走的?为什么竞拍裁决不直接操作 MySQL?
  6. 为什么要使用 Redis Lua?Lua 脚本里主要做哪些事情,操作顺序为什么重要?
  7. 为什么不直接在 Lua 里写 MySQL?
  8. 为什么用 Redis Stream 而不是 Kafka、RocketMQ?Redis Stream 后面的数据怎么落库?
  9. 这里的 Room 是一个真实实体吗?WebSocket 断线以后怎么恢复,怎么保证重连后还是进入原来的房间?
  10. Redis 中这些数据怎么组织?为什么参与用户适合用 Set?为什么排行榜使用 ZSet?
  11. Redis ZSet 底层是什么数据结构?
  12. WebSocket 是怎么建立连接的?属于哪一层协议?什么时候创建 WebSocket Room?
  13. 给定整数 N 和一组允许使用的数字,如何找到不超过 N 的最大整数?这道算法题的思路是什么,现场代码的问题在哪里?
  14. 一个经常按 create_at 和 user_id 查询的表,你怎么优化?索引有什么优点和缺点?
  15. TCP 和 UDP 有什么区别?TCP 的「有连接」是什么意思,一个 TCP 连接怎么唯一标识?
  16. TCP 和 UDP 分别适合什么场景?UDP 不可靠,怎么实现可靠传输?
  17. 你们项目里的 AI 功能是什么?为什么传统关键词搜索不够?
  18. AI 找拍品具体怎么实现,用了什么模型和技术栈?这个功能算 Agent 吗?
  19. 你怎么理解 Agent 的设计?论文里的 Agent / Workflow 是怎么设计的?
  20. 为什么需要 LLM 来设计启发式算法?一轮迭代具体是怎么进行的,下一轮一定会比上一轮好吗?
  21. 谁负责选择最好的策略,是 Agent 吗?为什么这种 Agent 需要保存上一轮结果?
  22. ReAct 模式有什么优点和缺点?ReAct 和 Plan-and-Execute 怎么选?
  23. 你怎么定义「复杂任务」?
  24. 科研里的大模型 API 从哪里来?为什么你觉得 LLM 适合做算法设计?
  25. 你说的「不同环境」具体指什么?论文做的是实际地图路径规划吗?
  26. 这种算法能落地到真实路径规划吗?真实约束能直接加入你的求解框架吗?

字节跳动 · 后端开发工程师(字节云)· AI 算力基础设施 · 一面

  1. 进程和线程有什么区别?线程之间共享哪些资源、哪些资源是私有的?
  2. 协程和线程有什么区别?
  3. 详细讲一下 Go 的 GMP 调度模型。
  4. 用户态和内核态有什么区别?从用户态切换到内核态有哪些方式?
  5. 详细讲一下虚拟内存机制,一个程序使用内存的完整过程是什么?
  6. 缺页中断的处理流程是什么?
  7. 网络协议栈了解多少?OSI 七层模型分别是什么?
  8. UDP 为什么不可靠?TCP 为什么可靠?TCP 快速重传机制是什么?
  9. Cookie 和 Session 分别是什么,两者有什么关系?
  10. RESTful 是什么?
  11. MySQL 常用索引有哪些?InnoDB 的索引是怎么实现的,B+ 树有什么特点?
  12. 数据库/DBMS 的主要特点是什么?
  13. LangGraph 是什么样的框架?
  14. 如果设计一个安全系统,核心安全模块有哪些?
  15. 大模型如何与传统算法、领域工具结合并进行迭代?
  16. 复杂 Agent 流程能否直接封装成 Skill?
  17. 是否了解 Kubernetes/K8s、Agent Sandbox、DeepSeek 开源的 Harness 项目?
  18. 设计一个带统一 TTL 的 LRU Cache:容量为 n,超过容量时优先淘汰已过期 KV,如果没有过期 KV 则淘汰最近最少使用的数据,查询到过期 KV 时返回空。这道题的实现思路是什么?

字节跳动 · 后端开发工程师(字节云)· AI 算力基础设施 · 二面

  1. 介绍一个你认为做得比较好的项目。
  2. 高并发场景下多个用户同时操作时,核心业务逻辑是怎么裁决的?
  3. 「读取当前值 → 判断 → 写入」不是原子操作,并发情况下怎么避免竞态?两个请求同时基于旧数据判断,怎么防止后写入的低值覆盖先写入的高值?
  4. Redis Lua 是怎么实现「判断 + 更新」原子操作的?脚本内部具体做了哪些校验和状态更新?
  5. Redis 操作成功以后,什么时候把数据写入 MySQL?
  6. Redis 到 MySQL 采用异步落库时,怎么保证数据最终一定能写入?异步消费者挂掉、重启后怎么保证消息不丢?
  7. 消息重复消费时,怎么保证 MySQL 写入幂等?
  8. 最终结算时应该以 Redis 还是 MySQL 中的数据为准?两者存在延迟时怎么保证最终结果一致?
  9. 结算与最后一次并发操作同时发生时,怎么保证拿到的是最终状态?如何通过状态机阻止结算之后的新请求?
  10. Redis Stream 或 Redis 出现异常、数据丢失时怎么办?
  11. 为什么采用 Redis + Lua,而不是 Redis 分布式锁 + MySQL?
  12. 这个架构里使用 Redis 的核心目的是抗并发、低延迟,还是保证原子性?为什么要把实时热路径和 MySQL 写路径解耦?
  13. 幂等键是怎么设计的、在哪里生成?服务端拿到幂等键后,怎么判断这个请求之前是否已经处理过?
  14. 幂等键应该在请求处理的哪个阶段写入 Redis?写入时怎么区分业务处理成功、失败、处理中三种状态?
  15. 如果业务请求被拒绝,失败结果需不需要也做幂等缓存?
  16. 幂等键应该放在 Lua 脚本内部一起写,还是 Lua 返回以后再写?如果 Lua 已执行成功但幂等键还没写入,此时客户端重试怎么办?
  17. 如果重新设计一套幂等机制,你会怎么实现?SETNX 能不能直接解决幂等问题,它和业务处理结果之间如何保证一致性?
  18. 平时怎么使用 AI Coding?和传统开发相比,项目开发流程有什么区别?
  19. 用过哪些 Skill?Skill 是怎么工作的?
  20. 与 AI Coding 工具交互时,你一般怎么提供上下文、描述需求?
  21. 通常会让 AI 帮你完成哪些工作?哪些内容由人设计,哪些交给 Agent 生成?
  22. 项目的功能优先级、任务拆分是人定义的还是 Agent 自动定义的?用过哪些 AI Coding 工具?能否现场演示一次完整的 AI Coding 开发流程?
  23. 启动三个线程分别只打印 1、2、3,如何让它们循环输出 123123123……?可以使用什么同步机制实现线程之间的顺序协作?
  24. 代码中的 flag 状态变量有什么作用?多个线程是在「竞争资源」还是在「协作」,两者怎么理解?
  25. 线程抢到锁后发现还没轮到自己应该怎么办?wait 被唤醒返回以后,为什么还要重新判断 flag?
  26. 什么是虚假唤醒?为什么条件判断通常要写在 while 中?
  27. 设计一个支持 get/set 的 LRU Cache,核心数据结构应该怎么设计?为什么通常使用 HashMap + 双向链表?
  28. 如果要求某个 Key 在 X 秒内没有被访问就自动过期,应该怎么实现?过期数据采用惰性删除、后台定时清理,还是两者结合?
  29. 写出 LRU Cache 的核心数据结构和伪代码。如何严格保证缓存中的对象数量最多为 N?
  30. Cache 已满时,应该先插入再淘汰,还是先淘汰再插入?更新一个已经存在的 Key 时需要触发容量淘汰吗?
  31. 过期时间应该在什么时机设置?get 时发现 Key 已过期应该怎么处理?get 和 set 操作是否应该刷新过期时间?
  32. 并发执行 get/set 时,如何保证 HashMap、链表和容量的一致性?
  33. LRU 具体是什么意思?get 为什么也算一次「最近使用」?set 是否也应该改变节点在链表中的位置?
  34. LRU 中的 Node 应该包含哪些字段?双向链表具体是怎么组织的,prev/next 如何维护?
  35. 删除节点时如何保证 HashMap 与链表中的节点同步删除?节点删除不彻底可能产生什么内存或引用问题?
  36. 如果使用 C++ 的 list,是否可以直接把它作为 LRU 的双向链表?

美团 · 财务平台-财务科技-全栈

  1. K 个一组翻转链表。
  2. 讲一下 K 个一组翻转链表的代码逻辑。
  3. 如何把题目通过自然语言或结构化 Prompt 描述给 AI,让 AI 自动生成代码?
  4. 这道 AI Coding 题的 Prompt 设计思路是什么?怎么保证 Prompt 能覆盖输入输出、边界条件和核心逻辑?整体实现思路是什么?
  5. 从简历里挑一个最有意义或复杂度最高的项目讲一下:背景是什么,要达成什么目标,你具体是怎么做的?
  6. 过程中遇到了什么问题,最后是怎么解决的?
  7. 为什么在竞拍系统里使用 Redis Lua 脚本?脚本操作了多少个 Redis Key,每个 Key 分别是干什么的?
  8. 竞拍实时状态的 Redis Key 里具体存了哪些数据?
  9. 竞拍排行榜是怎么实现的?数据存在哪个 Key,用什么数据结构,具体怎么排序和维护?
  10. Lua、SETNX、WATCH 等方案有没有做过对比,为什么最终选择 Lua?
  11. 什么是 RAG,主要用来解决什么问题?你的项目里为什么使用 RAG,具体用在什么场景?
  12. 你对 DeepSeek Harness 了解多少?
  13. 你了解 LangChain 吗?LangChain 和 LangGraph 是什么关系,为什么会从 LangChain 发展到 LangGraph / Workflow?
  14. 你实际使用过哪些大模型,还了解哪些大模型?哪些大模型的编程能力比较强?
  15. 智谱、Kimi 这些模型了解吗?豆包了解或使用过吗?
  16. 有了 AI Coding 工具之后,你和 AI 分别扮演什么角色?相比没有 AI Coding 的传统开发方式,开发者的角色发生了什么变化?
  17. 测试驱动开发是什么?规范驱动开发是什么?TDD 和 Spec-Driven Development / Spec Coding 怎么理解?
  18. 你用过业界的 Spec Coding 工具吗?亚马逊的相关 AI Coding / Spec Coding 工具了解或用过吗?用过字节的 AI Coding 工具吗?

《参考解析》

1. 海量数据 Top K:哈希分片 + 小根堆:几十 TB 的 id 不可能一次读进 4G 内存,正确解法是两阶段分治。先按 hash(id) 取模把数据分成 M 个小文件(比如 4096 个),保证同一个 id 永远落到同一个文件;单个文件的大小要压到内存放得下的量级。然后逐个文件用哈希表统计词频,同时维护一个大小为 10 的小根堆,堆顶是当前第 10 名的频次,新词频大于堆顶才入堆并弹掉堆顶,候选集从 O(n) 降到 O(k)。面试里要主动补三个细节:哈希函数要选分布均匀的(MurmurHash、xxHash),否则分片倾斜;哈希表装填因子到 0.7 左右就要扩容,空间不能按 id 数量掐着算;必须先把这个分片的词频统计完再和堆顶比较,边统计边过滤会让同一个 id 被拆到多个批次里算错。最后合并 M 个局部 Top 10 得到全局结果。

2. Redis Lua 的原子性与「失败不回退」:Redis 的命令执行是单线程的,一个 Lua 脚本被当成整体执行,期间不会插入其他客户端的命令,所以「读—判断—写」放进脚本就天然原子,不需要额外加锁。但它和数据库事务的语义完全不同:脚本中途报错不会回滚已经执行过的写命令,也不支持 ROLLBACK,唯一强保证是「执行期间不被穿插」。因此脚本要写成幂等、参数在外部校验好、尽量不触发运行时报错的形式。之所以不用 WATCH/MULTI/EXEC,是因为 MULTI 只能把命令排队,做不到「先读结果再决定后续命令」,WATCH 遇到冲突只能整段重试,高并发下重试率很高。Lua 的收益是把判断与更新合成一次网络往返、一次原子执行,代价是逻辑散在脚本里、调试和版本管理更麻烦,业务复杂后要控制脚本长度。

3. 幂等键怎么设计:幂等键的本质是给「一次业务意图」发一个唯一标识,通常由客户端生成(UUID、雪花号)随请求上行,服务端在入口用它去重。放在客户端生成更贴合语义,因为用户重复点击应当被识别为同一次意图。写入时机最关键:必须和业务处理处在同一段原子逻辑里,实践上就是放进 Lua 脚本一起执行,用 SETNX 或状态位记录三态——处理中(先占位并带短 TTL,挡住并发重复进入)、成功、失败。先处理业务再写幂等键,中间宕机就会出现「钱已扣、无记录」的窗口,重试必然重复;先写幂等键再处理业务,则必须能识别处理中状态,让后来者快速失败或短暂轮询。失败结果要不要缓存取决于失败类型:余额不足这类确定性失败可以缓存以便快速返回,超时、依赖不可用这类瞬时失败应当允许重试。更稳的做法是把幂等键与业务状态放在同一存储、同一事务里(MySQL 唯一索引 + 状态机),Redis 只当前置快速拦截层。

4. 竞拍与秒杀的并发裁决:核心矛盾是「读—判断—写」不是原子操作:两个请求都读到当前价 100、都判断 110 大于 100,后写入的 105 会覆盖先写入的 110。三条路里,数据库悲观锁性能差,乐观锁版本号在冲突密集时重试多,把裁决收敛到单点执行才是主流,也就是 Redis Lua。脚本内要依次校验:拍品是否在有效期内、用户有没有出价资格与保证金、出价是否高于当前最高价并满足最小加价幅度、是否超过封顶价,全部通过才写入最高价和出价人,并把出价流水推进 Stream。落库走异步:消费者组读取 Redis Stream,用 XACK 加待处理列表兜住「读到一半进程挂掉」,消费端用幂等键或 MySQL 唯一索引防重复写。最终结算以 MySQL 为准,Redis 只是热路径加速层;要保证一致性,就用品类状态机把状态原子地从「竞拍中」切到「已结算」,其后的出价一律拒绝,结算读冻结的快照而不是还在变的实时值。

5. 缓存穿透:查一个数据库里也不存在的 key,缓存永远不命中,请求全部落到数据库,被恶意构造不存在的 id 时足以打垮 DB。三种手段:入口做参数校验,格式、范围、权限先过滤掉明显非法的请求;缓存空值,查不到时也写一个带短 TTL(30~60 秒)的空标记,代价是短暂不一致,且要防止大量随机 key 把内存打满;布隆过滤器,把所有存在的 key 预先映射到位图,查询前先过一遍,判定不存在就直接返回,它有小概率误判但不漏判,适合当前置拦截。布隆过滤器的难点是删除与扩容——标准实现不支持删除,可以用计数布隆或定期重建,数据量大时也可换 Cuckoo Filter。生产上通常是三者叠加,再配全局限流兜底。

6. MySQL 索引:B+ 树与设计原则:InnoDB 选 B+ 树是因为它矮胖:非叶子节点只存键值和指针,一个 16KB 页能放上千个键,三四层就能覆盖千万级数据,磁盘 IO 次数稳定;数据全部在叶子节点且用双向链表相连,天然支持范围查询和 ORDER BY,这是 B 树做不到的(数据分散在各层,范围扫描要中序遍历跳来跳去)。和普通二叉搜索树比,关键是树高:BST 在有序插入时退化成链表,即便平衡成红黑树,两千万数据也有二十多层,每层一次磁盘随机 IO。另一种结构是 Hash 索引(Memory 引擎默认,InnoDB 有自适应哈希索引),等值查询 O(1),但不支持范围、排序和最左前缀,冲突严重时会退化。索引不是越多越好:每个二级索引都占空间,写入时要同步维护,增删改都会变慢,优化器可选路径变多还可能选错。设计原则可概括为高频查询优先、区分度高的列靠前、尽量做覆盖索引、遵守最左前缀、避免在索引列上做函数运算和隐式类型转换,最后用 EXPLAIN 看 type、key、rows 验证。

7. CPU 与内存告警怎么排查:CPU 打满先看 top/uptime,区分用户态(us 高,业务计算密集)、内核态(sy 高,系统调用与上下文切换多)和 iowait(wa 高,磁盘瓶颈)。us 高就 top -H 找线程,把线程 id 转十六进制去 jstack 定位栈(Go 用 pprof 的 CPU profile),再用火焰图看热点调用链:横轴采样占比、纵轴调用栈,宽而平的就是优化目标。load average 是运行队列里可运行与不可中断任务的平均数,要和核数一起看;load 高而 CPU 不高,一般是 IO 阻塞或大量 D 状态进程。内存告警先看 free -h 与 /proc/meminfo,判断是堆上涨、page cache 占满还是真泄漏:Java 看 jmap/jstat 的堆与 GC 频率,Go 看 heap profile 的 inuse_space,并排查大对象、无上限的本地缓存和 goroutine 泄漏。OOM 前后看 dmesg 的 oom-killer 记录与容器 limit,确认是被内核杀还是自己退出。

8. 短链接系统设计:核心是「长转短」的映射与「短转长」的跳转。短码生成两条主流路线:发号器加 Base62 编码(自增 id 或号段模式,全局唯一、无冲突,长度随 id 增长,可加起始偏移或打散让短码不连续、不易被遍历),以及哈希取前几位(MD5/Murmur 后截取 6~7 位,需要处理冲突重试,且不可逆推)。存储用 MySQL 保存 short_code 到 long_url 的映射,short_code 建唯一索引,热点数据前面加一层 Redis;跳转用 302 还是 301 要按业务取舍,302 便于统计点击和随时改目标,301 省服务器压力但客户端会长期缓存。防遍历和防滥用靠足够大的短码空间(62^6 约 568 亿)、黑名单与风控、单用户创建配额和敏感链接审核。要进一步缩短 URL,可以从三处下手:压缩短码长度、换更短的域名(这是最大头,协议头和域名本身都占长度)、把同域名长链接的参数做归并。另外还要考虑过期策略、点击统计的异步写入,以及高并发下的缓存与限流。

9. 带 TTL 的 LRU Cache 实现:基础结构是 HashMap 加双向链表:前者 O(1) 定位节点,后者维护访问顺序,头部最近使用、尾部最久未用。get 命中后要把节点移到头部,这就是「get 也算一次最近使用」的原因;set 已存在的 key 只更新值并移到头部,只有新增 key 才判断容量,淘汰尾部节点,且淘汰必须发生在插入之前,否则中间态会短暂超过容量 N。加 TTL 后节点多存一个过期时间戳,淘汰优先级是先扫有没有过期节点、有就优先删,没有才按 LRU 淘汰尾部。清理用惰性删除加后台定时清理:get 发现过期就当作 miss 并删除以保证语义正确,同时用定时任务或采样淘汰分批清理死节点,避免内存堆积。get 到过期 key 要不要续期取决于语义——滑动过期每次访问续期,绝对过期写死时间点。并发下要加锁或分段加锁,保证 HashMap、链表指针和 size 三者同步;用 C++ 的 std::list 时节点指针不暴露,必须把迭代器存进 map 才能在 O(1) 内删任意节点,手写 Node 则要防止删除后留下悬空引用。

10. 三线程循环打印 123123:这是典型的协作而非竞争问题:三个线程不是抢同一个资源,而是按固定顺序轮流执行,所以同步机制要能表达「轮到我了吗」。最直接的写法是共享一把锁加一个状态变量:每个线程在 while 里检查 flag 是否等于自己的编号,不是就 wait 挂起,是就打印、把 flag 改成下一个编号、再 notifyAll 唤醒其他线程。三个必被追问的点:wait 必须写在 while 里而不是 if 里,因为被唤醒后条件可能又不成立(别的线程先抢到锁改了状态),这就是虚假唤醒和「唤醒后要重判」的由来;wait/notify 必须在持有锁的临界区里调用,否则抛 IllegalMonitorStateException;要用 notifyAll 而不是 notify,notify 可能唤醒到不该跑的那个,导致全部挂起。更好的写法是 ReentrantLock 加三个 Condition,每个线程只等自己的条件、用 signal 精确唤醒下一个;也可以直接用三个 Semaphore 串联。

11. ReAct 与 Plan-and-Execute 怎么选:ReAct 是 Thought、Action、Observation 交替推进,每一步先想再调工具、看到结果再决定下一步。优点是实现简单、能根据中间反馈动态调整,适合工具链短、环境变化快的任务;缺点是每步一次 LLM 调用,延迟和 token 成本高,长任务容易跑偏或陷入循环,需要最大步数、重复动作检测这类刹车。Plan-and-Execute 先让模型产出完整计划再逐步执行、必要时重规划:好处是把规划与执行解耦,执行步可以换更便宜的小模型,长任务的目标一致性更好,也更容易人工审核和展示进度;缺点是计划基于错误假设生成时前几步都可能白做,重规划本身也不便宜。选择可以按任务的确定性和长度来分:步骤少、需要频繁与外部世界交互试错的用 ReAct;步骤多、依赖关系明确、能离线拆解的用 Plan-and-Execute。实践中常见两级结构——上层拆解,下层每个子任务内部用 ReAct 执行。

12. WebSocket 与房间设计:WebSocket 靠一次 HTTP 请求完成握手(带 Upgrade: websocket 与 Sec-WebSocket-Key,服务端返回 101 切换协议),之后在同一条 TCP 连接上全双工通信,帧头只有 2~10 字节,省掉 HTTP 每请求的头部开销,属于应用层协议。竞拍场景选它而不是轮询,是因为出价要即时广播给房间内所有人。房间是逻辑概念而非实体表:以 roomId 为聚合根,Redis 里维护成员 Set、出价流水 Stream 和排行榜 ZSet。断线重连要解决「回到原房间」:连接时带上 token 与 roomId,服务端把连接注册进会话表并订阅对应频道;重连时客户端带上最后收到的事件序号,服务端从 Stream 补发断线期间的消息再续推增量,既不丢也不重复。房间数据不必落 MySQL,但结算结果必须落库,房间数据要设 TTL 或用完即删。

13. HTTPS 如何防窃听、防篡改、身份认证:HTTPS 就是 HTTP 加 TLS。防窃听靠密钥交换协商出的对称会话密钥(常用 ECDHE,具备前向安全),之后的业务数据用 AES-GCM 这类对称加密,因为对称加密比非对称快几个数量级。防篡改靠 AEAD 的认证标签或 MAC,每条记录都带完整性校验,中间人改一个字节就会校验失败。身份认证靠数字证书:服务端把公钥、域名、有效期、签发机构交给 CA,CA 用自己的私钥对证书摘要签名,客户端内置受信任的根证书,逐级验签即可确认「这个公钥确实属于这个域名」;证书链任何一环对不上、域名不匹配、过期或被吊销都会告警。TLS 1.3 握手大致是 ClientHello(带支持的套件与 key_share)、ServerHello 加证书与 Finished、双方用 ECDHE 算出共享密钥、客户端 Finished,1-RTT 完成。至于伪造证书冒充百度:攻击者没有百度的私钥,签不出能被验证的证书,自签证书不在系统信任链里会直接报错,真正的攻击面只剩诱导用户手动信任恶意根证书或 CA 被攻破错签。

14. 手撕题的常见扣分点:二分查找的坑集中在边界:循环条件用 left <= right 还是 left < right,mid 用 left + (right - left) / 2 防溢出,取整方向决定了下一轮是 left = mid 还是 left = mid + 1,写错就死循环;求第一个或最后一个满足条件的位置时模板与普通查找不同,动手前先口述要找的是哪个边界。链表反转的核心是三指针 prev、cur、next:先把 next 存下来再改 cur.next,否则链会断;循环结束返回的是 prev 而不是 cur(此时 cur 为 null);递归写法要能讲清 base case 与每层返回值的含义。面试官追问「你刚才这段代码有什么问题」,通常就是这几处:没处理空链表和单节点、没保存 next、返回值写错、变量命名混乱。K 个一组翻转是把反转限定在区间内,需要哨兵节点和区间前后指针的重新连接,最后别忘处理不足 K 个的尾部。