高性能系统常见面试题总结
高性能系统面试的底层套路只有一条:先量化瓶颈,再谈方案。本文围绕高并发通用方法论、单机优化维度、限流降级与异步化整理十道高频题,每题给出结论、原理与追问方向。
考察地图
- 方法论:高并发通用思路、瓶颈定位、性能指标。考察分析框架而非组件背诵。
- 单机优化:CPU、内存、IO、网络、锁五个维度。
- 组件与异步:缓存、读写分离、分库分表、MQ 的引入顺序,异步化的手段与代价。
- 保护机制:限流算法、降级与熔断。考察故障场景下的自保意识。
- 容量与验证:容量估算、安全水位、灰度验证。考察工程闭环能力。
- 建议自行查阅:CDN 缓存策略、分库分表中间件对比、各 MQ 产品原理——均有独立专题。
方法论与指标
高并发系统的通用优化方法论是什么?
结论:一句话概括——能不用资源就不用(缓存与裁剪),能少等就少等(异步与批量),一个不够就加机器(水平扩展),加不动就保护(限流降级)。
原理:按层次展开。减少计算与传输:CDN、Redis、本地缓存挡掉重复计算,压缩降低传输。减少等待:MQ、线程池异步化,攒批写与 pipeline 摊薄往返。扩展资源:无状态服务水平扩容加负载均衡,存储层读写分离与分片。保护系统:限流、降级、熔断、线程池隔离。顺序很关键——先用便宜手段,再动分库分表这类伤筋动骨的方案。
延伸:面试直接报「加缓存、上 MQ、分库分表」三连是大忌,等于承认没分析过瓶颈。从「瓶颈在哪一层、证据是什么」推导方案才是正确用法。
追问:为什么水平扩展要求服务无状态?提示:状态要外移到 Redis 或数据库,否则会话粘滞让负载均衡失效。
接口突然变慢,怎么定位瓶颈?
结论:自顶向下逐层排除:先确认流量与下游依赖,再沿链路查网关、应用、缓存、数据库、MQ,用「对比法」缩小范围——和昨天比、和其他机器比。
原理:排查顺序:QPS 监控看流量是否突增;下游 RT 看慢查询、Redis 大 key、HTTP 下游超时;应用自身看 GC 日志、线程池与连接池是否打满、有无锁竞争;系统层看 CPU、load、磁盘 IO。注意 P99 比均值更早恶化——长尾往往先于平均 RT 报警。
延伸:一个经典反例:RT 升高的根因常是下游接口抖动导致上游线程池队列堆积,而非自身代码变慢。「先怀疑依赖、再怀疑自己」的心智比罗列工具名更加分。
追问:CPU 高且 RT 高、CPU 低但 RT 高,排查方向有何不同?提示:前者查热点代码与 GC,后者大概率是等待——锁、IO 或下游。
QPS、TPS、并发数、P99 分别说明什么?
结论:QPS 是每秒请求数,TPS 是每秒事务数(一个事务可含多个请求),并发数是同一时刻处理中的请求数,P99 表示 99% 的请求快于该延迟值。
原理:前三者被 Little’s Law 串起来:并发数 = QPS × 平均 RT。实战意义在于解释「下游慢会把上游拖死」——RT 翻倍而 QPS 不变,并发占用就翻倍,线程池随之打满。P99 的意义是均值会掩盖长尾:一百个用户里有一个等了十秒,平均 RT 只涨一百毫秒,但那个用户的体验已经崩了。
延伸:别只背定义,带上自己系统的数字:峰值 QPS、P99 目标、线程池容量怎么按 Little’s Law 反推。能把指标和容量计算连起来,说明真管过线上系统。
追问:QPS 不变时降低 RT 一定能减少并发占用吗?提示:是,但串行链路里不可压缩的段落会限制收益。
单机优化与组件引入
单机性能优化有哪些维度?
结论:五个维度——CPU、内存、IO、网络、锁;统一方法是先 profile 找热点,再针对性消除,不猜。
原理:CPU:优化算法复杂度、消除正则与反射热点、减少不必要的序列化。内存:对象复用、警惕装箱拆箱、控制大对象带来的 GC 压力。IO:缓冲、批量、顺序写、零拷贝。网络:连接复用、协议精简。锁:缩小临界区、读写锁分离、CAS 无锁化、分段思想(LongAdder 相对 AtomicLong 的演进就是范例)。每步优化前后用基准测试对比,防止越「优化」越慢。
延伸:单机优化是最便宜的扩容——单机 QPS 翻倍等于集群机器减半。举一个具体案例,远比列维度清单有说服力。
追问:什么情况说明单机优化到头了、必须水平扩展?提示:单核打满且热点不可拆分,或内存装不下工作集。
缓存、读写分离、分库分表、MQ 该按什么顺序引入?
结论:按成本从低到高、侵入从小到大:SQL 与索引优化 → 缓存 → MQ 异步 → 读写分离 → 分库分表。
原理:索引和 SQL 优化零架构成本,永远先做。缓存挡读流量性价比最高。MQ 把非关键路径移出同步链路,顺带削峰。读多写少且单库读压力见顶时上读写分离。分库分表排最后——它一次性引入跨库 JOIN、分布式事务、扩容迁移一堆后遗症,能用读写分离顶住就别分。
延伸:顺序不是教条,核心判断是瓶颈在哪:写瓶颈时缓存无用,突发流量时 MQ 优先。能讲清「为什么我的场景跳过某一步」,才说明顺序是理解出来的。
追问:读写分离引入了什么新问题?提示:主从延迟导致刚写入的数据读不到,关键路径要强制走主库。
为什么要异步化?有哪些手段和代价?
结论:异步化把「不必立刻等结果」的工作移出同步链路,换 RT 下降与突发流量缓冲;代价是复杂度上升与一致性窗口。
原理:手段从轻到重:进程内用线程池或 CompletableFuture,跨服务用 MQ,IO 层用事件驱动模型。收益举例:下单只同步扣库存,短信、积分、风控通知全异步,RT 从五百毫秒降到一百毫秒。代价:结果从「立即可知」变「稍后可知」,需要状态查询、回调或对账补位;排查问题要跨异步边界。
延伸:判断一段逻辑能否异步的标准只有一句话——调用方此刻需要这个结果吗?用户下一步决策依赖的部分必须同步留下。
追问:线程池异步和 MQ 异步怎么选?提示:看可靠性要求——进程宕机任务能不能丢、是否跨服务边界。
保护机制
限流是什么?常见算法有什么区别?
结论:限流是按预设阈值拒绝或排队超额请求,防止系统被流量打垮;主流算法有固定窗口、滑动窗口、漏桶、令牌桶四种。
原理:固定窗口按时间窗清零计数,最简单,但窗口临界处能放进两倍阈值的突发。滑动窗口把大窗切成小格滑动统计,平滑了临界问题。漏桶按恒定速率放行,输出绝对平滑,代价是无法吸收合理突发。令牌桶按恒定速率发令牌,桶内积攒的令牌允许应对突发——生产最常用,Guava RateLimiter 与 Sentinel 默认流控都是这个思路。
延伸:两个易忽略的维度:单机限流与分布式限流(Redis 加 Lua);QPS 限流与并发线程数限流——面对慢调用,后者往往更有效。
追问:令牌桶的桶容量设多大?提示:它决定可容忍的突发量,取值要对齐下游能承受的最大瞬时流量。
降级和熔断是什么关系?什么时候触发?
结论:降级是「主动或被动砍掉非核心功能保住核心链路」;熔断是降级的一种自动触发机制——下游失败率超阈值后快速失败,给下游留恢复时间。
原理:熔断器三态:闭合时正常调用;失败率或慢调用比例超阈值后打开,请求走 fallback 快速失败;冷却后进半开,放少量探测请求,成功则闭合。降级手段更宽:大促预案关推荐位、返回缓存兜底数据、读服务降级为读快照,都属于降级。
延伸:两点经验:降级清单要在设计期排好功能优先级,出事再讨论砍哪块已经晚了;熔断参数必须对着下游 SLA 调。另外兜底逻辑不能再依赖同一个下游,否则熔断形同虚设。
追问:熔断打开期间流量去哪了?提示:走 fallback 兜底,同时半开探测决定何时恢复。
容量与验证
容量怎么估算?安全水位怎么留?
结论:从业务峰值反推:峰值 QPS 乘单请求资源消耗得到机器数,再按水位线(如 CPU 70%)和冗余系数上浮。
原理:标准步骤:拿到业务预测(如大促峰值五万 QPS);压测出单机极限(CPU 70% 时单机两千 QPS);机器数等于五万除两千得二十五台,再乘冗余系数;最后对数据库、缓存、MQ、下游接口各做一遍同样核算——整链容量由最短板决定。安全水位是故障缓冲:CPU 卡 70%、MQ 积压设告警线,为流量预估偏差和单机摘除留余地。
延伸:容量不是算完就闭环——要全链路压测验证,再用限流兜底保证「算错了也不死」。
追问:为什么水位不按 100% 利用率设计?提示:请求到达本就不均匀,叠加故障摘除后剩余机器必须接住全量流量。
优化上线后怎么验证效果?
结论:灰度发布、前后对比、监控告警、回滚预案,四件套缺一不可。
原理:先按用户或机房切 5% 小流量灰度,对比核心指标:RT 分位数、错误率、资源使用率,观察周期要覆盖流量高峰而非只看低峰。极限容量靠压测验证,别让线上流量替你裸奔。监控告警要先于用户反馈发现回归。回滚预案必须真实演练过才算 ready。
延伸:回答这题请带真实证据:优化前后 P99 从多少降到多少、机器缩了几台、观察了多久。「优化后接口更快了」九个字毫无信息量,有数字、有周期、有对比才有。
追问:灰度期间指标变好就能直接全量吗?提示:警惕缓存冷启动红利和低峰流量假象,高峰复测后再放量。

