跳到主要内容
英文版本为准

本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。

方法论

ruststream-sea-file 如何测量自己:三个循环、读取流文件的两种方式、受存储限制的判定计算,以及代码计数。流程就是框架自己的流程(RustStream 方法论),本页说明它在流文件上是什么样子。

三个循环​

一个进程把每个场景跑三遍,作为三个循环,它们只有一处不同:承载消息的是什么。

  • 裸客户端。 直接驱动 sea-streamer-file:它的 streamer、消费者和生产者。
  • Broker crate。 本 crate,上面什么也没有:FileBroker 建立连接,FileStream 打开一个订阅,一个循环从它的流中取出投递、解码并结算。
  • RustStream。 用户写的服务:一个 #[subscriber] 处理器及其外围的应用。

其余一切在三个循环中都相同:流文件、消费者选项、解码成同一个结构体、载荷字节、带四个工作线程的 tokio 运行时,以及二进制程序。裸客户端没有结算要做,本 crate 的结算会立即报告 AckError::Unsupported,因此没有哪个循环需要等待结算。

消息体是 512 字节的 JSON。它解码成一个包含两个整数字段的结构体,因此解码不做内存分配,数字反映的是本 crate,而不是 JSON 解析器。

两个场景​

  • 重放。 先写好整个文件,然后每个循环从开头读取它。文件比计时窗口统计的数量多出 8192 条消息体,因此没有哪个循环会读到末尾。
  • 实时跟随。 先打开订阅,每个循环一边读取,一边通过自己的那一层追加。和本 crate 的发布者一样,每次追加都在下一次之前刷写到文件,写入者最多领先读取者 32 768 条消息。

运行​

  • 每次运行使用新的流文件。 它位于 target/bench-streams 下,运行结束时删除,因此一次运行永远读不到之前的运行留下的东西。
  • 在三个循环中,计时窗口都从第一次投递开始,到最后一个处理器返回时结束。 打开文件、创建消费者和写入被记录的区域都在窗口之外。
  • 消息条数来自一次探测,它用 100 000 条消息测量裸循环的速率,因此在任何机器上,测量的运行都至少持续五秒。条数最多为两百万条消息,约合一 GiB 的流文件。
  • 各循环交替进行:裸、crate、RustStream,共三轮。每个循环报告它最佳、中位和最差的一轮。
  • 页缓存是热的。 每次运行都在读回文件之前刚刚写入它,因此这些数字反映的是文件系统,而不是设备。

当裸客户端在运行中一直在等待追加时,该行标为 受存储限制。这是算出来的:一次探测在 5000 次预热之后,为 50 000 次追加计时,每次追加都刷写到文件。实时跟随每次投递等待一次追加,重放则不等待。等待时间达到每条消息测得时间的一半时,该行就被标记。一次追加的时间与机器信息一起公布,因此这个计算可以核对。

代码计数​

开销图的每个场景都是用户写的服务,基于 FileBroker,使用自己的流文件,构建时不带 testing 特性。服务运行在单线程运行时上。服务启动之后,另一个线程通过客户端追加消息,这部分工作在测量区间之外。

指令数来自 callgrind,内存分配来自 DHAT。一个场景依次在一次投递、1000 次、2000 次上运行。后两次之差是一条消息的稳态开销,单次投递就是冷启动。

同一个二进制程序运行五次,每条消息的数字相差在千分之五以内。唯一的例外是应答的内存分配,它在 70 到 74 之间变动,取决于服务等待写入者的次数。一次运行的指令总数最多变动 2.7%。因此,与保存的基线对照时,某个场景的指令数多出百分之六就算失败。内存分配在每次运行中都受每个场景声明的下限约束。

自己运行​

just bench

这条命令让两个对照场景都经过全部三个循环,删除流文件,并重写 docs/benchmarks/results.json。它需要独占机器,并且会通过 target/bench-streams 写入数 GiB 的数据,每次一个文件,最大约一 GiB。它会清空 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 与它对照。