gRPC 服务的性能测试
在本指南中,您将学习 gRPC 的基础知识以及如何使用 k6 编写 gRPC 性能测试。
开始之前
- 安装 k6 v0.29 或更高版本。
什么是 gRPC
gRPC 是一个轻量级的开源 RPC 框架。它最初由 Google 开发,1.0 版本于 2016 年 8 月发布。
与 JSON 这种以人类可读文本传输的方式相比,gRPC 是二进制格式,因此传输速度更快且更紧凑。对于频繁通信的分布式系统来说,这些改进累积起来会迅速显现,不仅在基准测试中显而易见,终端用户也能感受到差异。
API 类型
gRPC 支持四种不同类型的 RPC:一元、服务器流式、客户端流式和双向流式。实际上,消息是通过同一个连接进行多路复用的,但为了保持简单易懂,下面的 gRPC 服务模型图并未展示这一点。
一元 (Unary)
一元调用与常规函数调用工作方式相同:客户端发送单个请求到服务器,服务器回复单个响应。
服务器流式 (Server streaming)
在服务器流式模式下,客户端向服务器发送单个请求,服务器则回复多个响应。
客户端流式 (Client streaming)
客户端流式模式与服务器流式模式相反。客户端向服务器发送多个请求,服务器则回复单个响应。
双向流式 (Bi-directional streaming)
在双向流式模式下,客户端和服务器都可以发送多个消息。
.proto
定义
用于 gRPC 的消息和服务在 .proto 文件中描述,这些文件包含 Protocol buffers(或简称 protobuf)定义。
然后使用定义文件生成代码,供发送方和接收方用作通过这些消息和服务进行通信的契约。由于 gRPC 使用的二进制格式缺乏自描述属性,这是发送方和接收方了解如何解释消息的唯一方式。
对于本指南,您可以使用 QuickPizza 演示应用程序 GitHub 存储库中提供的 quickpizza.proto
定义。有关如何构建您自己的 gRPC proto 定义的详细信息,请参阅官方 gRPC 文档。
syntax = "proto3";
option go_package = "pkg/grpc/quickpizza";
package quickpizza;
service GRPC {
rpc Status(StatusRequest) returns (StatusResponse) {}
rpc RatePizza(PizzaRatingRequest) returns (PizzaRatingResponse) {}
}
message StatusRequest {
}
message StatusResponse {
bool ready = 1;
}
message PizzaRatingRequest {
repeated string ingredients = 1;
string dough = 2;
}
message PizzaRatingResponse {
int32 stars_rating = 1;
}
使用 k6 编写 gRPC 性能测试
从 k6 v0.29.0 开始,您可以使用内置模块进行 gRPC 通信。您可以在 k6/net/grpc 模块文档中找到所有可用方法的详细信息。
创建测试
gRPC 模块是一个单独的模块,您可以从测试脚本中以 k6/net/grpc
方式访问它。在使用之前,您必须先创建一个客户端实例。客户端实例化以及 load()
函数仅在测试初始化期间可用,即直接在全局作用域中。
import grpc from 'k6/net/grpc';
import { check, sleep } from 'k6';
const client = new grpc.Client();
接下来,加载适用于被测系统的 .proto
定义。为了本文的目的,您可以使用 QuickPizza。
注意
QuickPizza gRPC 服务 URL grpc-quickpizza.grafana.com:443 如果您在浏览器中访问它,会返回 464 HTTP 状态码。但是,您仍然可以在 k6 测试脚本中使用它,gRPC 功能将正常工作。
load()
函数接受两个参数,第一个参数是搜索 proto 文件的路径数组,第二个参数是要加载的文件名。
import grpc from 'k6/net/grpc';
import { check, sleep } from 'k6';
// Download quickpizza.proto for grpc-quickpizza.grafana.com, located at:
// https://raw.githubusercontent.com/grafana/quickpizza/refs/heads/main/proto/quickpizza.proto
// and put it in the same folder as this script.
const client = new grpc.Client();
client.load(['definitions'], 'quickpizza.proto');
完成后,添加调用 gRPC 服务的测试其余部分。
import grpc from 'k6/net/grpc';
import { check, sleep } from 'k6';
// Download quickpizza.proto for grpc-quickpizza.grafana.com, located at:
// https://raw.githubusercontent.com/grafana/quickpizza/refs/heads/main/proto/quickpizza.proto
// and put it in the same folder as this script.
const client = new grpc.Client();
client.load(null, 'quickpizza.proto');
export default () => {
client.connect('grpc-quickpizza.grafana.com:443', {
// plaintext: false
});
const data = { ingredients: ['Cheese'], dough: 'Thick' };
const response = client.invoke('quickpizza.GRPC/RatePizza', data);
check(response, {
'status is OK': (r) => r && r.status === grpc.StatusOK,
});
console.log(JSON.stringify(response.message));
client.close();
sleep(1);
};
此测试脚本执行以下操作:
- 首先,它使用
.connect()
函数连接到被测系统。默认情况下,客户端将plaintext
设置为 false,只允许您使用加密连接。如果出于任何原因需要连接到缺少 SSL/TLS 的服务器,只需将此设置切换为true
。 - 然后脚本继续创建要发送到正在调用的远程过程的对象。在
RatePizza
的情况下,对象包含比萨的配料和面团类型。 - 接下来,它使用 proto 文件中描述的
<package>.<service>/<procedure>
语法调用远程过程。此调用是同步的,默认超时为 60000 毫秒(60 秒)。要更改超时,请将键timeout
添加到.connect()
的 config 对象中,并将持续时间作为值,例如'2s'
表示 2 秒。 - k6 从服务器接收到响应后,脚本会检查以确保过程执行成功。gRPC 模块包含用于此比较的常量,这些常量列在此处。将响应状态与
grpc.StatusOK
进行比较(它与 HTTP/1.1 通信一样是200 OK
),确保调用成功完成。 - 脚本然后记录响应中的消息,关闭客户端连接,并暂停一秒。
运行测试
您可以使用 k6 run
命令像运行任何其他测试一样执行此测试:
$ k6 run grpc-example.js
/\ Grafana /‾‾/
/\ / \ |\ __ / /
/ \/ \ | |/ / / ‾‾\
/ \ | ( | (‾) |
/ __________ \ |_|\_\ \_____/
execution: local
script: grpc-example.js
output: -
scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
* default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)
INFO[0000] {"starsRating":3} source=console
✓ status is OK
checks...............: 100.00% 1 out of 1
data_received........: 4.1 kB 3.6 kB/s
data_sent............: 762 B 656 B/s
grpc_req_duration....: avg=33.75ms min=33.75ms med=33.75ms max=33.75ms p(90)=33.75ms p(95)=33.75ms
iteration_duration...: avg=1.16s min=1.16s med=1.16s max=1.16s p(90)=1.16s p(95)=1.16s
iterations...........: 1 0.860427/s
vus..................: 1 min=1 max=1
vus_max..............: 1 min=1 max=1
running (00m01.2s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs 00m01.2s/10m0s 1/1 iters, 1 per VU
从输出中,您可以检查脚本是否正常工作,以及服务器是否确实回复了请求体中提供的比萨类型的评分。您还可以看到 check
成功了,这意味着服务器回复了 200 OK
。
总结
在本文中,您了解了一些 gRPC 的基础知识及其工作原理。您还查看了 k6 gRPC 客户端并创建了一个有效的测试脚本来演示其功能。