我正在写一个Netty应用程序。该应用程序在64位八核linux盒上运行
Netty应用程序是一个简单的路由器,它接受请求(传入管道)从请求中读取一些元数据并将数据转发到远程服务(传出管道)。
此远程服务将返回对传出管道的一个或多个响应。 Netty应用程序将响应路由回原始客户端(传入管道)
将有数以千计的客户。将有数以千计的远程服务。
我正在进行一些小规模的测试(10个客户端,10个远程服务),我没有看到10毫秒的低于10.9毫秒的性能,我预计为99.9%。我正在测量客户端和服务器端的延迟。
我正在使用与SPDY类似的完全异步协议。当我们处理FrameDecoder中的第一个字节时,我捕获时间(我只使用System.nanoTime())。我在调用channel.write()之前就停止了计时器。我正在测量从输入管道到输出管道的亚毫秒时间(99.9百分位数),反之亦然。
我还测量了从FrameDecoder中的第一个字节到(上面)message.write()上调用ChannelFutureListener回调的时间。时间是高达数十毫秒(99.9百分位数),但我无法说服自己这是有用的数据。
我最初的想法是我们有一些缓慢的客户。我看了channel.isWritable()并在返回false时记录。在正常情况下,此方法不会返回false
一些事实:
我是否有可以遵循的调试技术来确定我的Netty应用程序运行速度不如我认为的那么快?
感觉channel.write()将消息添加到队列中,而我们(使用Netty的应用程序开发人员)对此队列没有透明性。我不知道队列是Netty队列,OS队列,网卡队列还是什么。无论如何,我正在审查现有应用程序的示例,我没有看到任何反模式我正在关注
感谢您提供任何帮助/见解
答案 0 :(得分:2)
Netty默认创建Runtime.getRuntime()。availableProcessors()* 2个worker。在你的情况下16。这意味着您可以同时处理多达16个通道,其他通道将等到您释放ChannelUpstreamHandler.handleUpstream / SimpleChannelHandler.messageReceived处理程序,因此不要在这些(IO)线程中执行繁重的操作,否则您可能会卡住其他通道。
答案 1 :(得分:0)
您尚未指定Netty版本,但它听起来像Netty 3。 Netty 4现在稳定,我建议您尽快更新。 您已指定您需要超低延迟时间,以及数万个客户端和服务。这并不是很好。与OIO相比,NIO本身具有潜在的合理潜力。然而,这里的缺陷是OIO可能无法达到您希望的客户数量。尽管如此,我还是会使用OIO事件循环/工厂,看看它是怎么回事。
我自己有一台TCP服务器,在localhost上花费大约30ms来发送和接收并处理一些TCP数据包(从客户端打开套接字直到服务器关闭它开始计算)。如果您确实需要如此低的延迟,我建议您切换远离TCP,因为打开连接需要SYN / ACK垃圾邮件,这将占用您10ms的大部分时间。
答案 2 :(得分:0)
如果您使用System.nanoTime()之类的简单内容,则在多线程环境中测量时间非常困难。想象一下1核心系统:
在这种情况下,如何正确测量有两种方法:
您可以强制执行任何时候只使用一个线程 这允许您测量操作的确切性能,如果操作系统不干扰,则。因为在上面的示例中,线程B也可以在您的程序之外。在这种情况下,一种常见的方法是中断干扰,这将为您提供代码速度的估计。然而,您可以假设,在其他空闲的多核上系统,将有另一个核心来处理后台任务,因此您的测量通常不会被中断。将此线程设置为高优先级也有帮助。
您使用更复杂的工具插入JVM,以实际测量原子执行时间和时间,这将有效地消除外部干扰。一个工具是VisualVM,它已经集成在NetBeans中,可以作为Eclipse的插件使用。
作为一般建议:使用多于线程的线程并不是一个好主意,除非您知道这些线程会被某些操作频繁地阻塞。当使用非阻塞NIO进行IO操作时,情况并非如此,因为没有阻塞。
因此,在您的特殊情况下,您实际上会降低客户端的性能,如上所述,因为在高负载下通信将被保留50%的时间。在最坏的情况下,这可能导致客户端甚至遇到超时,因为无法保证线程何时实际恢复(除非您明确请求公平调度)。