QPS、并发、吞吐量——这三个词大概是分布式系统领域被提及频率最高的性能指标。也正因如此,被混用的频率同样高得离谱。
理清这三者并不需要啃论文。一个高速收费站的类比就够了。
三个概念,一个收费站
把分布式系统想象成一个高速收费站:
**并发(Concurrency)**是收费站同时开放的窗口数——此刻正有多少辆车停在窗口前缴费。它衡量的是系统的”并行处理容量”。一个 API 服务同时维持着 1000 个活跃连接做业务处理,当前并发就是 1000。
**平均响应时间(Response Time,RT)**是一辆车从停到窗口前到抬杆离开的耗时。单位毫秒,包含了网络传输、路由转发、业务逻辑、数据库查询等全部环节。
**QPS(Queries Per Second)**是整个收费站每秒钟能放行多少辆车。在 API 语境下,吞吐量(Throughput)通常直接等于 QPS(或 TPS)。底层网络层面有时用 Bytes/s 衡量,但评估业务接口时说的就是请求数。
| 指标 | 收费站类比 | 本质 |
|---|---|---|
| 并发 | 同时开放的窗口数 | 系统的并行处理容量 |
| RT | 单辆车缴费耗时 | 单次请求的端到端延迟 |
| QPS | 每秒通过车辆数 | 单位时间的处理能力 |
这三个量不是各自独立的。
Little’s Law:一根绳子拴住三个变量
利特尔法则(Little’s Law)来自排队论,公式简单到可以口算:
假设系统当前有 100 个并发请求,每个请求平均 200ms 处理完毕。那么 QPS = 100 / 0.2 = 500 次/秒。这就是系统的总吞吐量。
这个公式看着不起眼,但它是所有容量估算和限流策略的数学底线。三个变量,知道任意两个就能推第三个。任何一个变量的变化,都会强制连锁反应到另外两个。
在大型分布式系统中,这条法则的工程意义体现在三个关键环节。
容量估算:反向推资源
系统上线前,需要回答一个问题:要扛住目标 QPS,得部署多少资源?
假设核心服务预期高峰 QPS 为 10,000,压测显示单次请求平均 RT 为 50ms(0.05 秒)。根据公式:
这意味着网关和业务层至少需要维持 500 个工作线程或 500 个活跃的下游连接,请求才不会排队。这个数字直接决定了线程池参数和连接池上限。
限流:保住 RT,别让它跑偏
任何系统的物理资源(CPU、内存、文件描述符)都有硬天花板,换言之,最大并发数是一堵绕不开的墙。
突发流量来临时,QPS 飙升。如果并发数已经打到物理极限(比如 Tomcat 线程池满了),新请求只能进队列等着。一旦排队,RT 就不再是纯处理时间,而是处理时间 + 等待时间。 RT 被拉长后,为了维持当前 QPS,所需并发数进一步膨胀——恶性循环启动。
限流的本质不是为了挡流量,是为了死守 RT 不被拖垮。 假设系统最大并发能力 1000,QoS 目标要求 RT ≤ 200ms,那么安全吞吐量上限就是:
网关层把令牌桶或漏桶算法的速率上限卡死在 5000 QPS。超出的请求直接回 HTTP 429,宁可牺牲部分用户的成功率,也不能让整个服务代理层被拖下水。
熔断:下游变慢时的自保逻辑
微服务架构中,一个请求往往串联多个下游。当下游某个 API 响应开始抖动时,Little’s Law 会像放大镜一样暴露问题。
假设你的服务维持 1000 QPS 的入流量,下游 API 的 RT 从 100ms 恶化到 500ms:
- 恶化前:所需并发 = 1000 × 0.1 = 100
- 恶化后:所需并发 = 1000 × 0.5 = 500
一夜之间,你需要 5 倍的并发连接来挂起这些慢请求。如果连接池上限只配了 200,这 500 个慢请求会立刻占满所有资源,其他原本健康的接口也一起瘫痪。
这就是熔断(Circuit Breaking)存在的理由。当检测到下游 RT 超过阈值,直接掐断调用(Fail Fast),强行把 RT 压下来,释放被慢请求绑住的并发资源。熔断不是在惩罚下游——是在保护自己不被拖死。
几点心得
Little’s Law 本身不复杂。但把这根绳子绷紧了去审视每一次扩容决策、每一个限流阈值、每一处熔断配置,能避免很多靠直觉拍脑袋的坑。
容量估算不是”加机器”就完了——得先算清楚并发数和 RT 的乘积能不能撑住目标 QPS。限流不是随便设个数字——它背后是并发硬上限除以 RT 目标的精确计算。熔断阈值也一样,RT 劣化 5 倍,并发需求就膨胀 5 倍,连接池够不够大,心里得有数。
这些道理说出来平淡无奇。但在生产环境被突发流量打穿过的同学应该知道——平淡无奇的公式,往往是最贵的教训。