16

我正在编写一个 Netty 应用程序。该应用程序在 64 位八核 linux 机器上运行

Netty 应用程序是一个简单的路由器,它接受请求(传入管道)从请求中读取一些元数据并将数据转发到远程服务(传出管道)。

此远程服务将向传出管道返回一个或多个响应。Netty 应用程序会将响应路由回原始客户端(传入管道)

将有成千上万的客户。将有数千个远程服务。

我正在做一些小规模的测试(十个客户端,十个远程服务),我没有看到我期望的 99.9% 的 10 毫秒以下的性能。我正在从客户端和服务器端测量延迟。

我正在使用类似于 SPDY 的完全异步协议。我在处理 FrameDecoder 中的第一个字节时捕获时间(我只使用 System.nanoTime())。我在调用 channel.write() 之前停止了计时器。我正在测量从传入管道到传出管道的亚毫秒时间(99.9%),反之亦然。

我还测量了从 FrameDecoder 中的第一个字节到在(以上)message.write() 上调用 ChannelFutureListener 回调的时间。时间高达几十毫秒(99.9%),但我很难说服自己这是有用的数据。

我最初的想法是我们有一些缓慢的客户。我观看了 channel.isWritable() 并在返回 false 时记录。这个方法在正常情况下没有返回false

一些事实:

  • 我们正在使用 NIO 工厂。我们没有自定义工人大小
  • 我们已禁用 Nagel (tcpNoDelay=true)
  • 我们启用了保持活动 (keepAlive=true)
  • CPU 90+% 的时间处于空闲状态
  • 网络空闲
  • GC(CMS)每 100 秒左右被调用一次,时间很短

有没有我可以遵循的调试技术来确定为什么我的 Netty 应用程序没有像我认为的那样快速运行?

感觉就像 channel.write() 将消息添加到队列中,而我们(使用 Netty 的应用程序开发人员)对此队列没有透明度。我不知道队列是Netty队列,OS队列,网卡队列还是什么。无论如何,我正在审查现有应用程序的示例,但我没有看到我正在遵循的任何反模式

感谢您的帮助/见解

4

3 回答 3

2

Netty 默认创建 Runtime.getRuntime().availableProcessors() * 2 个 worker。16 在你的情况下。这意味着您最多可以同时处理 16 个通道,其他通道将等待您释放 ChannelUpstreamHandler.handleUpstream/SimpleChannelHandler.messageReceived 处理程序,因此不要在这些(IO)线程中执行繁重的操作,否则您可能会卡住其他通道。

于 2013-07-02T06:01:25.120 回答
0

如果您使用 System.nanoTime() 等简单的东西,在多线程环境中测量时间是非常困难的。想象一下 1 核系统上的以下情况:

  1. 线程 A 被唤醒并开始处理传入的请求。
  2. 线程 B 被唤醒并开始处理传入的请求。但是由于我们正在使用 1 核机器,这最终需要暂停线程 A。
  3. 线程 B 完成并执行得非常快。
  4. 线程 A 恢复并完成,但花费的时间是线程 B 的两倍。因为您实际测量了完成线程 A + 线程 B 所需的时间。

在这种情况下,如何正确测量有两种方法:

  1. 您可以强制始终只使用一个线程。如果操作系统不干扰
    ,这允许您测量操作的确切性能。因为在上面的示例中,线程 B 也可以在您的程序之外。在这种情况下,一种常见的方法是消除干扰,这将使您估计代码的速度。但是,您可以假设,在一个空闲的多核系统上,会有另一个核心来处理后台任务,因此您的测量通常不会被中断。将此线程设置为高优先级也有帮助。

  2. 您使用插入 JVM 的更复杂的工具来实际测量原子执行及其所花费的时间,这将有效地几乎完全消除外部干扰。一种工具是VisualVM,它已经集成在 NetBeans 中,可作为 Eclipse 的插件使用。

作为一般建议:使用比内核更多的线程并不是一个好主意,除非您知道这些线程会经常被某些操作阻塞。当使用非阻塞 NIO 进行 IO 操作时,情况并非如此,因为没有阻塞。

因此,在您的特殊情况下,您实际上会降低客户端的性能,如上所述,因为在高负载下通信将被搁置多达 50% 的时间。在最坏的情况下,这甚至可能导致客户端超时,因为无法保证线程何时实际恢复(除非您明确请求公平调度)。

于 2013-10-05T11:07:30.673 回答
0

您还没有指定您的 Netty 版本,但它听起来像 Netty 3。Netty 4 现在已经稳定了,我建议您尽快更新到它。您已指定需要超低延迟时间以及数以万计的客户端和服务。这并不能很好地混合。与 OIO 相比,NIO 本质上具有合理的潜在性。然而,这里的陷阱是 OIO 可能无法达到您希望的客户数量。尽管如此,我还是会使用 OIO 事件循环/工厂并看看它是如何进行的。

我自己有一个 TCP 服务器,它在 localhost 上大约需要 30 毫秒来发送和接收和处理一些 TCP 数据包(从客户端打开套接字到服务器关闭它的时间测量)。如果您确实需要如此低的延迟,我建议您因为打开连接所需的 SYN/ACK 垃圾邮件而放弃 TCP,这将占用您 10 毫秒的大部分时间。

于 2013-08-31T04:36:01.417 回答