gpt4 book ai didi

Java NIO 选择器可能的最小延迟

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:24:37 24 4
gpt4 key购买 nike

我正在通过环回 (127.0.0.1) 在 Linux 上使用优化的 Java NIO 选择器进行一些基准测试。

我的测试很简单:

  • 一个程序将一个 UDP 数据包发送到另一个程序,另一个程序将其回显给发送者并计算往返时间。下一个数据包仅在前一个数据包被确认(返回时)时才发送。在执行基准测试之前,会使用几百万条消息进行适当的预热。消息有 13 个字节(不包括 UDP header )。

对于往返时间,我得到以下结果:

  • 最短时间:13 微秒
  • 平均时间:19 微秒
  • 75% 百分位数:18,567 纳米
  • 90% 百分位数:18,789 纳米
  • 99% 百分位数:19,184 纳米
  • 99.9% 百分位数:19,264 纳米
  • 99.99% 百分位数:19,310 纳米
  • 99.999% 百分位数:19,322 纳米

但这里的问题是我正在旋转 100 万条消息。

如果我只旋转 10 条消息,我会得到非常不同的结果:

  • 最短时间:41 微秒
  • 平均时间:160 微秒
  • 75% 百分位数:150,701 纳米
  • 90% 百分位数:155,274 纳米
  • 99% 百分位数:159,995 纳米
  • 99.9% 百分位数:159,995 纳米
  • 99.99% 百分位数:159,995 纳米
  • 99.999% 百分位数:159,995 纳米

如果我错了请纠正我,但我怀疑一旦我们让 NIO 选择器旋转,响应时间就会变得最佳。但是,如果我们发送的消息之间的间隔足够大,我们就会付出唤醒选择器的代价。

如果我尝试只发送一条消息,我会收到 150 到 250 微秒之间的不同时间。

所以我对社区的问题是:

1 - 我的最小时间为 13 微秒,平均为 19 微秒,最适合此往返数据包测试。看来我在打ZeroMQ到目前为止,我可能在这里遗漏了一些东西。从这个基准来看,ZeroMQ 在标准内核上的平均时间为 49 微秒(99% 百分位数)=> http://www.zeromq.org/results:rt-tests-v031

2 - 当我旋转单个或很少的消息时,我可以做些什么来改善选择器的 react 时间? 150 micros 看起来不太好。或者我应该假设在产品环境中选择器不会完全正确?


通过忙着围绕 selectNow() 旋转,我可以获得更好的结果。发送少量数据包仍然比发送许多数据包更糟糕,但我认为我现在达到了选择器性能极限。我的结果:

  • 发送单个数据包时,我得到了一致的 65 微秒往返时间。
  • 发送两个数据包平均往返时间约为 39 微秒。
  • 发送 10 个数据包平均需要大约 17 微秒的往返时间。
  • 发送 10,000 个数据包,平均往返时间约为 10,098 纳秒。
  • 发送 100 万个数据包平均需要 9,977 纳秒的往返时间。

结论

  • 所以看起来 UDP 数据包往返的物理屏障平均为 10 微秒,尽管我有一些数据包在 8 微秒(最短时间)内完成了一次传输。

  • 通过繁忙的旋转(感谢 Peter),我能够将单个数据包的平均 200 微增至一致的平均 65 微。

  • 不确定为什么 ZeroMQ 是 5 times slower比起那个来说。 (编辑:可能是因为我在同一台机器上通过环回测试这个,而 ZeroMQ 使用的是两台不同的机器?)

最佳答案

你经常看到唤醒线程的情况可能非常昂贵,不仅仅是因为线程唤醒需要时间,而且线程运行速度慢了 2-5 倍,因为缓存和

我过去避免这种情况的方法是忙等待。不幸的是,即使它是一个空集合,每次调用它时 selectNow 都会创建一个新集合。这会产生如此多的垃圾,不值得使用。

绕过它的一种方法是忙于等待非阻塞套接字。这并不能很好地扩展,但可以为您提供最低的延迟,因为线程不需要唤醒,并且您在此之后运行的代码更有可能位于缓存中。如果您也使用线程亲和性,它可以减少您的线程干扰。

我还建议尽量减少代码锁定和垃圾。如果你这样做,你可以在 Java 中有一个进程,它在 90% 的时间内在 100 微秒内发送对传入数据包的响应。这将允许您在每个数据包到达时以 100 Mb 的速度处理它们(由于带宽限制,最多间隔 145 微秒)对于 1 Gb 的连接,您可以非常接近。


如果你想在 Java 的同一个盒子上进行快速进程间通信,你可以考虑像 https://github.com/peter-lawrey/Java-Chronicle 这样的东西。这使用共享内存传递消息,往返延迟(使用套接字更难有效地做到这一点)小于 200 纳秒。它还会保留数据,如果您只是想要一种快速生成日志文件的方法,它会很有用。

关于Java NIO 选择器可能的最小延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12099446/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com