写点什么

美团一面,有点难度

作者:王中阳Go
  • 2025-02-13
    湖南
  • 本文字数:2474 字

    阅读完需:约 8 分钟

美团一面,有点难度

一位粉丝朋友分享了最近参与美团民宿旅游业务线的一面的经历,全程约 1 小时,面试官围绕高并发、分布式事务、性能优化等高频考点展开追问,问题密集且注重落地细节。以下是完整问题整理+回答思路+扩展解析,助你避坑!



一、项目与高并发场景

1. “介绍一个项目中的难点,并说明 QPS 和用户量峰值?”


  • 回答示例

  • 项目背景:民宿节日大促活动,瞬时流量激增(如春节、国庆),用户抢购特价房源。

  • 核心数据

  • QPS 峰值:约 8000(主要集中在活动开始前 5 分钟);

  • 用户量峰值:单日活跃用户 12 万,抢购时段并发用户 3 万+;

  • 难点

  • 库存超卖:多节点并发扣减库存的原子性问题;

  • 系统崩溃风险:流量洪峰导致服务雪崩;

  • 响应延迟:用户提交订单后长时间卡顿。


2. “高并发下如何设计抢购功能?异步订单处理具体做了什么?”


  • 详细方案

  • 异步削峰

  • 用户点击下单后,前端直接返回“排队中”状态,请求进入 MQ 队列(如 RocketMQ);

  • 后端消费者分批拉取消息,通过 Redis Lua 脚本原子性扣减库存

  • 库存扣减成功则生成订单,失败则 MQ 重试(限制最大重试次数,避免死循环)。

  • 防超卖补充

  • 预扣库存:活动开始前预热 Redis,库存按房源 ID 分片存储;

  • 库存回滚:用户 15 分钟内未支付,系统自动释放库存(通过延迟队列实现)。


3. “如何用 Lua 脚本保证不超卖?限流除了令牌桶,还有其他方案吗?”


  • Lua 脚本示例


  local stock = redis.call('get', KEYS[1]) -- 获取库存    if tonumber(stock) > 0 then      redis.call('decr', KEYS[1])          -- 扣减库存      return 1 -- 成功    else      return 0 -- 失败    end  
复制代码


  • 限流方案对比

  • 令牌桶(Guava RateLimiter):允许突发流量(如预热期积攒令牌),适合秒杀场景;

  • 漏桶:恒定速率处理请求,保护下游系统(如数据库);

  • 滑动窗口(Sentinel):实时统计时间窗口内请求量,精准控制流量。


4. “Redis 集群用了多少机器?选举机制和设计模式如何应用?”


  • 集群架构

  • Redis Cluster:共 6 主 6 从,每个分片承载约 1.3 万 QPS;

  • 选举机制:主节点故障时,从节点通过 Raft 协议投票选举新主;

  • 设计模式实践

  • 策略模式:根据不同活动类型(如限时折扣、拼团),动态选择库存扣减策略;

  • 观察者模式:订单状态变更时,通知营销系统(发放优惠券)、日志系统(记录行为)。



二、分布式事务与锁

5. “项目中分布式事务如何实现?2PC 和 TCC 有什么区别?”


  • 最终一致性方案

  • 下单主事务:本地事务中插入订单记录,同时写入消息表(状态为“未发送”);

  • MQ 异步通知:事务提交后,扫描消息表发送 MQ(若发送失败,定时任务补偿);

  • 库存服务消费:保证幂等性(通过唯一订单 ID 去重),扣减真实库存。

  • 方案对比

  • 2PC

  • 优点:强一致性(如 XA 协议);

  • 缺点:同步阻塞(协调者单点问题)、MySQL 性能瓶颈;

  • 适用场景:银行转账、资金扣减。

  • TCC

  • Try 阶段:预留资源(如冻结库存);

  • Confirm/Cancel 阶段:确认或释放资源;

  • 缺点:业务侵入性强,需自行实现回滚逻辑。


6. “分布式锁除了 Redis,还有哪些实现方式?”


  • Redis 分布式锁陷阱

  • 误释放锁:A 线程超时导致锁过期,B 线程加锁后 A 完成操作误删 B 的锁;

  • 解决方案:value 存储唯一 ID(如 UUID),删除时校验归属;

  • ZooKeeper 方案

  • 创建临时有序节点,最小节点获得锁;

  • Watch 机制监听前序节点释放,避免惊群效应;

  • 优点:无超时问题;缺点:性能低于 Redis。



三、性能优化与问题排查

7. “慢 SQL 优化时,执行计划要关注哪些参数?”


  • EXPLAIN 关键字段

  • typeconst(主键查询) > range(索引范围扫描) > ALL(全表扫描);

  • rows:预估扫描行数,越大性能越差;

  • Extra

  • Using filesort:需优化排序字段索引;

  • Using temporary:用了临时表,常见于 GROUP BY 未走索引。

  • 案例:某查询type=ALLrows=50w,通过添加(user_id, status)联合索引,耗时从 2s 降至 50ms。


8. “线程池参数怎么设置?拒绝策略有哪些?”


  • 参数设定公式

  • 核心线程数:CPU 密集型任务 = CPU 核数 + 1;IO 密集型任务 = CPU 核数 * 2;

  • 队列容量:根据任务特性,内存敏感场景用同步队列(如SynchronousQueue),允许丢任务;

  • 拒绝策略

  • AbortPolicy:直接抛异常(默认策略,需做好降级);

  • CallerRunsPolicy:由提交任务的线程执行(减缓提交速度);

  • 自定义策略:记录日志并触发告警(如钉钉通知研发)。


9. “线上突发 CPU 飙升,如何快速定位问题?”


  • 排查流程

  • TOP 命令:找到占用 CPU 最高的进程和线程;

  • 线程转储jstack pid > thread.log,分析线程状态(如死锁、无限循环);

  • Arthas 工具

  • thread -n 3:查看最忙的 3 个线程;

  • watch com.example.Service method '{params,returnObj}':动态监控方法入参和返回值;

  • 案例:某次 CPU 100%因日志组件异步队列阻塞,改用 Disruptor 框架后解决。



四、算法题扩展

10. “接雨水除了双指针,还有其他解法吗?”


  • 暴力解法:对每个柱子,找左右最大高度,时间复杂度 O(n²);

  • 动态规划:预处理左右最大值数组,时间 O(n),空间 O(n);

  • 单调栈:维护递减栈,计算凹槽面积,时间 O(n),空间 O(n);

  • 面试官意图:考察对多种解法的理解和时间/空间复杂度权衡。


11. “合并回文链表时,如果链表长度差很大,如何优化?”


  • 优化思路

  • 若链表 A 长度远大于 B,先遍历 A 到中间节点,再与 B 合并,减少反转次数;

  • 空间换时间:将链表 B 全部存入 List,逆序后合并(需权衡内存占用)。



五、总结与避坑指南

  1. 高频考点总结

  2. 高并发:Redis+Lua+MQ 三板斧,限流算法必须手写伪代码;

  3. 分布式事务:至少掌握 2 种方案(如最终一致性+TCC),并能对比优缺点;

  4. 性能优化:从 SQL 到 JVM 调优,需结合具体数据说明优化效果。

  5. 避坑建议

  6. 忌空谈理论:所有方案必须关联项目场景(如“为什么不用 2PC?因为 QPS 要求高,事务管理器可能成为瓶颈”);

  7. 准备项目图谱:提前画好系统架构图、表结构设计,应对“集群怎么部署”类问题;

  8. 算法刷题技巧:面试前手写高频题(如链表、二叉树、双指针),重点注释时间/空间复杂度。




最后:若你想进一步深入某个技术点(如 Redis 集群选举源码、TCC 完整实现),欢迎留言!下期可针对性拆解🔥

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我:wangzhongyang1993,备注:面试群。

发布于: 刚刚阅读数: 6
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
美团一面,有点难度_Go_王中阳Go_InfoQ写作社区