本文 的 原文 地址
尼恩说在前面
在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:
流量暴涨,突然提升100倍QPS, 怎么办?
如果某个业务量突然提升100倍QPS你会怎么做?
最近有小伙伴在面试 阿里,又遇到了相关的面试题。小伙伴懵了,因为没有遇到过,所以支支吾吾的说了几句,面试官不满意,面试挂了。
有些伙伴一听完题目,就不假思索回答,就是 扩容 / 加机器 。
当然,这个不能算错,但是你只得其中一小点的分数,肯定不及格的。
作为一名优秀的后端架构师,我们应当从多个维度去思考这个问题,尽可能回答完整、详细、正确。
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
尼恩 团队给大家做了一个总结出来一个 (“压、分、缓、异” / ” 限、降、扩 、监” / ” 演 ”) 9字 真经 ,每一个维度都不能少哦 :
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V171版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,回复:领电子书
另外,此文的内容, 收入尼恩的《 五大 GC 学习圣经 》PDF , 帮助大家 吊打 面试官。
高并发架构 9字 真经(“压、分、缓、异” / ” 限、降、扩 、监” / ” 演 ”)
1. 压(压力测试)
通过模拟线上真实流量和场景,验证系统在极限负载下的表现。
需关注吞吐量、响应时间、错误率等核心指标,并使用工具如JMeter或WRK进行故障注入测试流量。
2. 分(分而治之 )
- 服务拆分:微服务架构隔离核心功能,提升扩展性。
- 数据分片:如订单号哈希分库分表,解决集中式存储瓶颈。
- 读写分离:降低主库压力,提高查询性能。
3. 缓(多级缓存)
构建客户端/CDN/Redis/数据库多级缓存,减少数据库访问。需处理缓存穿透(布隆过滤器)、雪崩(随机过期时间)等问题。
4. 异(异步化)
- 消息队列:如RocketMQ实现流量削峰和解耦。
- 异步I/O:非阻塞处理提升吞吐量。
5. 限(流量控制)
- 算法:令牌桶、漏桶或动态限流(如Guava RateLimiter)。
- 分级限流:按API优先级差异化控制58。
6. 降(服务降级)
流量暴增时关闭非核心功能(如评论推荐),保障核心链路可用。
7. 扩(弹性扩展)
- 横向扩展:通过容器化/K8s快速扩容实例。
- 资源池化:如数据库连接池复用资源。
8. 监(立体监控)
-
指标监控:Prometheus+Granfa看板
-
链路追踪:Skywalking全链路分析
-
智能预警:基于机器学习异常检测
9. 演(混沌工程)
模拟网络延迟、节点宕机等故障,验证系统容错能力,实现系统在 局部故障/分区故障场景下,整体的可用性能达到 99.99% 甚至 999.99% 。
9字真经 的 实战价值
某云厂商2023年42个崩溃案例显示,未分片数据库锁冲突(占比89%)、缓存穿透(76%)等是高频故障原因。
分片后系统QPS从2.1万提升至14.6万,异步处理吞吐量提升6倍,动态限流使恶意请求拦截率达99.2%,混沌演练将故障恢复时间从136分钟缩短至23分钟。
高并发设计无银弹,需通过“压、分、缓、异” / ” 限、降、扩 、监” / ” 演 ” 9字 真经 构建系统性解决方案,并结合实战持续优化架构,提升系统韧性与可用性。
第一字真金: 压(压力测试)
通过模拟线上真实流量和场景,验证系统在极限负载下的表现。
需关注吞吐量、响应时间、错误率等核心指标,并使用工具如JMeter或WRK进行故障注入测试流量。
设计压测方案
明确压测目标与范围
-
确定目标 :
明确压测的目的,如评估系统在高并发场景下的性能表现、确定系统的最大承载能力、验证系统在特定业务场景下的稳定性等。
例如,目标是确定系统在 100 倍 QPS 下的各项性能指标(如响应时间、吞吐量、错误率等)。
-
划定范围 :
确定压测涉及的业务模块、功能接口、服务器组件等。
如对电商系统的商品详情页接口、下单接口、支付接口等进行压测,以及对应的 Web 服务器、应用服务器、数据库服务器、缓存服务器等。
准备压测环境
-
搭建测试环境 :
尽量模拟生产环境的硬件配置、网络拓扑结构、软件版本等,确保测试结果具有代表性。
如在测试环境中(或者 预生产环境) ,配置与生产环境相同数量和型号的服务器(共 38 台,其中 Web 服务器 CPU 配置为 8 核、内存 16GB,应用服务器 CPU 配置为 16 核、内存 32GB 等),安装相同的操作系统(如 CentOS 7.9)、中间件(如 Tomcat 9.0.68 版本)、数据库(如 MySQL 8.0.30 版本)等。
-
部署压测工具 :
选择合适的压测工具,如 JMeter cluster( 支持模拟 10 万 + 并发用户)、LoadRunner( 能精准模拟不同业务场景下的复杂用户行为)、Gatling( 擅长处理高并发场景下的性能测试)等,并在测试机上进行部署和配置。
测试机的性能应与实际用户设备相当(如配置 CPU 为 4 核、内存 8GB 的测试机 20 台),避免测试机性能不足影响压测结果。
设计压测场景与脚本
-
制定场景 :
根据业务流程和用户行为,设计多种压测场景。如模拟正常业务流量场景、高峰流量场景、突发流量场景等。
例如,在电商促销活动场景中,模拟大量用户同时浏览商品、加入购物车、下单支付的操作。
-
编写脚本 :
使用压测工具编写测试脚本,定义请求的 URL、参数、请求头、请求频率、并发用户数等。
脚本应能够模拟不同类型的用户请求和操作行为,如随机访问不同的商品页面、提交表单数据等。
设置压测指标与监控
-
确定指标 :
明确压测过程中需要监控的性能指标,如系统的响应时间(包括平均响应时间、最大响应时间、最小响应时间)、吞吐量(每秒处理的请求数)、并发用户数、服务器资源利用率(CPU、内存、磁盘 I/O、网络带宽)、错误率等。
-
部署监控工具 :
在服务器端和网络设备上部署监控工具,如 Zabbix、Prometheus、Grafana 等,实时监控服务器的各项资源指标和网络流量情况。
同时,在应用层面添加日志记录和监控点,用于分析业务代码的执行情况和性能瓶颈。
执行压测并收集数据
-
逐步加压 :
按照预定的压测场景和脚本,逐步增加并发用户数或请求频率,模拟流量从低到高的变化过程。
比如,阶梯式增长:5万→10万→15万→20万(每级稳定15分钟)
在每个压力级别下,运行足够长的时间(如每个压力级别运行 30 分钟,确保系统各项指标稳定),使系统达到稳定状态,收集稳定状态下的性能数据(如每 5 分钟收集一次数据,每个压力级别收集 6 组数据,取平均值作为该压力级别的性能表现)
-
数据收集 :
使用压测工具和监控工具收集各项性能指标数据,并记录系统在不同压力下的表现。如在 JMeter 中,可以查看每个请求的响应时间、吞吐量、错误率等统计信息;在监控工具中,可以获取服务器的 CPU、内存等资源使用情况。
分析压测结果与优化调整
-
结果分析 :
对收集到的数据进行分析,绘制性能曲线, 如响应时间 - 并发用户数曲线,吞吐量 - 时间曲线等 。通过性能曲线, 找出系统的性能瓶颈。
如发现当并发用户数达到 4 万时,响应时间从 200 毫秒急剧上升至 600 毫秒,可能是服务器资源不足(此时 CPU 使用率达到 90%)或代码存在性能问题(如某个数据库查询语句未添加索引,导致执行时间过长)。
-
优化调整 :
根据分析结果,对系统进行优化调整,然后重新进行压测。
优化的方式 一:优化代码:对未添加索引的数据库查询语句添加索引,优化前查询时间 500 毫秒,优化后查询时间 50 毫秒;
优化的方式 二:对冗余的业务逻辑进行精简,减少不必要的计算和 I/O 操作
优化的方式 三:增加硬件资源(如增加 2 台应用服务器,CPU 配置为 16 核、内存 32GB,将数据库服务器的内存从 64GB 升级至 128GB)
优化的方式四:调整配置参数(如调整 Tomcat 的线程池大小,从默认的 200 提升至 500,优化数据库连接池配置,最大连接数从 100 增加至 200 等)。
然后重新进行压测(按上述优化措施调整后,重新执行压测,压测时长 2 小时,涵盖正常、高峰、突发三种场景),验证优化效果,直到系统性能满足预期目标(如响应时间控制在 200 毫秒以内,吞吐量达到 10000 请求 / 秒,错误率低于 0.1%)。
第二字真金:分( 分而治之)
分 就是 分而治之。
服务层 分而治之: 服务层的横向扩展
接入层的核心职责: 接收用户请求, 通过多种策略(如缓存策略) 提升系统的读写吞吐量,通过多种策略(如限流策略) 防止系统雪崩, 通过多种策略(如黑名单) 提升系统的访问安全性。
服务层的核心职责: 实现核心业务逻辑, 接收用户请求参数, 完成业务处理之后最终返回HTML或者JSON给用户。
在Spring Cloud分布式应用中, 接入层通过LVS或者Nginx可以将请求路由到服务层多个Spring Cloud Gateway网关服务, 请求顺利从接入层进入服务层。 服务层的横向扩展高并发架构可以分为:
- 微服务网关的高并发横向扩展。
- 微服务Provider(提供者) 的高并发横向扩展。
- 微服务Provider的自动伸缩。
微服务网关 横向扩展
当微服务层网关Spring Cloud Gateway成为瓶颈时, 可以进行横向扩展: 增加服务节点数量, 新增Spring Cloud Gateway服务的部署。
在接入层Nginx配置中配置新的Spring Cloud Gateway的IP和端口就能扩展服务网关的性能, 做到理论上的无限高并发。

微服务 Provider 横向扩展
微服务网关Spring Cloud Gateway, 相对于接入层网关Nginx区别在于,微服务网关能自动发现后端微服务Provider(提供者) , 而接入层网关仅有反向代理、 负载均衡的作用, 并不能进行后端微服务Provider的自动发现。 当微服务Provider有所变化时, 微服务网关,借助注册中心(Nacos,Eureka等),能够对目标Provider进行动态发现、 动态的负载均衡, 而接入层网关却做不到这点。
在生产环境上, 一旦发现Java服务(微服务Provider) 集群的吞吐能力不足, 具体来说就是集群吞吐量不足以支撑线上的用户请求规模, 就需要进行微服务Provider的高并发横向扩展, 开启新的Java服务。

微服务 Provider 的自动伸缩
微服务Provider的自动伸缩也叫作自动扩容、 自动缩容。 自动伸缩是和手动伸缩相对而言的,就是通过运维工具实现资源监控, 然后根据资源的紧张程度自动开启新的Java服务( 微服务Provider) , 或者自动关闭一些空闲的Java服务。
传统的微服务Provider扩容策略是手动的, 由运维人员手动进行。 一旦发现现有的微服务Provider能力不够, 运维人员就会开启新的Java服务并且动态地加入集群; 一旦发现现有的微服务Provider能力有富余, 运维人员就会关闭部分Java服务, 这些Provider会动态地离开集群(自动下线)。
手动伸缩的问题是无法面对突发流量。 一旦出现突发流量, 等到运维人员收到监控系统的资源预警信息后再去进行微服务Provider扩容, 中间会有较大的时间延迟, 在这个时间延迟内, 系统可能已经发生雪崩了。 所以, 对于会出现突发流量的系统需要用到自动扩容、 自动缩容的策略。
常见的微服务Provider的自动伸缩策略有以下两种:
- 通过Kubernetes HPA组件实现自动伸缩。
- 通过微服务Provider自动伸缩伺服组件实现自动伸缩。
数据层的横向扩展
在数据规模量很大的场景下, 数据层数据库涉及数据横向扩展高并发架构, 将原本存储在一台服务器上的数据层数据库拆分到不同服务器上, 以达到扩充系统性能的目的。
数据层的横向扩展高并发架构主要包括两个方面:
- 结构化数据的高并发架构方案: 分库分表。
- 异构数据、 复杂查询的高并发架构方案: NoSQL海量存储(如ElasticSearch、 HBASE、ClickHouse) 。
结构化数据:分库分表
业内对于结构化数据库(主要针对MySQL) 有一些比较共识的参考数据(基线值) :
- 单表的记录参考上限: 500万~1000万
- 单库的TPS上限: 1000~1500 TPS。
在进行架构设计时, 如果没有数据库实际的吞吐量/并发量指标值, 可以按照这些基线值进行架构设计。
为什么分库分表
为什么要分库分表? 随着数据量的增长, 数据库很容易产生性能瓶颈: IO瓶颈、 CPU瓶颈。
分库:就是将一个数据库分为多个数据库。 一个库一般最多支撑并发2000TPS, 较为合理是1500TPS。 如果吞吐量需要达到1万TPS, 则考虑分为8个库, 一个库支撑1250TPS。
分表:就是把一个表的数据放到多个表中, 然后查询的时候只查一个表。
| 场 景 | 分库分表前 | 分库分表后 |
|---|---|---|
| 并发支撑情况 | 数据库单机部署, 扛不住高并发 | 数据库从单机到多机, 能承受的并发增加了多倍 |
| 磁盘使用情况 | 数据库单机磁盘容量几乎撑满 | 拆分为多个库, 数据库服务器磁盘使用率大大降低 |
| SQL 执行性能 | 单表数据量太大, SQL 执行效率越来越慢 | 单表数据量减少, SQL 执行效率明显提升 |
亿级库表规模分库分表方案
(1)表的数量规划
假设一个系统, 其中某个表每天增长100万记录, 2年内保持稳定增长, 那么表的数据量预估为:两年数据记录总量是7.3亿(每天100万× 730天) 。
假设每个表的标准值为500万, 库中表的数量平均是146个, 若用2的幂次方形式表示, 则比较接近146的是27, 即128。 接下来, 按照128个表进行折算, 单个表存放570万(570万=7.3亿/128) 的
数据, 其数据规模也是可以接受的。
按照上面的算法, 最终按照128个的数量进行表的规划
(2)库的数量规划
假设按照TPS峰值1万的要求进行表库的规划:
相对乐观一点, 假设每个库正常承载的写入并发量是1500TPS。 那么8个库就可以承载8× 1500
= 12000TPS的写并发。
如果每秒写入不超过1万TPS, 8个库是可以胜任的。 如果每秒写入超过1万TPS, 比如5万TPS呢? 那么可以通过RocketMQ削峰+批写入的异步降级策略, 进行高并发异步批量写入。
由于RocketMQ集群的写入吞吐量可以轻松到达10万TPS级别, 所以通过RocketMQ削峰+批写入的异步降级策略, 10万TPS以内的数据写入吞吐量还是比较容易实现的。
异构化数据查询方案
比如对于订单库, 当对其分库分表后, 如果不是按照数据分片键而是按照分片键之外的商家维度或者按照用户维度进行查询, 那么是非常困难的, 性能也是非常低的。 如果需要进行跨库查询或者按照分片键之外的复杂维度去查询, 可以通过异构数据库来解决这个问题。

ES+HBase组合方案的查询过程大致如下:
- 先根据搜索条件去ES相应的索引上查询符合条件的Rowkey值。
- 然后用Rowkey值去HBase查询, 这一步查询速度极快。

ES+HBase组合方案的特点: 将索引与数据存储隔离。HBase的一个高速的特点是根据Rowkey查询速度超快,通过这种以空间换时间的方案, 可以解决根据各种字段条件进行复杂查询、 跨库查询的业务需求。
ES的优势是进行高速的分布式全文检索, 所以那些参与条件检索的字段都会在ES中建一份索引, 例如商家、 商品名称、 订单日期等。 HBase的优势是支持海量存储, 所有全量数据的副本都保存一份到Base中。
第三字真金:缓(多级缓存)
构建客户端/CDN/Redis/数据库多级缓存,减少数据库访问。
同时, 核心的 redis 缓存, 需处理 缓存穿透(布隆过滤器)、缓存雪崩(随机过期时间)、缓存 击穿 (加锁访问DB) 等问题。
在缓存层可以采用多级缓存方案,来应对流量突然激增问题,
Java 本地缓存
Java应用本地缓存简单一点的可以是Map, 复杂一点的可以使是Guava、 Caffeine这样的第三方组件。
Java应用本地缓存类似于寄生虫, 占用的是JVM进程的内存空间。
Guava Cache是Google开源的一款本地缓存工具库, 它的设计灵感来源于ConcurrentHashMap,使用多个Segments方式的细粒度锁, 在保证线程安全的同时, 支持高并发场景需求, 同时支持多种类型的缓存清理策略, 包括基于容量的清理、 基于时间的清理、 基于引用的清理等。
Caffeine是Spring 5默认支持的缓存, Spring抛弃Guava转向了Caffeine, 可见Spring对它的看重。Caffeine因为使用Window TinyLfu 回收策略而提供了一个近乎最佳的命中率。
Caffeine的底层数据存储采用ConcurrentHashMap。
因为Caffeine面向JDK8, 而在JDK8中ConcurrentHashMap增加了红黑树, 所以在Hash冲突严重时Caffeine也能有良好的读性能。
如果要在Java应用中使用本地缓存, 建议使用Caffeine组件
Nginx 本地缓存
Nginx有三类本地缓存:
-
proxy_cache(代理缓存)
-
shared_dict(共享字典)
-
lua-resty-lrucache缓存
多级缓存架构
根据分布式缓存、 本地缓存的特点, 对缓存进行分级。 在整个系统架构的不同系统层级进行数据缓存, 以提升访问的高并发吞吐量。
从Java程序在访问缓存时的距离远近的角度对缓存进行分级, 可以将缓存划分为:
- 一级缓存: JVM本地缓存, 如Guava Cache、 Caffeine等。
- 二级缓存: 经典的分布式缓存, 如Redis Cluster集群。
- 三级缓存: 在接入层的本地缓存, 如Nginx的shared_dict(共享字典) 。

不同热度的数据可以按照不同的层级进行存放:
- 对于访问热度最高的数据, 可以在接入层Nginx的shared_dict(共享字典) 缓存, 此为三级缓存(规模在1GB以内) , 比如秒杀系统中的优惠券详情、 秒杀商品详情信息, 这些信息访问得非常频繁。
- 对于访问热度没有那么高但也访问频繁的数据, 可以在JVM进程内缓存(如Caffeine) ,这部分的数据规模也不能太大, 大概在1GB以内, 作为一级缓存。、
- 对于访问热度比较一般的数据, 存放到Redis Cluster集群, 作为二级缓存, 这部分的数据规模最大, 可以以10GB为节点单位进行横向扩展。
第四字真金: 异(异步化)
- 消息队列:如RocketMQ实现流量削峰和解耦。
- 异步I/O:非阻塞处理提升吞吐量。
异步架构是一种常见的高并发架构, 与之相对的架构模式就是同步架构。
同步架构
什么是同步架构? 以方法调用为例, 同步调用代表调用方要阻塞等待, 一直到被调用方法中的逻辑执行完成, 返回结果。 这种方式下, 如果被调用方法响应时间较长, 会造成调用方长久阻塞,在高并发下会造成整体系统性能下降甚至发生雪崩。
<
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



