延迟基础:理解延迟、吞吐量与响应时间的关系

做性能优化这些年,我越来越觉得一个道理特别朴实——你连延迟是什么都说不清楚,就别提什么调优了。记得我刚带团队那会儿,有个同事跑过来说“系统延迟太高”,我问他具体是多高、哪个环节高、怎么测的,他支支吾吾答不上来。这种事,其实不少见。

说白了,延迟、吞吐量、响应时间,这三兄弟经常被人搞混。咱们先把这个捋清楚。

三大核心概念,一次讲透

我习惯用一个例子帮新人理解。你想想看,你去食堂打饭:

  • 响应时间 —— 从你站在窗口前,到端着饭离开,总共花了多少秒
  • 延迟 —— 你喊了一声“师傅,来份红烧肉”,师傅听到后到开始盛菜,中间那一小段等待
  • 吞吐量 —— 食堂师傅一分钟能打出多少份饭

这个类比其实挺准的。响应时间 = 延迟 + 处理时间。延迟更像是“空等”的那部分,处理时间是真正干活的时间。吞吐量则看系统并行能力。

记住这个公式:响应时间 = 延迟 + 服务时间

延迟是“等”,服务时间是“做”。你做优化,首先要分清楚你是在减少“等”还是减少“做”。

常见的延迟指标,你用过几个?

我在项目中遇到过不少团队,一上来就说“平均延迟20ms”,然后就觉得没问题了。嗯,这里要注意——平均延迟这东西,骗人的时候比诚实的时候多。

为什么?举个例子,100个请求里,99个只要1ms,但有1个卡了10秒。平均下来大概100ms出头,看着还行。可那1个用户呢?他已经骂娘了。

真正靠谱的指标是这样的:

指标 含义 我一般什么时候用
P50(中位数延迟) 一半请求比这个值快,一半比这个值慢 日常监控,看系统“通常表现”
P90 90%的请求都在这个值以内 评估大多数用户的体验
P99 99%的请求都在这个值以内 SLA保障,看尾部延迟
P999 99.9%的请求都在这个值以内 金融、交易类核心链路
平均延迟 所有请求延迟的算术平均 我很少单独用,容易掩盖问题

我个人的习惯是:日常看P50+P99两个就够了。P50告诉你“现在系统慢不慢”,P99告诉你“有没有用户正在遭罪”。

度量延迟,别被工具坑了

指标再漂亮,测不准全白搭。我曾经踩过一个坑:某次排查线上问题,监控面板显示P99延迟只有50ms,但客户投诉说页面打不开。后来一查,原来是监控采样周期设成了1分钟,那1秒的尖刺被平均掉了。

到现在,我总结出一套靠谱的度量方法:

  1. 用HDR Histogram记录完整分布 —— 不丢失任何百分位信息
  2. 打点位置要对 —— 入口到出口全链路埋点,分段记录
  3. 采样窗口别太大 —— 我习惯10秒一个窗口,最长不超过30秒
  4. 区分网络延迟和应用延迟 —— 这两者优化手段完全不同

我曾经见过一个团队用tcpdump抓包算延迟,结果发现算出来的数据比实际慢了一个数量级——他们忘了把网卡中断合并的时间算进去。工具本身也有开销,这一点一定要心里有数。

延迟、吞吐量,相爱相杀

这俩的关系说白了就是跷跷板。你拼命压吞吐量,延迟一定往上窜。你追求极致低延迟,吞吐量肯定上不去。

为什么?系统资源就那么多。当你把请求队列搞得很长,吞吐量确实上去了——但每个请求排队等的时间也长了。反过来,你让队列变短,每个请求是快了不少,可系统利用率下降,单位时间处理的请求数就少了。

我在优化一个消息中间件的时候,就遇到过这个问题。业务方要求每秒10万条吞吐,同时P99延迟低于5ms。这俩目标,说真的,天然冲突。最后我们是通过分区+绑核+忙等轮询的方式,才勉强同时满足。

核心思想:在资源瓶颈允许的范围内,找到延迟和吞吐量的最佳平衡点

这个点,不是固定的。不同业务、不同时段、不同硬件,都得重新调。

一张图看懂关系

下面这张图是我自己画的,把延迟、响应时间、吞吐量之间的逻辑关系串了一遍。说白了,延迟藏在响应时间里,而吞吐量又受限于响应时间。你调延迟,最终会影响吞吐量,反过来也一样。

延迟、响应时间与吞吐量关系图 延迟、响应时间与吞吐量关系 响应时间 从请求发出到收到完整响应 延迟 服务时间 响应时间 = 延迟 + 服务时间 吞吐量 单位时间完成的请求数 并发数 服务速率 吞吐量 = 并发数 / 响应时间 Little定律 L = λ × W(系统内请求数 = 到达率 × 平均响应时间) 互相影响 关键理解 1. 响应时间包含延迟和服务时间两部分,优化前先区分是哪个 2. 吞吐量受响应时间制约,延迟越低,理论上可达到的吞叶量上限越高 3. 但实际中,过低的延迟目标(如忙等轮询)可能降低CPU利用率,反而限制吞吐量 4. Little定律告诉我们:三者之间存在数学关系,调参时要全局考虑

一个实战视角:怎么“看”延迟

说一千道一万,落到具体操作上,你总得知道从哪下手。我一般按照下面这个流程来:

  1. 选定百分位 —— 先看P99,再看P50,两者差距越大,说明抖动越严重
  2. 分段定位 —— 用全链路追踪把一次请求拆成:网络传输→排队→CPU执行→IO等待→网络返回,逐段看
  3. 确定瓶颈 —— 哪一段占总延迟的比例最高,就优先优化哪一段
  4. 设定目标 —— 每段延迟优化10%~30%即可,不要追求一刀切到极限

我常用的一个调试技巧:先用perf record抓一把采样,再看哪个函数占的CPU时间长。如果发现大量时间花在锁等待或上下文切换上,那延迟大概率是因为争抢资源,而不是代码本身慢。

最后说句实在的

延迟优化这事儿,很多人一上来就想着改代码、调参数。但我建议你先花点时间,把延迟的基础概念吃透,把度量体系搭对。方向错了,跑得再快也没用。

嗯,这一章就到这里。你只要能分清P50和P99有什么区别、响应时间里的“等”和“做”怎么回事,后面调优的时候就不会抓瞎了。