【发布时间】:2012-02-07 17:31:27
【问题描述】:
在apache HTTPComponent document中有一句话:
与流行的看法相反,NIO 在原始数据吞吐量方面的性能明显低于阻塞 I/O。”
这是真的吗?有人可以更详细地解释这一点吗?
请求/响应处理需要解耦
【问题讨论】:
标签: java performance io nio
在apache HTTPComponent document中有一句话:
与流行的看法相反,NIO 在原始数据吞吐量方面的性能明显低于阻塞 I/O。”
这是真的吗?有人可以更详细地解释这一点吗?
请求/响应处理需要解耦
【问题讨论】:
标签: java performance io nio
第一种说法只有在并发请求数比较少(而不是几万)的情况下才成立。这一切都是关于使用多个线程(阻塞)而不是一个或几个线程(非阻塞)。假设您要编写一个仅从远程服务器下载文件的应用程序。如果您的应用程序一次只需要下载一个文件,您只需要一个线程。但是如果你有一个运行数千个 HTTP 请求的爬虫,那么你需要有数千个线程(或者使用有限数量的线程 + NIO 代替)。对于如此多的线程,问题在于上下文切换,这会显着降低您的应用程序的速度(因此对于这个数量的并发请求,NIO 更好)。
但是让我们回到你的问题。为什么 NIO 在原始数据吞吐量方面会变慢?原因是 NIO 驱动的应用程序使用的 CPU 时间量。对于阻塞模型中的这种情况,您的代码只做一件事 - 等待数据(它在循环中执行 recv() 操作)。在 NIO 应用程序中,逻辑要复杂得多:在循环中,代码使用选择器选择一组键(这涉及 Linux 上的 epoll_wait 系统调用,Oracle JVM),然后遍历该组,为每个键,然后从通道中读取数据(操作系统中的 read() 操作)。在标准阻塞模型中,您所做的就是执行 recv() 系统函数。总而言之:在这种情况下,NIO 驱动的应用程序使用更多的 CPU 时间并生成更多的模式切换操作,因为系统调用数量更多(所谓模式切换是指从用户模式到内核模式的切换)。因此下载文件所需的时间会更长。
【讨论】:
当您可以处理请求时,应该使用非阻塞 IO,将其分派到其他执行上下文(不同的线程、RPC 调用到另一台服务器、其他异步机制)并释放 Web 服务器的线程以处理更多传入的请求。当响应的处理完成时,将调用响应处理线程,并将响应发送给客户端。
我建议阅读netty documentation 以更好地理解这个概念。
至于更高的吞吐量:当您的服务器发送/接收大量数据时,所有这些上下文切换以及线程之间的数据传递都会真正影响整体性能。可以这样想:您收到一个大请求(带有大文件的 PUT 请求)。您需要做的就是将其保存到磁盘,然后返回 OK。开始在线程之间折腾它可能会导致更多的内存复制操作,以防你刚刚将它扔到同一个线程中的磁盘。并且以异步方式处理此操作不会提高性能:尽管您可以将请求处理线程释放回 Web 服务器的线程池并让它处理其他请求,但您的主要性能瓶颈是您的磁盘 IO,在这种情况下 - 尝试同时保存更多文件,只会让事情变慢。
我希望我已经足够清楚了。如果您需要更多解释,请随时在 cmets 中提出更多问题。
【讨论】: