当前位置: 首页 > news >正文

高并发下接口耗时狂飙?这3个高可用设计让QPS从500冲到5000

@TOC


上回书说完,这次来点更刺激的

Day5-1咱们聊了怎么用自定义线程池 + 连接池调优把接口从3秒拉到200毫秒,单机QPS稳在500。我记得那天晚上11点改完上线,信心满满地去睡觉,结果第二天凌晨3点……电话还是响了。

运维小哥声音都劈叉了:“哥!订单接口又炸了!现在QPS没到1000,CPU直接飙到90%,响应时间5秒起步……”

我一脸懵,赶紧爬起来看监控。好家伙,真是单机能扛500,超过500就开始排队,线程池满了直接拒绝请求。老板第二天黑着脸问我:“这系统能撑住促销吗?”我说……能。但心里直打鼓。

后来我花了三个周末,硬是把QPS从500干到了5000。用的就是今天要讲的3个高可用设计

  • 多活架构(多台机器一起扛)
  • 故障转移(Redis主从,自动切换)
  • 降级策略(关键时刻保核心,弃车保帅)

这篇你读完,直接拿配置去用,QPS至少翻10倍,还能睡个安稳觉。


一、多活架构:一台机器不行,就加三台

1. 原始场景还原

先复现一下那个凌晨的惨案。咱们有个订单查询接口,核心逻辑是查MySQL,顺带查用户标签服务(内部RPC),代码大概长这样:

@RestController public class OrderController { @Autowired private OrderService orderService; @GetMapping("/order/{id}") public Order getOrder(@PathVariable Long id) { return orderService.queryOrder(id); } }

Day5-1已经调过自定义线程池了,Tomcat也配了:

# application.yml server: tomcat: threads: max: 400 min-spare: 100

本地用JMeter压,500QPS稳稳的。但一到1000并发,错误率直接上去,RT(响应时间)暴涨。

问题出在哪?单机天花板。CPU就2核,内存就4G,400线程全满了,新的请求排队,排到超时。这就是典型的“单活”问题——流量全压在单个节点上。

2. 多活架构的落地

所谓的“多活”,听起来高大上,说白了就是多台机器同时提供服务。咱们搞三台ECS,每个上面部署同一个Spring Boot应用,然后用Nginx做负载均衡。

架构图大概这样:

用户请求 -> Nginx -> 应用节点1 (192.168.1.10) -> 应用节点2 (192.168.1.11) -> 应用节点3 (192.168.1.12)

Nginx配置超级简单:

upstream order-backend { server 192.168.1.10:8080 weight=1; server 192.168.1.11:8080 weight=1; server 192.168.1.12:8080 weight=1; } server { listen 80; location /order/ { proxy_pass http://order-backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

人话解释:Nginx把请求平均分给三台机器,每台机器的负载从1000QPS降到了300多,理论上整体能抗的QPS变成原来的3倍。

3. 实践中的血泪教训

你可能觉得这就完了?我当时也是这么以为的,配完Nginx直接压测,结果QPS只翻了一倍多,离5000还差得远。排查半天发现两个坑:

  • Session粘滞问题:如果接口用了Spring Session或JWT,Nginx默认轮询,不需要粘滞,但如果业务依赖了服务器本地内存(比如用了ConcurrentHashMap存用户状态),就会导致请求发到不同节点找不到数据。血的教训:做多活前,先干掉本地内存状态,转为Redis或分布式缓存。
  • 数据库连接数暴增:三台节点同时连MySQL,连接数从20直接飙到60,如果数据库没优化好,反而成为瓶颈。所以Day5-1的连接池调优得多机器一起考虑,每台机器的最大连接数 = 数据库总连接数 / 节点数,提前规划好。

二、故障转移:别让Redis宕机拖垮整个集群

1. 缓存雪崩的恐怖

多活搞完后,QPS上到了3000,但离5000还有距离。我一拍脑袋,加Redis!把订单数据缓存起来,数据库压力瞬间下降。

@Service public class OrderService { @Autowired private StringRedisTemplate redisTemplate; public Order queryOrder(Long id) { String cacheKey = "order:" + id; String json = redisTemplate.opsForValue().get(cacheKey); if (json != null) { return JSON.parseObject(json, Order.class); } // 查数据库,再写缓存 Order order = orderMapper.selectById(id); redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(order), 30, TimeUnit.MINUTES); return order; } }

压测一看,QPS直接冲到4500,RT降到20ms,心里美滋滋。

然后,又一次深夜,告警来了。Redis实例因为内存满了挂了,重启后所有请求穿透到数据库,数据库瞬间被打崩,集群的QPS跌到0。

这就是典型的缓存雪崩 + 单点故障:Redis只有一台主库,挂了就全完。咱们需要故障转移机制。

2. Redis哨兵模式落地

Redis Sentinel(哨兵)能自动监控主从节点,主库挂了会选举新的主库,应用层几乎无感。

配置步骤(核心):

  • 在3台机器上分别部署一个Redis实例,一主两从。
  • 给每个Redis配上哨兵监控。哨兵配置sentinel.conf
    sentinel monitor mymaster 192.168.1.10 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 15000
  • Spring Boot集成哨兵,YAML配置:
spring: redis: sentinel: master: mymaster nodes: - 192.168.1.10:26379 - 192.168.1.11:26379 - 192.168.1.12:26379 lettuce: pool: max-active: 50 min-idle: 10

这样,主库挂了,哨兵自动把从库提升为主库,你的Spring Boot应用通过哨兵拿到新地址,整个集群继续服务。我那次凌晨3点就是没配哨兵,手动登录机器改配置,足足搞了40分钟。

3. 故障转移带来的QPS提升

加了哨兵后,即使Redis出问题,故障转移在15秒内完成,期间因为熔断降级(下面会讲),接口不至于全挂,数据库也能顶住。单节点缓存可靠性从“看天吃饭”变成了自动修复,整体集群的可用性直接拉满。

数据说话:加上哨兵后,集群抗住了一波5000QPS压测,RT稳定在30ms以内,0错误。


三、降级策略:关键时刻,保命要紧

1. 不是所有功能都值得死扛

上了多活和故障转移,按理说可以躺平了。但有一天运营搞了个“新品推荐”活动,用户点进订单页时,后台会调用一个推荐服务,返回你可能喜欢的商品。这个推荐服务偶尔会慢到2秒,导致整个订单接口被拖慢。

我又被老板叫去:“为什么订单接口这么慢?推荐不显示也行啊,先把订单展示出来!”

对啊,非核心功能,关键时刻可以降级

2. Resilience4j 实现降级

Spring Boot 3.x 原生支持Resilience4j,咱们用它来实现熔断+降级

添加依赖:

<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> </dependency>

编写推荐服务调用,加上降级逻辑:

@Service public class RecommendService { @CircuitBreaker(name = "recommendBackend", fallbackMethod = "fallbackReco") public List<Product> getRecommendProducts(Long userId) { // 远程调用推荐服务,可能很慢 return restTemplate.postForObject("http://reco-service/api/reco", userId, List.class); } // 降级方法:返回空列表或默认推荐 public List<Product> fallbackReco(Long userId, Throwable t) { log.warn("推荐服务降级,返回空列表。原因:{}", t.getMessage()); return Collections.emptyList(); } }

YAML配置熔断规则:

resilience4j: circuitbreaker: instances: recommendBackend: sliding-window-size: 10 # 窗口大小 failure-rate-threshold: 50 # 失败率超过50%就熔断 wait-duration-in-open-state: 30s # 熔断30秒后尝试半开 permitted-number-of-calls-in-half-open-state: 3 slow-call-rate-threshold: 100 # 慢调用阈值 slow-call-duration-threshold: 1s # 超过1秒视为慢调用

人话解释:当推荐服务最近10次调用中失败或超时比例超过50%时,熔断器打开,接下来30秒内所有调用直接走降级方法(返回空列表),避免拖垮整个订单接口。30秒后尝试少量请求,如果恢复正常就关闭熔断器。

3. 降级策略带来的压测效果

我把这个配置上线后,再压5000QPS,即使故意把推荐服务延迟调到5秒,订单接口的RT一直稳定在40ms以内。因为一旦触发熔断,推荐调用直接短路,主流程丝毫不受影响。

对比数据

| 方案 | QPS能力 | 平均RT(ms) | 99线(ms) | 错误率 | |------|---------|-----------|----------|--------| | 单机+无缓存 | 500 | 200 | 1200 | 5% | | 三节点集群+缓存 | 4500 | 20 | 150 | 0.1% | | 集群+缓存+降级 | 5000 | 18 | 100 | 0% |

看到了吧,降级策略不光是可用性的保障,还能在异常场景下稳住性能


四、避坑指南:这些烂坑,我全踩过

⚠️ 坑1:多活≠随便加机器我早期觉得加机器就能线性提升QPS,结果加到5台时,QPS不升反降。排查发现数据库连接池满了,每台机器默认连20个,5台就是100个,MySQL配置的max_connections只有100。解决:统一调配连接池大小,用HikariCP的maximumPoolSize限制,总共别超过数据库上限。血的教训:先评估数据库和中间件的承载能力,再决定加多少节点。

⚠️ 坑2:降级方法不能有远程调用降级方法的目的是快速返回,别在里面调数据库或远程服务,否则雪上加霜。我见过有人在降级方法里查缓存,结果缓存也挂了,死循环。降级方法尽量只返回静态默认数据或本地计算。

⚠️ 坑3:缓存与数据库数据不一致加了缓存后,偶尔会出现A机器改了数据库,B机器缓存还是旧的。咱们采用先更新数据库,再删缓存的策略,并且可以用Canal监听binlog来同步。这个坑我掉进去过,搞出了一个“幽灵订单”,缓存里显示已支付,数据库却是未支付。


五、高级进阶:你以为5000就到头了?

今天讲的这些,其实只是企业级高可用的基础款。如果你还想继续往上冲,比如QPS到5万、50万,那就要考虑:

  • 异地多活:同城三节点如果整个机房挂了怎么办?数据同步、延迟处理是另一个大课题。
  • 服务网格(Service Mesh):用Istio等把降级、负载均衡做到基础设施层,业务代码可以更干净。
  • 读写分离+CQRS:数据库读写分离,查询走从库,写走主库,复杂查询走ES等。

这些内容,我在专栏后面会展开讲,带着你一步步搭建能在双十一扛住百万并发的系统


写在最后

今天从凌晨救火开始,咱们用多活架构打破了单机瓶颈,用Redis哨兵解决了缓存单点故障,最后用Resilience4j降级保住了核心接口的性能。这套组合拳打下来,QPS从500干到5000,其实只是开胃菜。

说实话,这3个设计思路能直接帮你解决80%的高并发接口性能问题,而且配置我全都贴出来了,直接拿到项目里改改就能用。但如果你想应对更变态的场景,比如大促秒杀、红包雨,那得深入学习分布式事务、最终一致性那些不得不啃的硬骨头。

这个专栏30天能带你从CRUD工程师蜕变到能扛住亿级流量的架构师。下一篇,我要跟你聊聊“接口再怎么优化都扛不住?该上消息队列了”,带你看Spring Boot 3.x整合RocketMQ的真实案例,还是老规矩,代码可运行,数据全透明。

觉得有用的,点个赞收藏,想系统学整套的,关注专栏,咱们下一篇见。

http://www.gsyq.cn/news/1472427.html

相关文章:

  • 电脑怎么录屏?告别捆绑软件和水印!3种工具从入门到进阶全搞定
  • 西安实体黄金回收就近上门:2026年6月金价973元/克,六家持证门店实测全攻略 - 余生黄金回收
  • TMPGEnc 2.54.37.135 Windows版视频转码工具包:含VCD/SVCD/DVD多制式模板、双语帮助与完整配置文件
  • VC/C++Builder/Delphi一键生成OPC DA服务器的开发套件
  • 2026最新诚信优选乌鲁木齐市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 2026最新诚信优选水富市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • Day 6:LangChain 入门——框架是双刃剑
  • 2026广州黄金回收TOP标杆:高价领先权威机构实力测评 - 奢侈品回收评测
  • 2026最新诚信优选石家庄市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • [智能体-282]:常见的中英词静态向量表以及主要参数阐述
  • VC6.0环境下可直接运行的PMAC运动控制卡图形化调试工具
  • 告别手动VL02N:5分钟教你用SAP BAPI和函数搞定交货单自动拣配与过账
  • 2026医学文献AI解读工具测评:当“循证”成为医生工作流的新标配
  • 从汽车电子到工业控制:STM32F1的CAN总线轮询发送实战解析
  • 从负载线到开关速度:三极管深度饱和的实战设计与权衡
  • 2026最新诚信优选芜湖市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 电脑本地调用DeepSeek API完整教程
  • 2026最新诚信优选寿光市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 手把手教你用OpenCV搞定鱼眼相机标定:从Pinhole+RadTan到Omni+EQUI的实战踩坑记录
  • 2026最新诚信优选吴忠市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 烟台闲置黄金回收六店报价公开|6月金价973元每克 正规门店实测汇总 - 余生黄金回收
  • 告别仿真器!手把手教你为TMS320F28377D实现串口Bootloader(附完整CMD配置)
  • 2026最新诚信优选松滋市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 2026最新祁阳市贵金属回收权威靠谱TOP5门店排行榜 黄金+铂金+白银+彩金回收及联系方式推荐 - 亦辰小黄鸭
  • 【214期】五十种U盘量产修复工具一次打包,常见主控型号几乎全覆盖
  • ESP8266玩转1.44寸屏:用TFT_eSPI的Sprite功能做流畅动画和游戏界面(附代码)
  • 广州最全宠物店对比!番禺/海珠/增城三家黎宥萌宠实地测评,哪家最值得去 - 润富黄金回收
  • FreeRTOS消息队列在STM32H7串口DMA接收中的应用:如何安全地从中断服务程序传递数据
  • 智能体开发实战:Agent Programs与Agent Experience双轮驱动
  • 利用快马平台快速构建多模态理解应用原型:基于understand anything