美团 AI应用开发 一面

1. 做一下自我介绍

2. 如果一个核心链路已经同步调用很多下游了,为什么还要引入消息队列,而不是继续堆线程池

消息队列真正解决的不是“异步”两个字,而是削峰、解耦、容错和流量治理。同步链路堆线程池只能把等待成本从调用方挪到自己进程里,并不能改变系统容量边界;一旦下游抖动,请求会在调用链上层层堆积,最终把连接池、线程池和网关超时一起拖崩。引入 MQ 后,主链路可以只做核心事务,非核心逻辑异步化,下游能力不足时也能通过堆积和消费速率控制做缓冲。不过 MQ 不是银弹,如果业务要求强一致、低延迟、同步结果可见,盲目异步反而会把复杂度转移到补偿和状态机里。

3. 从生产端到消费端,怎么把“消息不丢”这件事讲完整

消息不丢从来不是某一个组件的承诺,而是一整条链路共同完成的。生产端需要有发送确认、失败重试、消息落库或事务消息兜底;Broker 侧要有刷盘策略、副本同步、故障恢复和积压治理;消费端必须做幂等、失败重试、死信隔离和位点提交控制。很多人说“MQ 保证可靠性”,其实最多保证消息尽量送达,不能保证业务一定执行成功。真正线上稳定的是“消息可靠传递 + 消费结果幂等 + 补偿闭环”,而不是单纯开个重试。

public void onMessage(OrderEvent event) {
    if (consumeLogRepository.exists(event.getBizId())) {
        return;
    }
    try {
        orderService.handle(event);
        consumeLogRepository.save(event.getBizId());
    } catch (Exception e) {
        throw e;
    }
}

4. 线上说系统能扛多少 QPS,这个值你怎么测出来,怎么判断瓶颈到底在哪

QPS 不是压出来一个峰值就算数,必须结合延迟、错误率、资源利用率和稳定持续时间一起看。通常会先明确压测场景,区分读多写少、冷热数据、是否命中缓存、是否包含下游依赖,再逐层观察 CPU、GC、线程池、连接池、网络带宽、磁盘 IO 和数据库执行时间。真正的瓶颈定位不是看哪个指标最高,而是看链路里哪个资源最先饱和并开始放大尾延迟。很多系统表面上 CPU 不高,但其实是线程阻塞、锁竞争、下游超时或连接池耗尽导致吞吐上不去。

5. 你在使用消息队列的过程中遇到过最棘手的问题是什么,最后怎么收敛的

比较典型的棘手问题不是“不会发消息”,而是消息重复、乱序、消费放大和异常重试叠加之后把业务状态打乱。比如订单履约链路里,一个状态变更事件因为网络闪断触发重复投递,消费者又带有重试逻辑,最后库存回滚和优惠券补偿都被执行多次。最后的收敛方式通常不是调大超时,而是把事件做业务主键幂等、把状态流转做成有限状态机,再把重试策略和补偿任务拆开。这样即使发生重复或乱序,状态仍然能自洽。

6. 消息积压突然出现时,你会怎么区分是生产端突刺、消费端退化,还是中间件本身异常

先看堆积曲线是不是短时突刺还是持续增长,如果短时拉高后能自动消化,通常是流量峰值;如果持续堆高,说明消费能力长期低于生产速度。接着要拆消费者侧,看单条处理耗时、线程池活跃数、批量拉取参数、下游依赖耗时、失败重试次数和死信增长情况。如果 Broker 监控显示分区分布异常、磁盘刷盘变慢或副本同步延迟,也可能是中间件问题。真正排查时最怕只盯 MQ 面板,因为堆积往往只是结果,根因经常在数据库、缓存击穿、RPC 抖动或者消费逻辑锁冲突。

7. 用 Redis 做分布式锁时,setNx 的 key 和 value 为什么都不能随便设计

key 决定锁的粒度,value 决定锁的归属。key 如果设计得太粗,会导致不相关请求相互阻塞;太细则无法保护共享资源,锁等于白加。value 必须是全局唯一标识,比如请求 ID 或实例 ID 加线程标识,因为释放锁时要判断“是不是自己加的锁”,不能谁都能删。很多线上事故不是锁没加上,而是锁过期后被别的线程拿到,原线程执行完又把别人的锁删了,这就是为什么一定要 compare-and-delete。

if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

8. 数据库里为什么很多高并发更新场景更倾向于乐观控制,而不是一上来就悲观锁

因为悲观锁的前提是假设冲突很频繁,所以先锁住再说,但在线上很多热点更新场景里,真正昂贵的是锁等待、事务持有时间和死锁风险。乐观控制更适合“冲突有,但不是常态”的情况,它把竞争推迟到提交时,通过 version 或条件更新判断是否成功。这样吞吐通常更高,也更利于扩展。不过乐观不是免费午餐,如果冲突率本来就高,重试风暴会把数据库打得更惨,所以是否用乐观控制,关键还是看数据热点和冲突模型。

9. 悲观锁和乐观锁真正的分界线是什么,怎么根据业务挑选

分界线不在于哪个“更高级”,而在于你对冲突的预期、失败成本和业务语义。像库存扣减、热点账户余额、少量强冲突资源,悲观锁更容易把语义收紧;但像用户资料更新、状态位修改、配置变更这类读多写少或冲突概率低的场景,乐观控制能明显减少阻塞。更高阶一点的判断是看失败是否可重试,重试代价高不高,失败是否会影响用户体验。如果重试成本远高于等待成本,乐观未必是更优解。

update coupon_account
s

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

AI-Agent面试实战专栏 文章被收录于专栏

本专栏聚焦 AI-Agent 面试高频考点,内容来自真实面试与项目实践。系统覆盖大模型基础、Prompt工程、RAG、Agent架构、工具调用、多Agent协作、记忆机制、评测、安全与部署优化等核心模块。以“原理+场景+实战”为主线,提供高频题解析、标准答题思路与工程落地方法,帮助你高效查漏补缺.

全部评论
佬 打扰下 考虑我司么 考虑的话 可以看我主页帖子
点赞 回复 分享
发布于 04-12 23:36 上海

相关推荐

04-10 02:40
门头沟学院 Java
给我面没招了,发点面经攒攒人品~1.项目拷打2.你在这个 RAG 系统优化里面,在多阶段 RAG 系统中采用了 BM25 和向量混合检索,然后这个是怎么去设计两者的结合逻辑的?然后混合策略的话具体是如何去提升检索效果的?3.RAG支持 PDF 扫描件和 OCR,然后还有表格结构化的提取,然后在这过程中有没有遇到什么技术难点?4.识别准确率怎么样?5.这个多智能体系统设计里面,然后它的这个 State 管理和Checkpoint分配机制的具体实现方式是什么?怎么去解决对话执行中的状态竞争问题呢?6.怎么样实现 State 全局管理?7.将Choice 接口封装为MCP工具的时候,怎么去设计一个标准化接口?然后遇到有没有遇到过一些兼容性的挑战?8.举了项目里的一个例子,问我出参入参是怎么去定义的?9.大模型在调用这个工具的时候,比如说有 MCP 之前,它的调用的处理流程是什么样子的?10.或者说 MCP 它有哪些缺点或者挑战呢?11.提供的这个 MCP 的结果它是流式的吗?12.这个多agent项目是主子agent的项目吗?13.其中一个功能,然后它的 token 就是一次会话 token 大概有多少?有没有超过上限?14.模型用的哪个?我答Qwen,问我Qwen具体哪个版本15.在子任务过程中啊,如果它的某个子任务失败,比如说数据获取为空,它的这个整个工作流是怎么去重试或者是降级处理的?16.在实现这个流式输出实现的时候,比如说后端用了 FastAPI 和 SSE 来实现中间结果的实时流式输出。然后在这个 Langchain 这种基于图的状态机框架中,是怎么捕获每个 node 的执行结果,然后推送到前端的?17.LangGraph 和Langchain 为什么选择了 LangGraph 没有选择简单的那个 Langchain 呢?18.Checkpoint 的持久化19.对话之后重新连接的话,是怎么能够恢复到之前的那个状态呢?20.对话持久化的话,是存储到哪里的?是存储到内存里面,还是存到硬盘上面去的?21.关于 RAG 的,向量数据库在选择建索引的时候是用了哪种向量数据库?为什么?22.这里面你提到了 RRF 重排序,然后有没有引入什么模型进行精排?
查看22道真题和解析
点赞 评论 收藏
分享
牛客28967172...:跟着卡子哥才是正道,灵茶属实不太行
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务