跳转到内容

智能批处理与空闲策略

别再在应用里对消息做批处理了。Aeron 已经替你做了——做得更好,而且不会增加延迟。

核心原则只有一句话:来了就发,不要等(消息一到就立即发送,不要等待)。每条消息一到达就立即发布。C media driver 会通过 sendmmsg() 把缓冲区里已有的内容合并成更少的系统调用。你既能获得批处理带来的吞吐收益,又无需为等待凑满一个批次而付出延迟代价。

在延迟与 CPU 的取舍中,真正起作用的旋钮是空闲策略(idle strategy)——而不是你的批次大小。

Aeron 的智能批处理与应用层批处理有着本质区别:

  • 不要试图把多条消息聚合到一个 MTU 里——收益是递减的。
  • C media driver 会在传输层通过 sendmmsg() 自动完成批处理。
  • 应用代码只需在消息到达时就将其发布即可。

响应时间与负载的关系:典型系统随负载急剧攀升,而 Aeron 的智能批处理让曲线在更长区间内保持平坦

传输层会自然地把时间上相近到达的消息合并成更少的系统调用。无需任何应用逻辑,更关键的是,不会增加任何等待时间。

更大的批次很快就不再有帮助。性能增益曲线是典型的边际收益递减。

吞吐增益与批次大小的关系:每增大一档批次带来的增益都不如前一档,到 batch 16–20 时趋近于零

  • 从 batch=1 提升到 batch=2 会带来显著改善。
  • 从 batch=8 提升到 batch=16 几乎没有任何收益。

这正是手写批处理会吃亏的原因。吞吐量的上升空间会迅速趋于平缓,但你为了把批次攒大而扣下的每一条消息,都会直接累加到 p50 和 p99 上。你用确定无疑的延迟代价,换来的只是边际的——最终可忽略不计的——吞吐收益。

空闲策略控制着线程轮询与让出 CPU 之间的频率。这个选择才是你在延迟与 CPU 之间真正的调节杠杆。

策略行为适用场景
BusySpin / NoOp从不让出 CPU,持续轮询最低延迟,最高 CPU 开销
Sleeping / Yield在两次轮询之间让出 CPU更低的 CPU 占用,更高的延迟

如何结合你的延迟预算来理解这张表:

  • BusySpin / NoOp 通过从不在消息到达时陷入休眠,把 p50 和 p99 压到地板上——代价是一个被完全占满的核。请把它留给专用、隔离的核心,在那里 CPU 任你尽情消耗。
  • Sleeping / Yield 用延迟换取余量。线程在两次轮询之间把 CPU 交还出去,因此一条消息可能在休眠期间到达并被迫等待——这会抬高 p50,尤其是 p99。当 CPU 是共享或存在争用、且你的尾延迟预算能够吸收这些抖动时,再使用它。

关于 media driver 如何合并发送、以及每种空闲策略的具体实现细节,请参阅 The Aeron Files