4. 延迟类SLI口径设计:请求延迟、服务端延迟、网络延迟、端到端延迟的测量口径
延迟是衡量系统响应速度的核心指标,也是SRE黄金信号之一。不同观测视角下的延迟含义差异巨大:客户端感知的“慢”与服务端统计的“快”可能同时成立。本章从四个关键口径出发,逐一拆解其测量边界、统计方法与常见陷阱。
4.1 延迟SLI的四类口径概览
| 口径类型 | 测量起点 | 测量终点 | 典型场景 |
|---|---|---|---|
| 请求延迟 | 客户端发出请求 | 客户端收到完整响应 | API网关、前端监控 |
| 服务端延迟 | 服务端接收请求 | 服务端发出响应 | 应用服务器、微服务 |
| 网络延迟 | 数据包离开源端 | 数据包到达目的端 | 负载均衡、跨AZ通信 |
| 端到端延迟 | 用户操作触发 | 用户看到最终结果 | 全链路追踪、用户体验 |
关键原则:延迟SLI必须明确“从哪到哪”的测量边界。同一个请求,不同口径的延迟值可能相差数倍,混淆口径会导致SLO目标错位。
4.2 请求延迟:客户端视角的“真实感受”
请求延迟(Request Latency)在客户端侧测量,包含完整的网络往返时间(RTT)、服务端处理时间、以及响应数据传输时间。这是用户直接感知的延迟。
- 测量点:浏览器/移动端SDK/API网关出口
- 统计口径:从TCP连接建立(或HTTP请求发出)到最后一个字节接收完毕
- 常见陷阱:客户端DNS解析时间、TLS握手时间是否计入?建议单独记录,避免与业务延迟混淆
- 推荐分位:p50(中位数)、p95(第95百分位)、p99(第99百分位)
# 请求延迟计算示例(PromQL风格)
# 客户端侧:请求开始到结束的时间差
request_latency_seconds = request_end_timestamp - request_start_timestamp
# 按分位聚合(假设已记录到histogram)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
4.3 服务端延迟:排除网络干扰的“纯处理时间”
服务端延迟(Server Latency)仅测量服务进程内部的处理耗时,排除网络传输、客户端排队等外部因素。它是容量规划和性能优化的核心依据。
- 测量点:服务框架拦截器/中间件(如Spring Filter、gRPC Interceptor)
- 统计口径:从请求到达服务进程(反序列化完成)到响应发出(序列化开始前)
- 常见陷阱:线程池排队等待时间是否计入?建议区分“队列等待”与“实际处理”,分别记录
- 推荐分位:p50、p99、p999(用于识别长尾)
实践建议:服务端延迟应同时记录“CPU耗时”和“墙钟耗时”。墙钟耗时包含I/O等待(如数据库查询、下游RPC),CPU耗时仅反映计算密集度。两者差值过大说明存在阻塞点。
4.4 网络延迟:基础设施的“传输代价”
网络延迟(Network Latency)衡量数据包在网络上传输的单向或往返耗时。它通常由网络设备、链路距离、拥塞程度决定,与应用代码无关。
| 子类型 | 测量方式 | 典型值参考 |
|---|---|---|
| 单向延迟(OWD) | 源端打时间戳,目的端比对NTP同步时钟 | 同AZ:<1ms;跨Region:10-100ms |
| 往返延迟(RTT) | Ping/TCP握手时间/HTTP首字节时间(TTFB) | 同机房:<0.5ms;公网:20-200ms |
| 应用层网络延迟 | TTFB - 服务端处理时间 | 通常占端到端延迟的30%-70% |
注意:不要将服务端延迟与网络延迟简单相加得到端到端延迟。客户端请求延迟 = 网络延迟(请求方向)+ 服务端延迟 + 网络延迟(响应方向)+ 数据传输时间。其中数据传输时间与响应体大小强相关。
4.5 端到端延迟:用户体验的“最后一公里”
端到端延迟(End-to-End Latency)从用户发起操作开始,到用户界面完成渲染或反馈结束。它包含客户端处理、网络传输、服务端处理、以及前端渲染的全部环节。
- 测量点:真实用户监控(RUM)、合成监控(Synthetic Check)
- 统计口径:用户点击 → 页面首屏渲染 / API响应展示
- 常见陷阱:前端JavaScript执行时间、图片懒加载、客户端缓存命中是否计入?建议按“关键用户操作”定义测量边界
- 推荐分位:p75(用户体验基线)、p95(容忍上限)、p99(不可用阈值)
# 端到端延迟分解(示例:Web页面加载)
e2e_latency = dns_lookup + tcp_connect + tls_handshake +
request_network + server_processing +
response_network + dom_parsing + resource_loading +
javascript_execution + rendering
4.6 四类延迟口径的关联与对比
以下SVG图展示了一个典型HTTP请求从客户端到服务端再到客户端的完整路径,并标注了四类延迟的测量边界。
4.7 口径选择决策矩阵
在实际SLI设计中,应根据SLO目标和观测角色选择合适口径。以下矩阵帮助快速决策:
| SLO目标 | 推荐口径 | 理由 |
|---|---|---|
| 用户体验承诺 | 端到端延迟 | 直接反映用户感受,包含所有环节 |
| API性能承诺 | 请求延迟 | 客户端视角,包含网络但排除前端渲染 |
| 服务容量规划 | 服务端延迟 | 排除网络波动,聚焦服务处理能力 |
| 基础设施SLA | 网络延迟 | 衡量网络质量,与应用代码解耦 |
| 故障定位 | 四类口径同时采集 | 通过差值定位瓶颈环节 |
最佳实践:建议同时采集服务端延迟和请求延迟。两者差值即为“网络+传输”开销。当请求延迟恶化而服务端延迟正常时,问题大概率在网络或客户端侧;反之则问题在服务端内部。
4.8 延迟口径设计的常见陷阱与避坑
- 陷阱1:时钟不同步——分布式系统中各节点时钟偏差会导致延迟计算错误。解决方案:使用NTP对齐,或采用客户端单点打时间戳(如HTTP请求头记录时间)。
- 陷阱2:排队时间归属不清——请求在负载均衡器、线程池、消息队列中的等待时间应单独记录,避免与服务端处理时间混淆。
- 陷阱3:长尾请求被平均掩盖——仅看平均延迟会掩盖p99甚至p999的异常。必须使用分位统计,并设置独立的SLO阈值。
- 陷阱4:重试请求污染统计——客户端自动重试会导致延迟分布失真。建议在SLI中标记重试请求,或仅统计首次请求。
- 陷阱5:缓存命中与未命中混在一起——缓存命中请求的延迟远低于未命中请求。建议分别统计,或按缓存状态分层。
以下SVG图展示了一个完整的延迟分解结构,帮助理解各环节的归属关系。
总结:延迟SLI口径设计的核心是“明确边界、分解环节、分位统计”。在Metric Design实践中,建议为每个口径创建独立的metric,并在metric label中标注口径类型(如
latency_type="server"、latency_type="e2e"),以便在仪表盘和告警中灵活切换视角。