Dapr v1.17 服务调用性能深度报告:HTTP 与 gRPC 在 1000 QPS 下的延迟、开销与源码级解读
【免费下载链接】daprDapr is a portable runtime for building distributed applications across cloud and edge, combining event-driven architecture with workflow orchestration.项目地址: https://gitcode.com/GitHub_Trending/da/dapr
导读
本文基于 Dapr 仓库中的 v1.17.0 服务调用(Service Invocation)性能测试报告,系统拆解 Dapr 在 1 KB 载荷、16 连接、1000 QPS 持续压测下的 HTTP 与 gRPC 双协议延迟表现、Sidecar 附加开销与资源占用,并深入对应压测源码,说明测试方法、参数含义、断言阈值与结果结构。读完本文,你将掌握如何阅读 Dapr 性能报告中的百分位指标,以及如何复现、定制并判定服务调用性能压测是否达标。
报告概览:v1.17 服务调用的核心结论
服务调用(Service Invocation)是 Dapr 提供的核心服务间通信原语:应用通过 Dapr Sidecar 以 HTTP 或 gRPC 方式调用另一个应用,Sidecar 负责服务发现、路由、mTLS 加密与可观测性注入。v1.17 的性能报告(报告总览)给出了如下结论:
- HTTP 路径:p50 中位延迟1.59 ms、p902.38 ms、p993.89 ms,在 60,000 个请求中实现100% 成功率、0 错误、0 Pod 重启;
- gRPC 路径:p502.25 ms、p902.92 ms、p994.59 ms,同样 60,000 请求100% 成功、0 重启;
- 两种传输协议均精准命中 QPS 目标:实际 QPS 为 999.94~999.95,与请求的 1000 基本一致;
- 资源开销轻量:该负载下 HTTP Sidecar 消耗低于 250 mCPU 与约 51 MB 内存(具体为 202 mCPU / 51 MB),gRPC 为 248 mCPU / 50 MB。
如何阅读这些数字
报告中的延迟百分位描述的是单个请求耗时的分布情况:
- p50(中位数):一半请求比它快、一半比它慢,代表用户“典型体验”;
- p90:90% 的请求比它更快,即只有 1/10 的请求比该值慢;
- p99:99% 的请求更快,只有 1/100 的请求超过该值,反映尾部延迟(tail latency)质量。
“16 connections”表示 16 个并行调用者同时以总计 1000 QPS 的速率压测 Dapr Sidecar。“Dapr overhead(Dapr 附加开销)”的测量方式是:在相同条件下不带 Dapr 直接调用目标应用跑一遍基线(baseline)测试,再用带 Dapr 的结果减去基线结果,差值即为 Dapr Sidecar 代理层本身的纯开销。
HTTP 服务调用性能详解
详细的 HTTP 数据见 HTTP 分报告:
| 指标 | p50 | p90 | p99 | p99.9 |
|---|---|---|---|---|
| 端到端延迟(经 Dapr) | 1.59 ms | 2.38 ms | 3.89 ms | 6.61 ms |
| Dapr 附加开销(vs 直连) | +1.06 ms | +1.48 ms | +2.90 ms | — |
- 60,000 请求,100% 成功率(全部返回 HTTP 200),0 Pod 重启;
- 持续 1000 QPS 下 Sidecar 占用202 mCPU、51 MB 内存。
这里 1.59 ms 的中位延迟是完整的 HTTP 请求周期:客户端 → Dapr Sidecar → 目标应用 → 应用响应 → Sidecar 回传客户端。Sidecar 在这一过程中贡献约 1.06 ms,主要来自 HTTP 头部解析、路由与转发。即便最差的 1/100 请求(p99)也稳定在 4 ms 以内,而极端 p99.9(千分之一请求)仍低于 7 ms,p90 到 p99 的差距仅约 1.5 ms,说明尾部分布非常收敛。
gRPC 服务调用性能详解
gRPC 详细数据见 gRPC 分报告:
| 指标 | p50 | p90 | p99 | p99.9 |
|---|---|---|---|---|
| 端到端延迟(经 Dapr) | 2.25 ms | 2.92 ms | 4.59 ms | 8.00 ms |
| Dapr 附加开销(vs 直连) | +1.68 ms | +1.97 ms | +2.83 ms | — |
- 60,000 请求,100% 成功率(gRPC 状态全部为 SERVING),0 Pod 重启;
- Sidecar 占用248 mCPU、50 MB 内存。
gRPC 路径的完整往返为:gRPC 客户端 → Dapr Sidecar → Sidecar 通过自己的 gRPC 连接路由到目标应用 → 应用处理并返回 → Sidecar 回传结果。gRPC 的中位附加开销(1.68 ms)高于 HTTP(1.06 ms),原因在于 Dapr 需要在代理跳点的两侧都参与 HTTP/2 帧封装(framing),同时叠加 mTLS 与路由成本。尽管如此,p90 到 p99 仅从 2.92 ms 扩展到 4.59 ms,最慢的 1/100 请求也能在 5 ms 内完成,尾部延迟控制良好。
源码级解读:压测是如何执行的
报告背后是两个带//go:build perf构建标签的性能测试文件,分别位于 HTTP 压测源码 与 gRPC 压测源码,只有通过-tags perf编译才会生效。
1. 压测参数与测试拓扑
两个测试通过perf.Params(...)构建完全一致的负载参数:
p := perf.Params( perf.WithQPS(1000), // 目标吞吐:1000 QPS perf.WithConnections(16), // 16 个并行客户端连接 perf.WithDuration("1m"), // 持续 1 分钟 perf.WithPayloadSize(1024),// 随机载荷 1 KB )测试集群中部署两个应用(kube.AppDescription):
- testapp:被调用方,带 Dapr Sidecar,
DaprCPULimit: "4.0"、DaprCPURequest: "0.1"、内存512Mi/250Mi(HTTP 版监听 3000 端口,gRPC 版声明AppProtocol: "grpc"); - tester:压测发起方,与 testapp 通过
PodAffinityLabels亲和调度,保证两者同节点、网络距离最短,尽可能消除跨节点网络抖动对延迟数据的影响。
测试开始前会对两个应用各做60 次健康检查(numHealthChecks = 60):HTTP 版使用utils.HTTPGetNTimes,gRPC 版使用utils.GrpcAccessNTimes(testAppURL, utils.GrpcServiceInvoke, numHealthChecks)验证 gRPC 服务可用。
2. 三轮测试:基线、预热、正式
每个测试都遵循“基线 → 预热 → 正式”三阶段设计:
- 基线测试(Baseline):不走 Dapr,直接压测目标应用,得到“无 Dapr”的延迟基准。
- HTTP:
TargetEndpoint = "http://testapp:3000/test" - gRPC:
p.Grpc = true、p.Dapr = "capability=invoke,target=appcallback,method=load"、TargetEndpoint = "http://testapp:3000"
- HTTP:
- 预热(Warmup):以较低负载(100 QPS、10 秒)先打一遍 Dapr 路径,让连接池、缓存与 JIT/GC 状态就绪,避免冷启动污染正式数据。
- HTTP 预热目标:
http://127.0.0.1:3500/v1.0/invoke/testapp/method/test - gRPC 预热目标:
http://localhost:50001,Dapr 参数为capability=invoke,target=dapr,method=load,appid=testapp
- HTTP 预热目标:
- 正式测试(Dapr):以完整负载(1000 QPS、1 分钟)压测 Dapr 路径。
正式测试的请求路径印证了 Dapr 服务调用 API 的形态:
- HTTP:
http://127.0.0.1:3500/v1.0/invoke/testapp/method/test—— 即v1.0/invoke/{appId}/method/{method}约定,与 directmessaging 测试 中使用的v1.0/invoke/fakeAppID/method/fakeMethod路由格式一致; - gRPC:
http://localhost:50001(Dapr gRPC 端口),Dapr = "capability=invoke,target=dapr,method=load,appid=testapp"表示经 Sidecar 调用 appid 为 testapp 的应用。
3. 结果计算与断言阈值
测试结束后通过daprResult.DurationHistogram.Percentiles[k].Value与基线结果逐百分位做差,得到 Dapr 在各百分位(50th/75th/90th/99th)的附加延迟(单位毫秒,(daprValue - baselineValue) * 1000)。
测试最终通过 testify 的require做硬性判定:
require.Equal(t, 0, daprResult.RetCodes.Num400) // 不允许 400 错误 require.Equal(t, 0, daprResult.RetCodes.Num500) // 不允许 500 错误 require.Equal(t, 0, restarts) // 不允许 Pod 重启 require.True(t, daprResult.ActualQPS > float64(p.QPS)*0.99) // 实际 QPS 至少达到目标的 99% require.Greater(t, tp90Latency, 0.0) // p90 附加延迟必须为正(有效测量) require.LessOrEqual(t, tp90Latency, 2.0) // HTTP:p90 附加延迟 ≤ 2.0 ms // gRPC 版最后一行阈值为:require.LessOrEqual(t, tp90Latency, 2.5)这就是报告声称“零失败”的来源:压测期间 Sidecar 返回码中 400/500 数量均为 0、GetTotalRestarts为 0,且 p90 附加延迟被硬性约束在毫秒级上限内(HTTP ≤ 2.0 ms、gRPC ≤ 2.5 ms)。此外,压测数据还会通过utils.PushPrometheusMetrics推送到 Prometheus,供趋势监控使用。
压测参数与结果数据结构
压测参数定义在 test_params.go 中,除代码内显式设置外,还支持通过环境变量覆盖(环境变量优先级最高):
| 环境变量 | 对应参数 | 说明 |
|---|---|---|
DAPR_PERF_QPS | QPS | 目标吞吐(默认 1) |
DAPR_PERF_CONNECTIONS | ClientConnections | 客户端连接数(默认 1) |
DAPR_TEST_DURATION | TestDuration | 测试时长,支持1m、10s等 Go 时间记法(默认1m) |
DAPR_PAYLOAD | Payload | 固定载荷内容(默认空) |
DAPR_PAYLOAD_SIZE | PayloadSizeKB | 随机载荷大小 KB(默认 0) |
因此,在不改代码的情况下即可通过环境变量把上述测试改成其他负载场景(例如DAPR_PERF_QPS=5000 DAPR_TEST_DURATION=5m)来观察不同压力下的延迟曲线。
压测结果以 TestResult 结构返回,报告图表的数据来源包括:
- DurationHistogram:延迟直方图,含
Count / Min / Max / Sum / Avg / StdDev / Data / Percentiles,其中Percentiles数组直接驱动 latency 分布图; - RetCodes:
200 / 204 / 400 / 500各类状态码计数,是“100% 成功率”断言的依据; - Sizes 与 HeaderSizes:载荷体与请求头大小的分布统计;
- ActualQPS / SocketCount / NumThreads:实际吞吐、socket 数与并发线程数。
资源开销对比与部署启示
将两份分报告的资源数据放在一起对比:
| 传输协议 | Sidecar CPU | Sidecar 内存 | 中位延迟 | 中位附加开销 |
|---|---|---|---|---|
| HTTP | 202 mCPU | 51 MB | 1.59 ms | 1.06 ms |
| gRPC | 248 mCPU | 50 MB | 2.25 ms | 1.68 ms |
从源码结构看,这套测试覆盖了 Dapr 服务调用中最典型的两种入口(HTTP API 与 gRPC API),其结论可作为容量规划的参考:以 1 KB 小载荷、16 连接、1000 QPS 的典型服务间调用场景衡量,Dapr Sidecar 的中位附加延迟在 1~2 ms 量级,内存占用稳定在 50 MB 左右。需要说明的是,该报告基于 v1.17.0 的特定压测环境(1 KB 载荷、同节点亲和调度),不同载荷大小、连接数、跨节点部署或开启加密/追踪后,绝对数值会相应变化,但其测量方法(基线对比法)与数据解读口径具有跨版本的可比性。
如何复现与扩展阅读
- 阅读运行性能测试的完整指引:running-perf-tests.md;
- 复现 HTTP 压测:
go test -tags perf ./tests/perf/service_invocation_http/...(需先按仓库测试文档搭建 Kubernetes 测试集群); - 复现 gRPC 压测:
go test -tags perf ./tests/perf/service_invocation_grpc/...; - 对比其他版本:v1.17.0 报告位于 report/charts/v1.17.0/service_invocation,可按版本目录横向比较延迟与资源趋势;
- 深入服务调用实现:可结合 direct_messaging.go 与 directmessaging 测试 理解 Sidecar 内部的路由与转发路径。
总结
v1.17 的服务调用性能报告用一套严格、可复现的基线对比方法给出了明确结论:在 1000 QPS 持续负载下,HTTP 服务调用中位延迟 1.59 ms、p99 3.89 ms,gRPC 中位 2.25 ms、p99 4.59 ms,两者均 100% 成功且无 Pod 重启,Sidecar 内存占用稳定在约 50 MB。理解“p50/p90/p99”的口径、Dapr 附加开销的减法式测量,以及压测源码中的三轮测试与毫秒级断言阈值,是正确解读这份报告、乃至评估任何 Dapr 版本服务调用性能的关键。
【免费下载链接】daprDapr is a portable runtime for building distributed applications across cloud and edge, combining event-driven architecture with workflow orchestration.项目地址: https://gitcode.com/GitHub_Trending/da/dapr
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考