本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。
方法论
ruststream-kinesis 如何测量自己:三个循环、在 Kinesis 端点上的运行、受模拟器限制的判定计算,以及代码计数。流程就是框架自己的流程(RustStream 方法论),本页说明它在 Kinesis 上是什么样子。
三个循环
一个进程把每个场景跑三遍,作为三个循环,它们只有一处不同:承载记录的是什么。
- 裸客户端。 直接驱动
aws-sdk-kinesis:在分片迭代器上调用GetRecords,解码每条记录,为它写入检查点,并按本 crate 的节奏续约。 - Broker crate。 本 crate,上面什么也没有:Broker 建立连接,
KinesisStream描述符打开一个订阅,一个循环从它的流中取出投递、解码并 ack。 - RustStream。 用户写的服务:一个
#[subscriber]处理器及其外围的应用。
其余一切在三个循环中都相同:同一个 SdkConfig 构建所有客户端,流只有一个分片,每次读取请求 1,000 条记录,空读取等待 20 毫秒,检查点写到同样的地方,解码成同一个结构体,载荷字节、带四个工作线程的 tokio 运行时,以及二进制程序。这个等待时间有意远低于默认的一秒:回环接口上的模拟器没有按分片计算的读取额度,一秒的休眠只会测出休眠本身。
消息体是 512 字节的 JSON。它解码成一个包含两个整数字段的结构体,因此解码不做内存分配,数字反映的是本 crate,而不是 JSON 解析器。
运行
- 每次运行使用新的流。 每次运行创建自己的单分片流,DynamoDB 场景还创建自己的租约表,因此一次运行永远看不到之前的运行留下的东西。
- 消费者先接入,从 trim horizon 开始读取。随后十六个任务填充流,每条记录一次
PutRecord,并且最多领先消费者 50,000 条记录。 - 在三个循环中,计时窗口都从第一次投递开始,到读出最后一条记录的字段时结束。 创建流、获取租约和打开迭代器都在窗口之外。
- 记录条数来自一次探测,它测量裸循环的速率,因此在任何机器上,测量的运行都至少持续五秒。
- 各循环交替进行:裸、crate、RustStream,共三轮。每个循环报告它最佳、中位和最差的一轮。
当与端点之间的往返至少占一次投递所用时间的一半时,该行标为 受模拟器限制。这是算出来的。在发布任何记录之前,一次探测用一个独立的客户端,为端点能应答的最小请求 DescribeStreamSummary 计时。一次投递分摊承载它的那次 GetRecords 调用的一份,在 DynamoDB 场景下还要加上结算它的那次条件写入。文档按行把这份分摊公布为 round_trips_per_message。往返时间乘以这份分摊达到每条记录测得时间的一半时,该行就被标记。往返时间与机器信息一起公布,因此这个计算可以核对。
代码计数
开销图的每个场景都是用户写的服务,基于 KinesisBroker,连接同一个端点,构建时不带 testing 特性,在单线程运行时上启动。它从 trim horizon 读取一个为本次运行创建的单分片流,并通过默认的租约存储写入检查点。另一个线程在测量区间打开之前填充流,这个线程不计入。
指令数来自 callgrind,内存分配来自 DHAT。一个场景依次在一次投递、1000 次、2000 次上运行。后两次之差是一条记录的稳态开销,单次投递就是冷启动。一次读取由它返回的记录分摊,因此每一行都带有一次读取的一份:前两行每次读取最多一千条记录,第三行是一个 64 条记录的批。
计数涵盖服务线程运行的一切:运行时、本 crate,以及 AWS SDK 及其 HTTP 栈。SDK 自己运行的线程不计入,往返中端点那一侧的工作也不计入。同一构建的各次运行之间,指令数的变动小于百分之零点五,因为服务做真实的 I/O:一次排空结束时可能还有一次读取在途,续约和分片列举也由计时器触发。与保存的基线对照时,某个场景的指令数多出百分之二就算失败。内存分配在每次运行中都受每个场景声明的下限约束,下限高于观测到的最大计数。
自己运行
just bench
这条命令按 docker-compose.test.yml 启动 LocalStack 测试环境,运行两个对照场景,停止测试环境,并重写 docs/benchmarks/results.json。它需要几分钟,并且需要独占机器。它会清空 RUSTFLAGS,因此二进制程序不会绑定到构建它的 CPU 上。两条命令都按发布版本的方式构建基准测试,跨 crate 启用完整的链接时优化(fat LTO),因此这些数字描述的正是服务实际使用的代码。
just bench-code
代码计数需要几分钟,除测试环境外还需要 valgrind。just bench-code 5000 在五千次投递上测量每个场景,而不是一千次。在 main 上运行 just bench-code --save-baseline=main 记录基线,在分支上运行 just bench-code --baseline=main 与它对照。