高并发系统的典型瓶颈在哪

大促零点那一刻,平时每秒几百的请求突然冲到几万。系统崩之前,总有一个先顶不住的环节:可能是数据库连接被打满、可能是下游接口超时拖垮线程池、可能是单机网卡跑满。高并发架构的第一原则是先定位瓶颈,再动手扩容——盲目加机器往往只把瓶颈往后推了一层。

常见瓶颈有四类:计算瓶颈(CPU 跑满)、IO 瓶颈(数据库、磁盘)、外部依赖瓶颈(第三方接口慢)、资源池瓶颈(线程池、连接池耗尽)。后两类最隐蔽——机器很闲但服务超时,多半是资源池没配好或下游拖死了线程。

本文核心知识点
  • 异步化把非关键路径从同步调用里拆出去,缩短响应时间。
  • 削峰填谷用消息队列把突发流量摊平成平稳流量。
  • 熔断降级下游故障时快速失败、返回兜底,防止雪崩扩散。
  • 弹性伸缩按流量自动增减实例,但要先算清容量。
高并发架构配图:蓝色渐变背景左侧汹涌流量光带冲向漏斗形削峰装置,经缓冲后变成平稳数据流,中间消息方块与异步处理器节点
汹涌流量先经过漏斗削峰,再被平稳地喂给后端——高并发架构的核心就在于"整形"二字。

异步化:把同步调用拆成事件驱动

一个下单接口如果同步调用了库存、优惠券、积分、消息通知四个下游,响应时间就是四者之和,任一变慢都拖垮整体。异步化的思路是:只把必须同步完成的步骤留在主链路上(扣库存、生成订单),把可以稍后做的(发通知、加积分、写日志)发到消息队列,由消费者慢慢处理。主链路变短,吞吐自然上去。

// 同步主链路:只做必须立刻完成的事
Order order = orderService.create(req);      // 本地事务,落库

// 异步:这些发完消息就返回,不阻塞响应
mq.send("order-created", orderEvent);         // 下游各自订阅消费
return order;                                 // 用户立刻拿到响应

代价是最终一致性:消息可能延迟、可能重复消费,下游要做幂等。异步化不是免费的午餐,它把"快"换给了主链路,把"对"交给了消息可靠投递与消费幂等。

削峰填谷:流量整形的几种手段

突发流量的可怕之处在于"短时间内冲垮系统,而系统平时有余量"。削峰填谷就是把尖峰摊平:消息队列是最经典的削峰工具——请求进来先入队,后端按自己能处理的速率消费,流量从"脉冲"变成"平稳流"。秒杀场景尤其依赖这一招:10 万人同时点击,请求全部进队列,后端每秒放 1000 个通过,谁先进队列谁先得。

其他整形手段还有:前端按钮置灰防重复提交、网关层排队令牌(先拿令牌再放行)、库存预热提前放到 Redis 让绝大多数请求在缓存层就被挡掉。核心思想都是"不让突发流量同时砸到后端"。

缓存抗读与数据库扛写的分工

高并发系统里,读流量和写流量要分开治理。读流量尽量由缓存扛:详情页、商品信息、排行榜这些热点,99% 的读请求应该命中 Redis 或本地缓存,数据库只在未命中时被回源。写流量才是数据库真正的压力,能异步化的异步化、能合并写的合并写、能批量刷盘的批量刷盘。

一条经验法则:读多写少的系统,缓存设计的收益远大于数据库调优。把读请求挡在缓存层,数据库的连接数和 CPU 立刻宽裕下来,系统能扛的并发成倍提升。

限流、熔断与降级的组合拳

这三件事经常一起出现,但作用点不同。限流是入口挡流量:超过阈值的请求直接拒绝或排队,保护后端不被打垮。熔断是下游出问题时快速失败:某个下游持续超时,熔断器打开,后续请求不再调用它,直接走兜底,避免线程被慢慢拖死。降级是主动牺牲非核心功能:大促时关掉个性化推荐、关掉评论加载,把资源留给下单主链路。

手段作用点触发后的行为
限流入口/网关超阈值请求拒绝或排队
熔断调用下游处下游故障时快速失败走兜底
降级非核心功能关闭次要功能,保主链路

三者配合:入口限流挡住超限流量,熔断防止故障扩散,降级保证核心链路活着。缺少任何一环,一处故障都可能演变成全站雪崩。

连接池、线程池与参数调优

很多"系统很闲却响应慢"的事故,根源是资源池配置。数据库连接池太小,并发一上来请求就在排队等连接;线程池太大,上下文切换吃掉 CPU;超时时间设得太长,下游一抖动,所有线程都被挂住。调优的原则是:连接数按数据库能承受的上限反推、线程池按 CPU 密集还是 IO 密集分档、超时时间宁可短也要快速失败。

# 数据库连接池:不是越大越好
maximumPoolSize=20        # 按数据库 max_connections 反推
connectionTimeout=2000     # 拿不到连接 2 秒就失败,不无限等
# 线程池:IO 密集型可大一些,但要有界
corePoolSize=50
maxPoolSize=200
queueCapacity=1000        # 有界队列,拒绝策略兜底