Dapr v1.17.0 状态管理性能基准实测:gRPC 与 HTTP 状态读取的亚毫秒延迟解析
【免费下载链接】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 仓库 tests/perf/report/charts/v1.17.0/state/README.md 及其下属 grpc、http 两个分报告,系统解读 Dapr v1.17.0 在 1,000 QPS 持续压力下状态管理(State Management)API 的实测延迟、Sidecar 附加开销与资源占用,并结合仓库内性能测试源码,说明这份报告的数据是如何测出来、如何被断言的,帮助读者正确理解百分位延迟指标,并据此评估 Dapr 状态读取在生产环境中的真实成本。
报告概览:状态管理 API 的开销有多低?
v1.17.0 的性能报告给出了一个核心结论:状态管理在两种传输协议(gRPC 与 HTTP)下均实现了亚毫秒级中位延迟,持续负载 1,000 QPS 下依然如此,且是 Dapr 各 API 面中代理开销最低的之一。60,000 个请求全部成功(成功率 100%),Pod 零重启,说明该结论来自一次干净、无干扰的基准测试。
报告中的关键数字汇总如下:
| 指标 | gRPC | HTTP |
|---|---|---|
| 中位数 p50 | 0.57 ms | 0.73 ms |
| p90 | 0.93 ms | 1.60 ms |
| p99 | 1.65 ms | 1.97 ms |
| p99.9 | 2.66 ms | 2.84 ms |
| p50 处 Dapr 附加开销 | +0.12 ms | +0.28 ms |
| 请求数 / 成功率 | 60,000 / 100% | 60,000 / 100% |
| Sidecar 资源占用 | 142 mCPU、53 MB | 57 mCPU、48 MB |
| 实际 QPS | ≈999.97 | ≈999.98 |
两种传输方式的 QPS 达成率都极为精确(实际 999.97~999.98 vs 目标 1,000),说明压测负载全程被稳定打满,延迟数据可信度高。
如何读懂这些数字:百分位与"Dapr 开销"的定义
报告在"Highlights"部分专门说明了数据的含义,这是正确使用这份报告的前提:
- 延迟百分位(p50/p90/p99/p99.9):反映 60,000 个请求各自耗时的分布。p50 是大多数用户实际体验到的延迟;p99.9 则是极端尾部——1000 个请求中最慢的那 1 个,用来衡量系统在最坏情况下的稳定性。
- Dapr overhead(附加开销):通过"对比实验"测得——将经 Dapr Sidecar 代理后的结果,与绕过 Sidecar 直接访问状态存储的结果相减。这个差值就是 Dapr 引入的净成本,而不是请求的绝对耗时。
理解了这个口径就能明白:0.57 ms 的中位数不是"状态存储本身有多快",而是"在 1,000 QPS 下,Dapr 代理 + 状态存储整体路径有多快";而 +0.12 ms 才是 Dapr 真正为状态读取付出的代理代价。
测试是如何进行的:源码级拆解
这份报告对应的测试用例位于仓库 tests/perf/state_get_http/state_get_http_test.go 与 tests/perf/state_get_grpc/state_get_grpc_test.go,均带//go:build perf构建标签,只在性能测试模式下编译。
压测参数:1,000 QPS、16 连接、持续 1 分钟
两个用例使用相同的参数构造器(定义于 tests/perf/test_params.go):
p := perf.Params( perf.WithQPS(1000), perf.WithConnections(16), perf.WithDuration("1m"), perf.WithPayloadSize(0), )- QPS = 1,000:持续恒定负载,60 秒共发出 60,000 个请求,与报告中的请求数吻合;
- Connections = 16:16 条并发连接分摊负载;
- Duration = 1m:压测时长 1 分钟;
- PayloadSize = 0:无请求体负载,纯测"状态读取"这一 API 本身的处理路径。
参数还支持环境变量覆盖(DAPR_PERF_QPS、DAPR_PERF_CONNECTIONS、DAPR_TEST_DURATION、DAPR_PAYLOAD_SIZE等,见 tests/perf/test_params.go),便于复现时调整强度。
被测端点:inmemory 状态存储
- HTTP 用例压测 Dapr 状态管理 HTTP API 的读取端点:
http://127.0.0.1:3500/v1.0/state/inmemorystate/abc123(见 state_get_http_test.go),即通过 Sidecar 的 3500 端口读取inmemorystate存储中键abc123对应的值; - gRPC 用例通过 Dapr 参数串指定目标:
capability=state,target=dapr,method=get,store=inmemorystate,key=abc123(见 state_get_grpc_test.go),走 gRPC 的 GetState 调用路径。
两者都使用内存态状态存储(inmemorystate),排除了外部存储(如 Redis、SQL 数据库)网络往返与磁盘 IO 的影响,从而把测量焦点收敛到Dapr Sidecar 自身的处理开销上。
基线对照:绕过 Sidecar 直连存储
每个用例都先跑一轮"基线测试"(baseline):p.Dapr = "capability=state,target=noop",目标指向http://localhost:50001(见 state_get_http_test.go),相当于直连状态存储、不经 Sidecar。随后再跑一轮经 Dapr 代理的完整测试,用两者的分位延迟之差计算 Dapr 附加开销。
压测本身由部署在集群中的perf-tester应用执行,该应用暴露/test端点,接收测试参数后调用fortio完成负载注入(详见 tests/apps/perf/tester/app.go 与 tests/apps/perf/tester/fortio.go 中的buildFortioArgs)。
通过断言强制保证数据质量
测试末尾的断言(assert)实际上充当了报告数据的"质检关卡",任何一项不满足测试即失败:
- 0 个 HTTP 400 / 500 错误码(
require.Equal(t, 0, daprResult.RetCodes.Num400)); - 0 次 Pod 重启(
require.Equal(t, 0, restarts)); - 实际 QPS 必须超过目标值的 99%(
require.True(t, daprResult.ActualQPS > float64(p.QPS)*0.99)); - p90 附加延迟必须落在 (0, 2.0] ms 区间内(
require.Greater/require.LessOrEqual,见 state_get_http_test.go)。
这也解释了报告强调"100% 成功率、0 Pod 重启"的原因:这些不是宣传话术,而是测试用例本身硬性断言通过的验收条件。
gRPC 状态读取:+0.12 ms 的最低代理开销
gRPC 路径的数据(16 连接、1,000 QPS 目标):
- 延迟分布:p50 = 0.57 ms,p90 = 0.93 ms,p99 = 1.65 ms,p99.9 = 2.66 ms;
- Dapr 附加开销:p50 处仅 +0.12 ms,p90 处 +0.04 ms,p99 处 +0.66 ms——这是 Dapr 所有已测 API 面中最低的代理开销;
- 稳定性:60,000 请求 100% 成功(gRPC 全部返回 SERVING 状态),0 次 Pod 重启;
- 资源占用:持续 1,000 QPS 下 Sidecar 仅消耗 142 mCPU 与 53 MB 内存。
也就是说,即使是最差的千分之一请求(p99.9),端到端延迟也控制在 3 ms 以内。考虑到 gRPC 采用二进制帧协议、无需解析文本头,这一结果符合 gRPC 在低开销上的协议优势。该用例的完整图表(延迟分解、直方图、QPS、CPU/内存、尾部延迟等 9 张)见 grpc 分报告。
HTTP 状态读取:中位数 0.73 ms,Sidecar 资源最省
HTTP 路径的数据(16 连接、1,000 QPS 目标):
- 延迟分布:p50 = 0.73 ms,p90 = 1.60 ms,p99 = 1.97 ms,p99.9 = 2.84 ms;
- Dapr 附加开销:p50 处 +0.28 ms,p90 处 +0.71 ms,p99 处 +0.98 ms;
- 稳定性:60,000 请求 100% 成功(全部返回 HTTP 204),0 次 Pod 重启;
- 资源占用:持续 1,000 QPS 下 Sidecar 仅消耗 57 mCPU 与 48 MB 内存——这是所有已测传输方式中资源消耗最低的。
中位数同样落在 1 ms 以内。HTTP 路径的更完整图表集(连接统计、数据量、头部大小、负载大小、吞吐量等 14 张)见 http 分报告。
对比分析:为什么 HTTP 比 gRPC 多花约 0.16 ms?
报告对两协议差异给出了明确解释:
HTTP 状态访问的略微更高开销(p50 处 0.28 ms vs gRPC 的 0.12 ms),反映的是 HTTP/1.1 文本头解析相比 gRPC 二进制帧格式的额外工作——两者对典型请求而言都仍处于亚毫秒量级。
两份报告的完整对比(合并自 state 主报告 与两个分报告):
| 对比维度 | gRPC | HTTP |
|---|---|---|
| p50 | 0.57 ms | 0.73 ms |
| p99 | 1.65 ms | 1.97 ms |
| p99.9 | 2.66 ms | 2.84 ms |
| p50 附加开销 | +0.12 ms | +0.28 ms |
| Sidecar CPU | 142 mCPU | 57 mCPU |
| Sidecar 内存 | 53 MB | 48 MB |
| 成功率 | 100%(SERVING) | 100%(HTTP 204) |
值得注意的一个反差点:gRPC 延迟更低,但 Sidecar CPU 占用(142 mCPU)反而高于 HTTP(57 mCPU)。这提醒我们在做容量规划时不能只看单一指标——若追求最低请求延迟,gRPC 更优;若希望 Sidecar 资源占用更省,HTTP 在本次负载模型下表现更佳。
结论与生产实践启示
这份 v1.17.0 报告给出的三个可操作结论:
- 状态读取在 Dapr 中的成本几乎可以忽略:1,000 QPS 持续负载下,中位延迟 1 ms 以内,最差千分之一请求也低于 3 ms,Sidecar 附加开销为 0.12~0.28 ms(p50),适合作为对延迟敏感的调用路径;
- 协议选型有依据:追求极致延迟选 gRPC(+0.12 ms),追求最小 Sidecar 资源占用选 HTTP(57 mCPU / 48 MB);两者在正确性(100% 成功率、零重启)上完全一致;
- 数据可复现:测试参数、压测应用、断言阈值全部沉淀在仓库中(tests/perf/state_get_http、tests/perf/state_get_grpc、tests/apps/perf/tester),可通过
go test -tags perf按需复跑,或在既有测试基础上调整 QPS、连接数与负载大小,评估更高压力或更大负载模型下的表现(运行说明可参考 running-perf-tests.md)。
需要提醒的是:本报告使用内存态状态存储(inmemorystate),测量的是Sidecar 代理路径本身的性能上限。生产环境若接入 Redis、PostgreSQL、CosmosDB 等外部存储,端到端延迟还会叠加存储后端的网络与 IO 成本——这与 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),仅供参考