刚出的百度面经,问得很真实:从 GMP 到库存扣减,这些题一定要会

28 阅读14分钟

最近训练营学员给我们分享了一篇很新的百度后端面经,题目还挺典型,尤其是 Go 并发、锁、调度模型、库存扣减、系统重构这些内容,问得很细,也很贴近真实项目。

这篇我就不搞太复杂,直接把面试里出现的重点题目和回答思路整理出来。准备后端面试的同学,特别是 Go 方向,建议认真过一遍,很多题不是只会概念就够了,面试官更想听你怎么结合项目去讲。

题目主要集中在这几个方向:

1. Go 的内存逃逸,面试官一般会怎么问?

这个问题很常见,很多人知道“逃逸到堆上”,但一展开就说不清。

可以怎么答

先说定义:

内存逃逸,本质上是编译器在编译阶段分析变量的生命周期。如果一个变量不能确定只在当前函数栈帧内使用,或者它的生命周期超过了函数调用本身,那它就可能不会分配在栈上,而是分配到堆上。

常见会发生逃逸的场景

第一,在函数里返回局部变量的指针。 因为函数结束后,栈帧本来要销毁,但这个变量还被外部拿着用,所以只能放到堆上。

第二,把指针或者带指针的值发送到 channel。 因为编译时没法确定到底哪个 goroutine 什么时候取走这个值,所以生命周期不好判断,容易逃逸。

第三,切片里存放指针或者带指针的对象。 比如 []*string 这种,切片里的引用对象通常会逃逸到堆上。

第四,slice 扩容。 append 之后如果超过容量,底层数组可能重新分配,新分配的那部分往往是在堆上。

第五,在 interface 类型上调用方法。 因为 interface 的真实实现要到运行时才知道,所以相关对象更容易发生逃逸。

面试加分说法

你可以补一句: “逃逸不等于坏事,Go 编译器这么做是为了保证正确性。真正要关注的是,逃逸过多会带来额外 GC 压力,所以性能敏感场景会尽量减少不必要的逃逸。”

这一句说出来,整体就会更像有实战经验的人。


2. GMP 调度模型,协程能不能无限创建?

这题很爱和项目里的高并发一起问。

先把 GMP 讲清楚

G 是 goroutine,P 是调度器里的处理器,M 是真正执行任务的线程。Go 调度的核心,就是 P 把 G 分配给 M 去跑。

面试里可以顺着说这几个点:

  • P 有本地队列,优先从本地取 G 执行
  • 本地没活了,会尝试从全局队列拿
  • 再拿不到,就可能去别的 P 那里做 work stealing
  • 如果 goroutine 因为系统调用或者 IO 阻塞,P 会尽量和 M 分离,避免影响其他 G 的调度

协程能不能无限创建?

不能。

理由可以从 3 个方面讲:

第一,内存有限。 每个 goroutine 初始栈虽然只有 2KB,但如果量很大,内存照样扛不住。

第二,调度有成本。 goroutine 太多,调度队列会积压,线程切换、任务切换都会带来开销。

第三,线程和系统资源也有限。 M 不是无限的,goroutine 一旦大量阻塞,也会拖垮整体调度效率。

面试建议

如果你项目里做过协程池、并发控制,这里一定要带一句: “理论上 goroutine 很轻量,但工程上仍然要控制并发,常见做法是 worker pool、信号量、限流或者任务队列。”


3. 并发量上来后用了锁,结果 panic 了,服务直接退出,怎么排查?

这题特别像真实线上问题,回答时一定别只说“看日志”。

一个比较完整的排查思路

第一步,先定位 panic 类型

先看日志和堆栈,确认到底是什么 panic。常见的有:

  • nil 指针解引用
  • 切片或数组越界
  • map 并发读写
  • 重复 close channel
  • 类型断言失败
  • 除零
  • 资源关闭后继续调用

第二步,看是不是 OOM 或 goroutine 泄漏

如果并发量起来后内存暴涨,那要重点排查:

  • goroutine 数量是否异常增长
  • 是否有 goroutine 卡在 channel、锁、网络请求上
  • 是否存在任务堆积导致资源迟迟不释放

第三步,检查锁的使用方式

重点看这几个问题:

  • 锁粒度是不是太大
  • 锁里有没有放慢操作,比如 DB、RPC、磁盘 IO
  • 有没有嵌套锁或循环等待
  • 有没有忘记释放锁
  • 是不是有共享资源漏加锁,比如 map 只对写加锁、读没加锁

第四步,再看依赖资源是不是顶满了

比如:

  • 数据库连接池满了
  • 下游服务超时
  • 某个依赖阻塞,导致大量 goroutine 堆积

这题怎么说更像实战派?

你可以补一句:

“如果是线上服务,我会先止损,比如 recover 兜底、限流、降级,再去定位根因。因为 panic 导致整个服务重启,影响的不只是当前请求,而是整体可用性。”

这样回答会更成熟。


4. 聊聊你对 mutex 的理解

这题如果只回答“互斥锁,保护共享资源”,基本不够。

可以这么展开

sync.Mutex 是 Go 里的互斥锁,用来保证同一时刻只有一个 goroutine 能进入临界区,主要是保护共享资源的并发安全。

你可以继续说的点

1)它简单直接

常用就是 LockUnlock,Go 1.18 之后也支持 TryLock

2)底层效率还不错

底层依赖原子操作和信号量机制,轻竞争时开销低,重竞争时会进入等待和唤醒流程。

3)它不是可重入锁

同一个 goroutine 拿到锁以后,如果不释放,再次获取通常会出问题,所以设计时要避开重复加锁。

4)它有普通模式和饥饿模式

这一点很多人答不到,如果你提到,面试官一般会觉得你对底层有了解。

项目里怎么用?

可以举几个真实场景:

  • 保护全局 map
  • 做并发安全计数器
  • 管理资源池,比如连接池、对象池

5. channel 怎么理解?有缓冲和无缓冲有什么区别?

这题本身不难,但很容易答得太空。

无缓冲 channel

无缓冲更像同步通信。发送和接收双方都要准备好,数据才能真正传过去。 所以它很适合做 goroutine 之间的同步配合。

有缓冲 channel

有缓冲更适合做异步解耦。 只要缓冲区还没满,发送就不会立刻阻塞;只要缓冲区里有数据,接收也不用等发送方在线。

面试回答建议

不要只停留在定义,可以顺带补一句:

“我一般会根据业务目标来选。如果是任务通知、控制执行顺序,偏向无缓冲;如果是生产消费、削峰填谷、异步处理,偏向有缓冲。”


6. 协程池怎么理解?平时怎么用?那进程池呢?

这题本质上考的是“你会不会控制并发”。

协程池的核心价值

协程池的作用主要有两个:

  • 复用 goroutine,减少频繁创建和销毁的成本
  • 控制并发数,避免 goroutine 数量失控

日常怎么用?

可以结合你做过的项目场景讲,比如:

  • 批量发消息
  • 批量调用第三方接口
  • 批量处理任务队列
  • 爬虫、导入导出、异步重试等场景

至于进程池

如果面试官追问,你可以这么答:

Go 里平时更常见的是 goroutine 池,进程池在 Go 后端业务里不是主流方案。因为多进程通信成本更高,资源也更重,除非是做隔离性很强的任务、调用外部程序,或者某些需要进程级隔离的场景。


7. 项目里做系统重构,一般会考虑哪些因素?

这是典型项目题,很多人容易讲成“代码不好维护所以重构”,太空了。

这份面经里给出的点很实用

重构的核心原因包括:

  • 超时请求增多
  • 单表数据量过大,开始往分库分表方向演进
  • 业务耦合严重
  • 模块边界不清晰
  • 可维护性变差
  • 技术债越来越多,后面迭代困难

另外还可以补充:

  • 可扩展性不足,支撑不了新业务
  • 技术栈升级,比如从自研框架切到 go-zero
  • 团队和人力安排允许分阶段重构

这题怎么答更完整?

建议按“为什么重构—怎么拆—怎么平滑迁移—效果怎么样”这个顺序讲。

面试官其实最想知道的不是你知不知道重构,而是你有没有参与过有结果的重构。


8. 抽奖系统里,怎么保证奖品库存和下单前后的一致性?

这个题目非常典型,属于高并发系统设计常问题。

一个比较稳的回答方式

方案一:Redis 原子操作

可以用 Lua 脚本把“查库存 + 扣库存”封装成一个原子操作,这样能避免并发下超卖。

方案二:分布式锁 + 最终一致性

整体链路可以这样设计:

  1. 用 Redis 的 SETNX 抢分布式锁
  2. 扣库存成功后发 MQ
  3. 订单服务异步消费消息创建订单
  4. 如果订单创建失败,走补偿任务回滚库存

面试时可以顺便提一句

“一致性不是只有强一致一种方案,高并发业务里很多时候会在性能和一致性之间做平衡,库存场景常见就是先扣减、再异步落单、失败补偿,走最终一致性。”

这句很加分。


9. 抽奖项目怎么防恶意请求和安全冲击?

这题现在问得越来越多,因为系统设计已经不只是“能跑”,还要“扛得住”。

可以从这几个方向回答

限流

用 go-zero 的限流能力,按 IP 或用户维度限制请求频率,比如一分钟最多抽 10 次。

鉴权和验证码

要求用户登录,校验 JWT 或 OAuth2 token;必要时加图形验证码或滑块验证码,防止脚本刷接口。

防重复提交

每个请求带唯一 request_id,Redis 记录已处理请求,短时间内重复请求直接拒绝。

黑名单机制

对异常高频、恶意行为的 IP 或用户做封禁。

参数校验

对用户 ID、奖品 ID 等关键参数做合法性校验,避免非法参数攻击。

回答重点

别只列技术点,最好强调一句:

“安全策略不是单点措施,而是限流、鉴权、幂等、校验、黑名单多层组合。”


10. 商品库存扣减,用 Redis 还是 MySQL?

这个问题很适合拉开差距,因为它考的是你有没有理解高并发场景下的取舍。

更推荐的回答

高并发场景下,一般优先 Redis 扣库存,MySQL 做最终落库和兜底。

一个完整流程可以这么讲

1)库存预热

系统启动或者活动开始前,把 MySQL 的库存同步到 Redis。

2)扣库存

用 Redis Lua 脚本原子扣减库存,成功后发 MQ,后续异步更新 MySQL。

3)兜底方案

如果 Redis 不可用,可以降级到 MySQL 乐观锁;同时通过定时任务校验 Redis 和 MySQL 数据一致性。

为什么不直接用 MySQL 扣?

因为:

  • MySQL 是磁盘型存储,性能上限没那么高
  • 高并发下乐观锁会大量重试
  • 悲观锁又容易造成阻塞

这题如果你能把“性能 + 一致性 + 降级 + 补偿”都讲到,基本就比较稳了。


11. 业务拆分里,为什么把非必要同步流程改成异步?

这个问题其实很贴近线上优化。

面经里的例子很标准

优化前流程:

用户请求抽奖 → 扣库存 → 创建订单 → 发短信通知 → 返回结果 整个链路都串行,接口耗时高。

优化后流程:

用户请求抽奖 → 扣库存 → 先返回成功 后续订单创建、通知发送、积分更新、日志记录全都异步化。

这么做的好处

最直接的就是接口 RT 大幅下降,核心链路更短,吞吐更高,用户感知也更好。

面试答法建议

你可以顺手补充一句:

“不是所有流程都要异步,核心是区分主链路和非主链路。对用户结果无影响、允许延迟处理的步骤,更适合异步。”


12. 怎么衡量接口优化到底有没有效果?

这题很重要,因为它考的是“你优化完怎么证明自己真的优化了”。

核心指标一般看这些

响应时间

看平均 RT、P95、P99。 比如优化目标可以是 P99 从 500ms 降到 100ms 以内。

吞吐量

也就是 QPS/TPS,看单位时间处理能力提升了多少。

错误率

包括超时错误率、业务错误率。

资源利用率

CPU、内存、数据库连接池这些有没有更健康。

最好怎么说?

你可以加一句:

“优化不是只看接口变快,还要看高并发下系统稳不稳,所以我会结合压测和监控一起看,重点关注 P99、错误率和资源占用。”

这就比单纯说“看 QPS”强很多。


13. validate 库为什么能提升效率?怎么证明?

这个问题其实是在考你有没有做过工程化提效。

可以从 4 个角度说

1)减少重复代码

很多参数校验不需要再手写一堆 if-else,通过标签就能统一处理。

2)提升开发效率

开发接口时,直接写校验规则,省掉重复劳动。

3)性能可接受

高并发场景下不会成为明显瓶颈。

4)规则统一、提示统一

团队里参数规则一致,返回错误也更规范,前后端联调更顺。

那“依据”怎么讲?

这个特别关键,别只说感觉变好了。 面经里给出的说法是:

  • 参数校验相关 bug 率明显下降
  • 压测下校验部分 CPU 占用率下降

这类回答说明你不是“主观觉得提效”,而是拿指标说话。


14. 相似算法做文章推荐,结合布隆过滤器去重,完整流程怎么讲?

这题属于“算法 + 工程实现”结合,答得好很加分。

可以按业务链路来讲

1)数据预处理和特征提取

收集文章内容、用户点击阅读行为,用 TF-IDF、Word2Vec 或 BERT 提取文章特征。

2)召回候选文章

基于用户历史阅读文章,计算相似度,或者用协同过滤召回候选集。

3)用布隆过滤器做去重

为每个用户维护已读文章集合的布隆过滤器。 候选文章过一遍过滤器:

  • 过滤器判定不存在,那就一定没读过
  • 如果判定存在,可能是误判,再查数据库确认

4)排序

按相似度、热度、发布时间等综合排序,选出最终结果。

5)更新数据

用户读了新文章后,把文章 ID 加进布隆过滤器,同时落库更新阅读记录。

面试官为什么喜欢问这个?

因为它能同时看出你对推荐流程、去重思路、空间换时间设计、误判处理这些内容到底熟不熟。


最后说几句

看完这份面经,能明显感觉到一个趋势: 现在后端面试越来越不只是问八股,更多是在问你有没有把基础知识和项目真正连起来。

像 Go 的逃逸分析、GMP、mutex、channel,这些是基础。 但库存一致性、异步拆分、限流防刷、性能指标、系统重构,这些才是面试里真正拉开差距的部分。

如果你最近也在准备 Go 后端面试,我的建议就一句:

一定别只背概念。每一个知识点,最好都能落到“项目里我怎么用、为什么这么做、效果怎么样”这三个问题上。

这样答出来,面试官会更容易觉得你是能真正上手做事的人。


END

写在最后:

最近私信问我面试题的小伙伴实在太多了,一个个回有点回不过来。

我花了两个周末,把星球里大家公认最容易挂的 AI/Go/Java 面试坑点 整理成了一份 PDF 文档。里面不光有题,还有解题思路和避坑指南。

想要的同学,直接关注并私信我 【面试】,我统一发给大家。