HeadlinesBriefing favicon HeadlinesBriefing.com

快速Tokio应用程序的原则

Hacker News •
×

我正在从Rust Conf回来的路上。在Unconf上,我们进行了一场富有成效的讨论,主题是调试和基准测试异步应用程序。许多有趣的见解被分享了出来。我试图在这里列举其中一些,以及我自己的一些经验。这是我希望能成为一份关于最佳实践的活文档的第一稿。欢迎提交issue或PR。我希望在接下来的几天里还能添加一个示例应用,演示这些问题以及dial9 trace的样子。—— Russell

关于编写在Tokio运行时上表现良好的代码,几乎没有硬性规则;许多问题的答案是“视情况而定”。一个工作负载的性能取决于当时运行时上还在运行什么。这就是为什么这么多问题只在生产环境中才会出现!编写表现良好的异步应用程序,是在公平性与批处理、竞争与隔离之间的平衡。这篇文章列出了一些一般原则,并在可能的地方涵盖了例外情况。它假定读者对Tokio的工作窃取运行时(work-stealing runtime)有基本了解;附录中包含了高层次概述。

一般原则

首先,确定你是否真的有问题。如果你开始在Tokio应用程序中寻找危险信号,你一定会找到。我见过的几乎每一个真实应用程序的poll时间都远长于10-100微秒——这是Alice Ryhl在她那篇出色的文章What is Blocking?中建议的。这些问题可能会也可能不会影响你真正关心的应用程序指标或行为。重要的是从你试图改进的真实指标出发倒推。例如,一个应用程序可能有完全无害的长poll;“修复”它们不会对面向用户的指标产生可测量的影响。在我遇到的绝大多数问题中,问题都出在应用程序代码本身,往往是在分布式系统多个组件之间的交互中(而实际上并不在Tokio中)。dial9为Tokio提供了大量可见性;至少与它发现Tokio问题的频率一样高,它实际上清楚地证明了Tokio没有问题。当然,有时确实是Tokio的问题。就Tokio指标而言,最有用的最近新增的调度延迟直方图(schedule latency histogram)。调度延迟是你的任务准备好运行到Tokio实际poll该future之间的时间量。虽然这不会告诉你原因是什么,但调度延迟是Tokio与你的代码之间不良交互最常见的症状。

为延迟而拆分,为吞吐量而批处理。更频繁地yield以优化延迟。跨许多请求的低延迟需要连接之间的公平性。考虑Redis(或任何支持请求流水线的应用程序)。一个朴素的实现会在还有数据可用时直接从连接读取数据。当请求被流水线化时,整个流水线化的请求最终会进入一个内存缓冲区。当你从中读取帧时,每一帧都会是Poll::Ready,而无需回到网络。这既造成了长poll,也造成了客户端之间的不公平。对吞吐量的影响通常较小:处理了相同数量的请求。然而,延迟会发生巨大变化,因为一个完整的流水线可能排在另一个后面等待。在这个例子中,在每个请求之后显式yield可以将延迟降低大约10倍。你还可以做得更好:只在连续几次立即可读的读取之后再yield。

关键实体:公司:Tokio、Redis | 人物:Russell、Alice Ryhl | 地点:Rust Conf

FAQ:诊断性能问题时最有用的Tokio指标是什么?

最近新增的调度延迟直方图是最有用的Tokio指标。调度延迟是你的任务准备好运行到Tokio实际poll该future之间的时间量。虽然这不会告诉你原因是什么,但调度延迟是Tokio与你的代码之间不良交互最常见的症状。