生产工程 · 2024年2月14日 · 3 分钟

高并发系统的七种武器

缓存、限流、降级、异步、读写分离、池化、动静分离——七种高并发应对手段的组合使用。

高并发不是某种技术,而是一套组合拳。这篇文章总结七种常用的应对手段,大部分来自工作实践和阅读经典案例的总结。

1. 缓存:让请求止步于 DB 之前

    请求 → CDN → 本地缓存 → Redis → 数据库
           ↓        ↓         ↓
      命中率最高   速度最快   撑不住就走

缓存层级不是越多越好,而是每层有明确职责。CDN 负责静态资源,本地缓存(Caffeine)处理极热数据,Redis 承担大部分动态缓存,数据库是最后的底线。

一个容易被忽略的点:缓存预热。大促前如果缓存是空的,所有请求直接穿透到数据库,叫"缓存击穿大场面版"。所以一般会做离线预热脚本,提前把热点灌进缓存。

2. 限流:对系统的自我保护

没有限流的系统就像没有保险丝的电箱——流量超过了承受能力,直接烧毁。

常用的令牌桶算法不复杂:系统以固定速率往桶里放令牌,请求来了先拿令牌,拿不到就拒绝。Guava RateLimiter 开箱即用。但更推荐在网关层就做限流(Nginx + Sentinel),因为流量到应用层时 CPU 已经被无效请求消耗了。

3. 降级:优雅的妥协

假设你的首页要调三个服务:推荐服务、广告服务、热门列表。推荐服务挂了或超时,你是不是应该让整个首页报错?

降级的意思是:部分功能失败,整体服务仍然可用。 推荐挂了就展示兜底的热门列表,广告没返回就隐藏广告位,核心路径(商品浏览、下单)绝对不降级。

面试题里常问的"熔断 vs 降级",区别很简单——熔断是自动的(失败率超过阈值自动熔断),降级是主动的(预设一段兜底逻辑,出问题就切过去)。

4. 异步:削峰填谷

秒杀场景最典型的做法不是同步排队,而是先接收请求→丢消息队列→慢慢消费。用户看到的是"排队中",后台按能力消化。

异步的代价是用户体验的变化——从"立即知道结果"变成"等通知"。对时效性要求高的场景(比如支付),异步只适合做辅助,不能替代同步链路。

5. 读写分离 + 分库分表

单库扛不住的时候两条路:

  • 垂直拆分:不同业务用不同库(用户库、订单库)
  • 水平拆分:同一业务按 sharding key 分到多个库或多个表

经典的分片策略是按 user_id 取模,同一个用户的数据落在同一个分片上。但跨分片的 join 和统计就麻烦了——这是为什么要提前规划好分片策略,别等单库撑爆了再临时上 ShardingSphere。

6. 池化:连接、线程、对象的复用

Spring 的数据库连接池(HikariCP)、HTTP 连接池、线程池,本质都是减少创建/销毁开销。要关注的是池子大小和超时——池子太小吞吐量上不去,池子太大资源耗尽。监控连接池的使用率比关注具体数值更重要。

7. 动静分离

前端的优化容易被后端同学习惯性忽略。但事实上静态资源(JS、CSS、图片)通常占据总请求量的 60% 以上。把它们放到 CDN 或对象存储,HTML 走动态渲染、静态资源走边缘节点,请求量立竿见影地下降。

组合使用

这七种手段很少单独使用——真正的架构里它们是重叠的:

CDN(动静态分离)
  └→ Nginx(限流)
      └→ 网关(鉴权、限流)
          └→ 应用层
              ├── 本地缓存 → Redis缓存 → DB(读写分离)
              ├── 消息队列(异步削峰)
              └── 降级兜底(异常保护)

高并发系统的设计原则可以归结为一句话:尽量让请求在离用户近的地方被处理,尽量让数据库离负载远一点。

继续阅读

评论