☰
grpc-rust 基准测试框架解析:Worker、Server 与 Client 三大组件的 gRPC 性能压测实现
2026/10/2 1:58:04 网站建设 项目流程
  • 后端
  • RPC框架

【免费下载链接】grpc-rust

A native gRPC client & server implementation with async/await support.

项目地址:https://gitcode.com/GitHub_Trending/to/grpc-rust
点击查看免费下载

本指南聚焦当前仓库中grpc-benchmark目录下的 gRPC 基准测试框架代码,完整剖析其在 Rust 生态中落地 gRPC 官方基准测试协议的方式:包括 worker 进程的启动方式、BenchmarkServer 与 BenchmarkClient 的压测实现、直方图延迟统计原理,以及独立命令行工具bench的使用方法。读完本文,你将掌握这套框架的目录结构、控制协议(control.proto)中各个配置字段的含义、压测数据的采集与上报机制,并能直接编译运行 worker 与 bench 对本地 gRPC 服务发起基准测试。

框架定位:gRPC 官方基准测试体系中的 Rust 实现

grpc-benchmark/README.md 明确指出:该目录承载的是gRPC Benchmarking Framework(gRPC 基准测试框架)中 worker、server、client 三部分的 Rust 实现代码。框架的整体设计遵循 gRPC 官方的基准测试约定:

  • Driver(驱动):负责编排整个测试场景(如并发数、RPC 类型、测试时长),向各 worker 下发配置并汇总结果;官方驱动代码及运行说明位于 gRPC 官方仓库的tools/run_tests/performance目录下,不在本仓库内;
  • Worker(工作进程):由 driver 通过 gRPC 远程调用控制,负责在本机启动压测 server 或 client;
  • BenchmarkServer / BenchmarkClient:真正执行负载与统计的实体;
  • 持续监控:官方通过这套基准测试持续跟踪各语言 gRPC 实现的性能,指标数据汇总到 gRPC 官方性能仪表盘(README 中提到的 performance dashboard)。

需要说明的是:本仓库内虽然没有官方 driver 的代码,但提供了一个自包含的独立驱动工具bench(源码见 grpc-benchmark/src/bin/bench.rs),它可以本地拉起 worker、下发配置、运行压测并直接打印报告,便于在无法连接官方 driver 的情况下快速验证框架本身。这也从侧面印证了 worker/server/client 三层架构在 Cargo.toml 中的落地:该 crate 声明了两个二进制目标bench与worker,并导出了库模块供二者复用。

目录结构与模块总览

grpc-benchmark的核心布局如下(以下路径均以仓库根目录为起点):

路径职责
grpc-benchmark/src/main.rsworker二进制入口:解析--driver_port并启动 WorkerService gRPC 服务
grpc-benchmark/src/bin/bench.rsbench二进制入口:自包含驱动,解析压测参数并驱动 worker
grpc-benchmark/src/worker.rsWorkerService实现:暴露run_server、run_client、core_count、quit_worker四个 RPC
grpc-benchmark/src/server.rsBenchmarkServer与被测BenchmarkService(proto 服务器)实现
grpc-benchmark/src/client.rsBenchmarkClient:闭循环压测负载生成与延迟直方图采集
grpc-benchmark/src/rusage.rs跨平台 CPU 用户态/内核态时间采集封装
grpc-benchmark/src/lib.rs汇总生成代码与模块,同时编译 protobuf 与 tonic 两套生成产物
grpc-benchmark/proto/grpc/testing/官方基准测试协议定义:control.proto、benchmark_service.proto、stats.proto、payloads.proto、messages.proto、worker_service.proto等
grpc-benchmark/data/tls/基准测试专用 TLS 测试证书(ca.pem、server1.pem、server1.key)

lib.rs中generated模块同时 include 了两套代码生成产物:一套是基于 protobuf 运行时(protoc-gen-rust-grpc风格,模块路径generated::grpc::testing),一套是基于 tonic 与 prost(generated::services::grpc::testing)。前者用于驱动脚本bench构造配置消息,后者用于实现真正的 gRPC 服务与客户端。build 阶段的代码生成由grpc-protobuf-build、protoc-gen-rust-grpc与tonic-prost-build三个本地 crate 完成(见 Cargo.toml 的 build-dependencies)。

worker:承载压测的 gRPC 服务进程

启动方式与命令行参数

worker是一个独立的可执行文件,其唯一必需参数是 driver 通信端口,用法如下:

worker --driver_port=<port>

从 grpc-benchmark/src/main.rs 的解析逻辑可以看到:入口会遍历std::env::args(),仅接受形如--driver_port=<port>的参数,port必须是合法的u16端口号,否则打印错误并退出;其他未知参数会打印Warning: Unrecognized argument。未提供--driver_port时输出Usage: worker --driver_port=<port>并以非零码退出。该文件注释还解释了线程模型的一个设计取舍:默认 Tokio 运行时每个逻辑处理器一个线程,官方测试框架虽然支持在测试配置中指定线程数,但部署在 k8s 上的测试依赖特定机型规格、不期望 client/server 自行限制资源占用,且 Tokio 不支持嵌套运行时,因此当前版本未实现按测试配置设定线程数的能力。

WorkerService 的四个 RPC

worker进程通过tonic启动一个 gRPC 服务,将WorkerServiceServer::new(WorkerServer::new(quit_notify))挂载到0.0.0.0:<driver_port>,并使用serve_with_shutdown让quit_workerRPC 触发优雅退出(见 grpc-benchmark/src/main.rs 的run_worker)。WorkerService定义于官方协议文件 grpc-benchmark/proto/grpc/testing/worker_service.proto,其 Rust 实现位于 grpc-benchmark/src/worker.rs:

  • run_server/run_client:均为服务端流式 RPC。driver 通过流式请求先下发Setup(对应ServerConfig/ClientConfig),之后周期性下发Mark(reset为 true 表示快照后清零统计)来取回统计数据。worker 端使用async_stream::try_stream!逐个处理请求,并禁止重复启动(already_exists错误)。统计通过闭包yield回ServerStatus/ClientStatus,其中ServerStatus还携带绑定的端口号与可用 CPU 核数;
  • core_count:一元 RPC,返回available_parallelism()探测到的逻辑核数;
  • quit_worker:一元 RPC,触发Notify通知serve_with_shutdown正常退出。

run_server的实现细节(grpc-benchmark/src/worker.rs 的run_server分支)体现了ServerStatus的字段来源:stats来自BenchmarkServer::get_stats,cores来自core_count(),port来自server.port()——其中端口是启动时实际绑定到的端口(配置为 0 时由系统分配)。run_client分支则要求 client 存在时才能响应Mark,并在每个请求处理后异步取回ClientStats。

控制协议:配置字段与语义

所有压测配置都定义在官方控制协议 grpc-benchmark/proto/grpc/testing/control.proto 中,理解这些字段是正确使用框架的前提:

ClientConfig 关键字段

  • server_targets:待连接的目标列表(至少一个);worker 端实际构造连接时会在每个 target 前补dns:///前缀(见 grpc-benchmark/src/client.rs);
  • client_type:SYNC_CLIENT、ASYNC_CLIENT等枚举;当前 Rust 实现接受SyncClient与AsyncClient两种取值;
  • outstanding_rpcs_per_channel:每个 channel 上并发的在途 RPC 数(必须 > 0);
  • client_channels:要创建的独立 channel 数(必须 > 0),第 i 个 channel 连接server_target[i % size];
  • rpc_type:UNARY/STREAMING(服务端流式 ping-pong)等枚举;
  • load_params:负载模型。ClosedLoopParams(一个 RPC 完成后立即发起下一个)是当前实现的唯一支持项;PoissonParams(泊松到达率的开放环路)在源码中显式返回unimplemented,注释说明待 xDS 基准测试支持时再实现;
  • payload_config:负载内容。支持SimpleProtoParams(req_size/resp_size);ByteBufferParams与ComplexProtoParams在 client 与 server 中均返回unimplemented;
  • histogram_params:延迟直方图参数(resolution与max_possible,语义见下文)。

ServerConfig 与安全参数

ServerConfig的关键字段是port(0 表示由系统挑选空闲端口,实际绑定值通过ServerStatus.port回传给驱动)与security_params。SecurityParams中use_test_ca为 true 时启用 TLS 并使用内置测试证书;server_host_override用于客户端覆盖连接 authority(SNI/证书校验主机名)。

负载与基准服务定义

被测服务定义于 grpc-benchmark/proto/grpc/testing/benchmark_service.proto,即BenchmarkService:

  • UnaryCall(SimpleRequest) returns (SimpleResponse):一请求一响应,服务器原样回显客户端负载;
  • StreamingCall(stream SimpleRequest) returns (stream SimpleResponse):流式 ping-pong,逐条回显;
  • StreamingFromClient/StreamingFromServer/StreamingBothWays:其余三种组合形态,本仓库的 proto server 均返回unimplemented(见 grpc-benchmark/src/server.rs 中ProtoServer的实现)。

BenchmarkServer:被压测服务的实现要点

BenchmarkServer::start(grpc-benchmark/src/server.rs)负责按ServerConfig拉起被压测服务,核心要点如下:

  1. HTTP/2 自适应窗口:Server::builder().http2_adaptive_window(Some(true))开启自适应流控窗口,这是基准测试场景下提升高带宽流吞吐的常见调优项;
  2. TLS 支持:当配置了SecurityParams且use_test_ca为 true 时,加载编译期嵌入的测试证书(include_bytes!读取 grpc-benchmark/data/tls/server1.pem 与server1.key)构造ServerTlsConfig;否则使用空的 TLS 配置;
  3. 动态端口:port = 0时绑定到0.0.0.0:0,由操作系统分配端口,随后通过local_addr()获取实际端口并保存到BenchmarkServer.port;
  4. TCP 细节:对每个接入连接调用set_nodelay(true)关闭 Nagle 算法,降低小包延迟;
  5. 统计采样:get_stats(reset)基于Instant与Rusage(见 grpc-benchmark/src/rusage.rs,Unix 下用nix的getrusage(RUSAGE_SELF)取用户态与内核态时间差)计算time_elapsed、time_user、time_system,并返回ServerStats;cq_poll_count等字段按官方约定置 0(Java 与 Go 同样不设置这些字段)。

被测 handler 的实现非常轻量:unary_call构造一个响应体为vec![0; response_size]的SimpleResponse直接返回;streaming_call对入站流逐条回显同样大小的响应体,模拟真实协议开销但不去做业务计算,从而让压测聚焦在 RPC 框架本身的吞吐与延迟上。

BenchmarkClient:闭循环压测与直方图采集

BenchmarkClient::start(grpc-benchmark/src/client.rs)是压测负载的生成端,实现要点如下:

  1. 配置校验:依次校验client_type、payload_config(仅接受SimpleParams)、load_params(仅接受ClosedLoop)、client_channels > 0、outstanding_rpcs_per_channel > 0、server_targets非空;不合规即返回带具体原因的invalid_argument/unimplemented状态;
  2. TLS 客户端凭证:若配置use_test_ca,加载内置 grpc-benchmark/data/tls/ca.pem 作为信任根构造RustlsChannelCredentials;若提供server_host_override,则通过Channel::builder(...).authority(...)覆盖连接 authority(测试场景中常用假域名foo.test.google.fr配合测试 CA 做证书校验);否则使用LocalChannelCredentials(明文连接);
  3. 任务拓扑:任务总数num_tasks = client_channels × outstanding_rpcs_per_channel;每个 channel 一个Channel,按rpc_type为每个在途 RPC spawn 一个 Tokio 任务,运行blocking_unary或blocking_streaming的闭循环;
  4. 闭循环语义:每个任务循环执行——先检查取消标记与统计请求标记(watch通道),再发起一次 RPC 并计时,将耗时(纳秒)记录进共享的hdrhistogram::Histogram;统计请求到达时将直方图快照通过mpsc通道送回,reset为 true 时清空直方图后继续。流式模式下是"发送一条请求 → 接收一条响应"的 ping-pong,时间从发送前计时到接收完成;
  5. 统计聚合:get_stats通过watch::Sender广播统计请求,等待所有num_tasks个直方图回传并合并(2 秒超时返回deadline_exceeded),随后基于合并结果计算min_seen、max_seen、sum、sum_of_squares、count,并按指数桶把频次铺满到max_possible上限(驱动端期望覆盖全部桶区间),封装为ClientStats返回。

直方图与延迟百分位计算

延迟统计依赖HistogramParams的两个参数(grpc-benchmark/proto/grpc/testing/stats.proto):

  • resolution:第一个桶为[0, 1 + resolution),后续桶按resolution指数增长,默认 0.01(即 1%);
  • max_possible:覆盖的最大延迟上限,超过该值histogram.record会失败并打印告警(bench 中设为60e9纳秒,即 60 秒)。

bench通过calculate_percentile(grpc-benchmark/src/bin/bench.rs)在HistogramDataView上做线性插值:累计桶频次直至达到percentile × count,再在目标桶内按比例内插出延迟值,从而得到 p50 / p90 / p99 等指标。

独立驱动 bench:无需官方 driver 的本地压测

bench是理解整套框架调用关系的最佳入口(grpc-benchmark/src/bin/bench.rs)。它展示了"驱动 → worker → 被测服务/客户端"的完整闭环,运行流程为:

  1. 在127.0.0.1:0上临时绑定一个监听端口作为 worker 服务端口,本地 spawnWorkerServiceServer;
  2. 用grpccrate 的Channel(dns:///127.0.0.1:<port>+LocalChannelCredentials)创建WorkerServiceClient;
  3. 通过run_server流式 RPC 下发ServerConfig{port: 0}(动态端口),等待ServerStatus返回真实绑定端口;
  4. 通过run_client流式 RPC 下发ClientConfig,等待客户端就绪;
  5. 先预热 5 秒,随后发送Mark{reset: true}清零统计,再运行设定的时长;
  6. 发送Mark{reset: false}取回最终ClientStats,计算并打印报告;
  7. 关闭两个流并通知本地 worker 退出。

命令行参数

从--help输出(grpc-benchmark/src/bin/bench.rs 的main函数)可以拿到完整的参数清单:

Usage: bench --duration <secs> --channels <num> --rpcs-per-channel <num> --rpc-type <unary|streaming> [--secure] [--req-size <bytes>] [--resp-size <bytes>]
参数必填默认值说明
-d, --duration是无压测时长(秒)
--channels否1客户端 channel 数
--rpcs-per-channel是无每个 channel 的并发在途 RPC 数
--rpc-type是无unary或streaming,其他取值报错
--secure否关闭启用 TLS(使用内置测试 CA)
--req-size否1请求负载字节数
--resp-size否1响应负载字节数

参数解析使用pico-args,多参数字段解析完成后会调用pargs.finish(),任何未消费的残留参数都会被当作错误抛出。启用--secure时,bench 会在ServerConfig中设置SecurityParams{use_test_ca: true},并在ClientConfig中设置SecurityParams{use_test_ca: true, server_host_override: "foo.test.google.fr"}——这正是上面提到的测试 CA + 主机名覆盖的典型用法。

报告输出示例

压测结束后 bench 按如下格式打印结果(QPS 由count / time_elapsed计算,延迟单位毫秒,来自calculate_percentile的插值结果):

Benchmark Config: Duration: 10 s Channels: 1 RPCs per channel: 16 RPC type: unary Security: insecure Request size: 100 bytes Response size: 100 bytes Benchmark server bound to port: 49821 Warming up for 5 seconds... Running benchmark for 10 seconds... Report: QPS: 152301.25 Avg Latency: 0.1037 ms 50th Percentile Latency: 0.0923 ms 90th Percentile Latency: 0.1310 ms 99th Percentile Latency: 0.2846 ms

编译与运行

在仓库根目录(工作区)下,可以分别运行两个二进制:

# 方式一:worker 模式(供官方 driver 或自定义驱动远程调用) cargo run -p grpc-benchmark --bin worker -- --driver_port=50051 # 方式二:bench 模式(自包含驱动,本地完成全流程压测) cargo run -p grpc-benchmark --bin bench -- \ --duration 10 --channels 2 --rpcs-per-channel 8 \ --rpc-type unary --req-size 100 --resp-size 100 # TLS 模式 cargo run -p grpc-benchmark --bin bench -- \ --duration 10 --channels 1 --rpcs-per-channel 4 \ --rpc-type streaming --secure

编译该 crate 需要仓库内多个本地依赖(grpc、tonic、tonic-prost、grpc-protobuf、protoc-gen-rust-grpc、grpc-protobuf-build、tonic-prost-build等),且 Unix 平台下额外引入nix(resourcefeature)用于资源统计;tonic依赖启用了tls-aws-lc特性(main 入口中通过rustls::crypto::aws_lc_rs::default_provider().install_default()安装默认加密提供者)。需要说明的是:当前实现聚焦于官方基准测试框架的协议兼容,ByteBufferParams、ComplexProtoParams、泊松负载与其余三种流式 RPC 形态在源码中明确标注为未实现,使用时应以SimpleProtoParams+UnaryCall/StreamingCall场景为准。

与官方框架的关系及适用前提

需要再次强调的是本目录在 gRPC 生态中的定位(依据 grpc-benchmark/README.md 的原文表述):本目录只包含 worker、server、client 三个环节的实现,驱动编排代码与完整的运行指导位于 gRPC 官方仓库的tools/run_tests/performance目录,属于外部独立维护的部分;官方通过这些基准测试持续监控各语言 gRPC 实现的性能,并将指标呈现于其性能仪表盘。因此,本文所讲述的worker二进制面向的是官方 driver 下发配置的交互协议,而bench则是本仓库为便于本地验证而提供的独立入口。理解这一分工,就能清楚区分"协议实现"(本仓库的 Rust 部分)与"场景编排"(官方 driver)的边界,也能更准确地解读control.proto中Scenario、ScenarioResultSummary等由 driver 侧消费的数据结构。

  • 后端
  • RPC框架

【免费下载链接】grpc-rust

A native gRPC client & server implementation with async/await support.

项目地址:https://gitcode.com/GitHub_Trending/to/grpc-rust
点击查看免费下载

相关推荐

上一篇:如何快速解决歌词不同步问题:LyricsX歌词偏移调整终极指南
下一篇:KoboldAI-Client实战指南:本地AI写作助手深度解析与部署实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询