小红书 AI 小工具 leader 面:MQ 异步化、分库分表热点与稳定性
- 轮次
- leader 面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍。
- 简历里那个 MQ 解耦、QPS 提升的项目,是生产项目还是自己做的?
- 那其实你就是把同步做了一次异步转换,对吧?
- 原来同步失败前端能感知,异步失败你怎么知道,怎么保证它稳定运行?
- 你这个重试是无限制的吗?
- 如果失败了,你会漏掉消息吗?
- 这个过程怎么防止重复投递?
- 如果有顺序要求,你觉得它能做到吗?
- QPS 再提高 10 倍,你觉得瓶颈在哪里?
- 数据库层面可以解决它的问题吗?
- 按设备去分库分表,数据会均衡吗,还是会有热点?
- 有热点、有数据倾斜,你觉得有办法解吗?
- 有些表数据量特别大,你觉得还有办法继续优化吗?
- Redis 缓存你用过的数据结构有哪些?
- 如果用 Redis 做一个榜单,你会怎么做?
- 你还用了 Redis 的 bitmap 对吧,主要用在什么场景?
- 当时为什么选它,是因为量级很大吗,直接用数据库不行吗?
- 这个项目对你来说最大的难点是什么?
- 结合你现在的认知,从架构角度看这个系统有什么不足?
- 上线之后一直有人运维,稳定性这块你们做了哪些事?你怎么觉得这个系统还在稳定地跑?
- 半夜没人用的时候,哪些指标能提前发现它出了问题?
- 你平时有看过并发工具的源码吗,学到过什么?
- 你现在会用 AI 来做一些什么事情?
- 你怎么判断 AI 写的到底对不对?
- 手撕:LRU。
- 你最大的优点和缺点是什么?
- 你实习的时间计划是什么,最快多久能到岗,对实习地点有要求吗?
- 反问。
《参考解析》
同步改异步后,失败怎么被感知:同步调用的失败顺着返回值就到前端了,异步之后失败发生在消费者里,必须自己补上「失败可见」。做法是三层:消费侧捕获异常后不吞掉,按错误类型分流(可重试的进延迟重试队列,业务性失败进死信表并告警);对账——定时用业务主表与消息处理表比对,找出「有请求无结果」的孤儿记录并补;端到端可观测——每条消息带 traceId,从投递到落库全链路能串起来,看板上能看到积压量、消费失败率、P99 处理时长。重试必须有上限和退避:指数退避 + 最大次数 + 死信兜底,否则坏消息会把队列堵死。
重复投递与幂等:MQ 普遍是「至少一次」,重复无法避免,只能靠消费侧幂等。幂等键的选法很关键——用业务唯一键(订单号、请求 id、设备 + 时间窗)而不是消息 id,因为消息重投和业务重发是两回事。落地一般是一张幂等表(唯一索引 + 状态机)或在 Redis 上做 setnx + 过期,前者强一致但多一次写,后者快但要考虑过期语义。
顺序性:全局有序只能单分区单消费者,吞吐会崩;实际做法是按业务键分区——同一订单/同一设备的消息 hash 到同一分区,分区内单线程消费,就得到「局部有序 + 整体并行」。还要注意重试队列会破坏顺序:同 key 的消息重试时不能被后来的消息插队,要么阻塞住该 key 的后续消息,要么重试消息回原分区排队。
QPS 再涨十倍的瓶颈在哪:按链路逐段推。入口是带宽与连接数,然后是应用层的线程/协程与 GC 停顿,接着是 DB 的连接数与写入能力,最后是 Redis 的单分片 QPS 和网络往返。真正先崩的通常不是「算不过来」,而是连接池打满 + 慢查询 + 锁等待三者互相放大。数据库层能缓解的招是:写入合并/批量提交、冷热分离、读写分离、按业务键分片;但分片会引入跨片查询和分布式事务的成本,得算清楚。
分片热点:按设备号 hash 理论上均匀,现实里会偏——头部设备/大客户贡献了不成比例的流量,hash 只保证「键分散」不保证「负载分散」。解法分两类:打散(对热点键加后缀拆成 N 份,查询时扇出合并)、隔离(热点单独建库或单独一条链路,避免拖累长尾)。监控上要能画出分片间的 QPS/容量分布,不能只看总量均匀。
Redis 榜单与 bitmap 的选型:实时榜单用 ZSET——score 是分数,ZINCRBY 累加、ZREVRANGE 取 TopN,日榜/周榜可以用 key 加时间后缀,配合过期自动清理。bitmap 适合「海量 id 的布尔状态」:签到、是否活跃、是否已读,一个用户一天一位,1 亿用户一个月只要几百 MB;用 SETBIT/BITCOUNT/BITOP 做统计和交集。选它而不是数据库的原因是空间和原子性:数据库存一行一状态,同样的量级存储和统计成本高一个数量级;但它的代价是只能表达布尔、不支持复杂查询,需要额外的维度就得换结构(比如 HLL 做去重计数)。
稳定性怎么证明它在跑:不能只说「没出过事」。要有分层指标:资源层(CPU、内存、连接数、GC 次数与停顿)、应用层(QPS、P95/P99 延迟、错误率、线程池队列长度)、业务层(下单成功率、消息积压量、对账差异数)。深夜没人用时最该看的是趋势型指标:内存是否缓慢上涨(泄漏)、连接数是否只增不减(泄漏)、定时任务是否按时执行、慢查询数量是否在爬。再看告警是否真的会响——定期人为制造一次失败验证告警链路,比堆一堆没人看的监控有用。
手撕 LRU:哈希表 + 双向链表,get 命中就把节点移到头部,put 超容量就删尾节点。要点是哨兵头尾节点省掉边界判断、get/put 都 O(1)、注意「put 已存在的 key 要更新值并移到头部」。