概念定义
延迟分布是长尾的:一小部分请求耗时是中位数的许多倍。这一小撮不是噪声——它是稳定的群体,在规模上就是大量的真实用户。
工作机制
扇出放大尾部:发起 100 个并行调用的页面在 100 个的最大值处完成,百分之一的慢调用率意味着多数页面都要等慢调用。排队论解释了负载下方差本身如何膨胀尾部——利用率逼近饱和会成倍放大等待时间方差。
使用场景
一切交互服务。先找方差源:GC 停顿、锁队列、冷缓存、重试风暴、后台任务。再上尾容忍技术——对冲请求、请求级超时、优雅降级、负载丢弃——而不是徒劳地让每个组件均匀变快。
常见误区
“均值与中位数抓不住体验”的另一面是:p50=50ms 配 p99=8s 的服务,用户经常在干等而聚合指标毫无表示。超时设在观测尾延迟之上,等于让最慢调用拖住整个请求。分位数运算要小心:跨时间窗平均分位数会失真,应从直方图计算;小样本 p99 是噪声;协调性遗漏(测量间隔等慢响应)会隐藏尾巴。
代码示例
from dataclasses import dataclass, field
import random
@dataclass
class Span:
name: str
duration_ms: float
error: bool = False
@dataclass
class Policy:
slow_ms: float = 500.0
keep_errors: bool = True,
fallback_rate: float = 0.01
def decide(spans: list['Span'], policy: Policy, rng: random.Random | None = None) -> tuple[bool, str]:
rng = rng or random.Random()
if not spans:
return False, 'empty'
if policy.keep_errors and any(s.error for s in spans):
return True, 'error'
slowest = max(s.duration_ms for s in spans)
if slowest >= policy.slow_ms:
return True, 'slow'
if rng.random() < policy.fallback_rate:
return True, 'sampled'
return False, 'dropped'