首页 / 知识库 / python服务端进阶 / 服务端高并发优化

09 - 一个高并发接口的优化实录

前八章讲了一堆手段。这一章把它们串起来,用一个虚构但典型的场景——「电商首页商品列表接口」——演示优化是怎么一步步推进的

重点不是数字(数字是示意),而是推导的思路和顺序

一句话先记住:优化是「测量 → 找瓶颈 → 针对性下手 → 再测量」的循环,每次只解决当前最大的瓶颈。


9.0 场景设定

接口:GET /api/products   (首页商品列表,读多写少)
初始情况:
  · 单台 FastAPI,同步写法
  · 每次请求都查 PostgreSQL,一句复杂 SQL(多表 JOIN)
  · 压测结果:QPS ≈ 200,响应时间 ≈ 500ms
目标:扛住大促流量,QPS 2 万+

第 1 轮:优化慢查询(先修最痛的)

压测发现:500ms 里有 450ms 花在那句 JOIN 的 SQL 上。瓶颈在数据库查询本身。

动作

  • EXPLAIN ANALYZE 分析,发现漏了索引 → 加索引
  • 简化 JOIN、去掉不必要的字段

结果:SQL 从 450ms → 50ms,QPS ≈ 200 → 1500。

教训:先优化「单次请求本身有多慢」,别的手段都是后话。(索引优化见系列三)


第 2 轮:加缓存(拦住重复的读)

分析:商品列表内容变化不频繁,但每个请求都查库,纯属重复劳动。

动作

  • 上 Redis 缓存,商品列表缓存 60 秒(旁路缓存模式)
  • 处理缓存穿透/击穿/雪崩(缓存空值、加随机过期、热点互斥锁)

结果:绝大多数请求直接命中缓存(内存读 ≈ 2ms),只有极少数回源查库。QPS ≈ 1500 → 8000。

优化前:每个请求都查库
优化后:
  10000 请求 → 缓存命中 9500(2ms)
             → 回源查库 500(50ms)

教训:读多写少 + 能容忍短暂不一致,缓存是性价比之王。


第 3 轮:改异步 + 调连接池(榨干单机)

分析:同步写法下,请求等 IO 时 CPU 在发呆;连接池太小,高并发时请求排队等连接。

动作

  • 接口改成 async def,用异步数据库驱动
  • 连接池大小压测调优到「刚好够用」
  • 部署改成「多进程(用满核)+ 每进程异步」

结果:单机吞吐大幅提升,等待时间被利用起来。QPS ≈ 8000 → 15000。

教训:并发模型选对,单机就能翻几倍(第 08 章)。


第 4 轮:水平扩展 + 负载均衡(加机器)

分析:单机已榨干,要再上就得加机器。

动作

  • 应用无状态化(Session/缓存都放 Redis)
  • 跑多台 FastAPI 实例,前面 Nginx 负载均衡(轮询)
  • 数据库读压力大 → 加从库,读写分离

结果:QPS 随机器数量近似线性增长。3 台 → QPS ≈ 4 万+。

教训:无状态是水平扩展的前提(第 06 章)。


第 5 轮:加保护(防止被打崩)

分析:大促可能来超预期流量,得给系统兜底。

动作

  • 网关 + 应用限流(令牌桶,超出容量的请求直接拒绝)
  • 大促时降级:关掉「猜你喜欢」等非核心模块
  • 对下游依赖加熔断,防止某个服务挂了拖垮全局

结果:即使流量超预期,系统也「部分可用」而非全崩。

教训:扛不住时,丢卒保车(第 07 章)。


9.1 复盘:优化的推进顺序

① 优化单次请求本身   (索引、SQL)      ← 最先做,成本最低
② 加缓存             (拦住重复读)      ← 性价比之王
③ 榨干单机           (异步、连接池)    ← 免费提升吞吐
④ 水平扩展           (加机器、读写分离) ← 花钱换上限
⑤ 加保护             (限流降级熔断)    ← 兜底,防崩溃

注意这个顺序背后的逻辑:从「便宜且见效快」到「昂贵但上限高」,从「提升能力」到「兜底保护」。


9.2 关键心态

  • 不要跳步:没加索引就想着分库分表,是本末倒置
  • 每次只解决当前最大瓶颈:解决完再压测,瓶颈会转移到下一处
  • 数字要靠压测得出:本章的 QPS 全是示意,真实项目一切以压测为准

本章小结

轮次手段解决什么
1索引 / SQL 优化单次请求太慢
2缓存重复的读打到库
3异步 + 连接池单机没榨干
4水平扩展 + 读写分离单机到顶了
5限流降级熔断防止被打崩

下一章预告:全程都在说「压测发现……」,那压测到底怎么做?关键要监控哪些指标?


上一章 ← 08 - 并发模型与异步 IO | 下一章 → 10 - 压测与监控