【问题标题】:nonblocking-io vs blocking-io on raw data throughput原始数据吞吐量上的非阻塞 io 与阻塞 io
【发布时间】:2012-02-07 17:31:27
【问题描述】:

apache HTTPComponent document中有一句话:

与流行的看法相反,NIO 在原始数据吞吐量方面的性能明显低于阻塞 I/O。”

这是真的吗?有人可以更详细地解释这一点吗?

请求/响应处理需要解耦

【问题讨论】:

    标签: java performance io nio


    【解决方案1】:

    第一种说法只有在并发请求数比较少(而不是几万)的情况下才成立。这一切都是关于使用多个线程(阻塞)而不是一个或几个线程(非阻塞)。假设您要编写一个仅从远程服务器下载文件的应用程序。如果您的应用程序一次只需要下载一个文件,您只需要一个线程。但是如果你有一个运行数千个 HTTP 请求的爬虫,那么你需要有数千个线程(或者使用有限数量的线程 + NIO 代替)。对于如此多的线程,问题在于上下文切换,这会显着降低您的应用程序的速度(因此对于这个数量的并发请求,NIO 更好)。

    但是让我们回到你的问题。为什么 NIO 在原始数据吞吐量方面会变慢?原因是 NIO 驱动的应用程序使用的 CPU 时间量。对于阻塞模型中的这种情况,您的代码只做一件事 - 等待数据(它在循环中执行 recv() 操作)。在 NIO 应用程序中,逻辑要复杂得多:在循环中,代码使用选择器选择一组键(这涉及 Linux 上的 epoll_wait 系统调用,Oracle JVM),然后遍历该组,为每个键,然后从通道中读取数据(操作系统中的 read() 操作)。在标准阻塞模型中,您所做的就是执行 recv() 系统函数。总而言之:在这种情况下,NIO 驱动的应用程序使用更多的 CPU 时间并生成更多的模式切换操作,因为系统调用数量更多(所谓模式切换是指从用户模式到内核模式的切换)。因此下载文件所需的时间会更长。

    【讨论】:

    • 但是,如果几乎所有线程都被阻塞等待 I/O,那么就没有上下文切换正在进行,我想……那么上下文切换成本真的是使用线程处理许多并发请求的问题吗?
    • @DobesVandermeer 操作系统调度程序无论如何都必须在空闲线程上花费资源,以控制它们是否需要被唤醒。所以是的,空闲线程也是有代价的。
    【解决方案2】:

    当您可以处理请求时,应该使用非阻塞 IO,将其分派到其他执行上下文(不同的线程、RPC 调用到另一台服务器、其他异步机制)并释放 Web 服务器的线程以处理更多传入的请求。当响应的处理完成时,将调用响应处理线程,并将响应发送给客户端。

    我建议阅读netty documentation 以更好地理解这个概念。

    至于更高的吞吐量:当您的服务器发送/接收大量数据时,所有这些上下文切换以及线程之间的数据传递都会真正影响整体性能。可以这样想:您收到一个大请求(带有大文件的 PUT 请求)。您需要做的就是将其保存到磁盘,然后返回 OK。开始在线程之间折腾它可能会导致更多的内存复制操作,以防你刚刚将它扔到同一个线程中的磁盘。并且以异步方式处理此操作不会提高性能:尽管您可以将请求处理线程释放回 Web 服务器的线程池并让它处理其他请求,但您的主要性能瓶颈是您的磁盘 IO,在这种情况下 - 尝试同时保存更多文件,只会让事情变慢。

    我希望我已经足够清楚了。如果您需要更多解释,请随时在 cmets 中提出更多问题。

    【讨论】:

    • 所以我可以得出结论,非阻塞 io 提供的最大优势是容量,即每个服务器可以处理的同时请求的数量,而不是每个请求处理的总吞吐量或速度?如果我在集群中添加更多服务器,如果我的应用程序架构具有良好的水平可扩展性,我是否可以使用阻塞 io 以更好的速度和吞吐量获得相同的结果?
    • 大概 - 是的。当然,你所有的服务器都使用一些共享资源(数据库、共享文件系统、一些后端服务),你会受到它的速度的限制,但如果你没有类似的东西,添加更多的服务器会让你变得更好大多数情况下的吞吐量。此外,异步编程更难,更容易出错。
    • 另一方面,向集群中添加更多的服务器是扩展的,并且可能无法帮助您处理几乎不需要服务器时间的大量小请求(例如使用非阻塞 IO 对 DOS 攻击更具弹性——它以正确的错误代码响应攻击者,并为有效请求执行所需的操作)
    • 得到它。感谢您的详细回答。
    猜你喜欢
    • 1970-01-01
    • 2010-11-17
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    • 2014-04-01
    • 1970-01-01
    相关资源
    最近更新 更多