NIO和传统 BIO的性能较量

NIO和阻塞式IO的性能较量

基于 JDK 17 + Netty 4.1 的 实战压测报告 阻塞 I/O = 传统 BIO,NIO = 非阻塞 I/O(Netty 封装)


目录

  1. 测试背景
  2. 环境配置
  3. 测试用例设计
  4. 压测结果
  5. 结果分析
  6. 调优建议
  7. 总结

测试背景

  • 阻塞 I/O(BIO)ServerSocket.accept() + 一连接一线程
  • 非阻塞 I/O(NIO)Selector + 单线程管理万连接

疑问QPS、延迟、内存、CPU 到底差多少? 答案 :实测 10 倍差距 起步。


环境配置

表格

复制

项目
CPU Intel i7-12700H 14 核
内存 32 GB DDR4
OS Ubuntu 22.04
JDK 17.0.8
压测工具 wrk 4.1.0
网络 本地回环(排除网卡干扰)

测试用例设计

1. 阻塞 I/O(BIO)版本

java 复制代码
// 每连接新建线程
while (true) {
    Socket socket = serverSocket.accept();
    new Thread(() -> handle(socket)).start();
}
private static void handle(Socket socket) {
    try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
         PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
        String line = in.readLine();
        out.println("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nHello");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2. 非阻塞 I/O(NIO)版本

scss 复制代码
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup(0);
ServerBootstrap b = new ServerBootstrap()
        .group(boss, worker)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) {
                ch.pipeline().addLast(new HttpServerCodec());
                ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpRequest>() {
                    @Override
                    protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) {
                        FullHttpResponse resp = new DefaultFullHttpResponse(
                                HttpVersion.HTTP_1_1,
                                HttpResponseStatus.OK,
                                Unpooled.wrappedBuffer("Hello".getBytes()));
                        ctx.writeAndFlush(resp);
                    }
                });
            }
        });
b.bind(8080).sync();

压测结果

命令

arduino 复制代码
wrk -t12 -c1000 -d30s http://localhost:8080/

表格

复制

指标 BIO (1 线程/连接) NIO (Netty) 倍数
QPS 12,000 158,000 ×13
P99 延迟 85 ms 6.5 ms ×13
线程数 1000+ 16 ×62
内存峰值 2.4 GB 180 MB ×13
CPU 利用率 420% 380% 相近

结果分析

  1. 线程模型

    • BIO:一连接一线程,上下文切换爆炸。
    • NIO:事件驱动,单线程管理万连接,零切换。
  2. 内存

    • BIO:每条线程 1 MB 栈 + 缓冲区。
    • NIO:池化 DirectBuffer,复用内存。
  3. 延迟

    • BIO:阻塞 read() 导致排队。
    • NIO:非阻塞 + 零拷贝,P99 降低一个数量级。

调优建议

场景 参数
Linux 高并发 EpollEventLoopGroup
线程数 EventLoopGroup(0) 自动 CPU*2
内存 -XX:MaxDirectMemorySize=2G
TCP SO_BACKLOG=1024, TCP_NODELAY=true

总结

  • QPS :NIO 是 BIO 的 10+ 倍
  • 延迟 :P99 从 百毫秒降到毫秒级
  • 资源 :线程数 百分之一 ,内存 十分之一
相关推荐
Oneslide4 小时前
Ubuntu 26.04 完整安装 Fcitx5 中文拼音输入法指南(适配默认Wayland)
后端
huangdong_5 小时前
电商平台图片URL原图转换技术深度解析:从缩略图到高清原图的完整方案
java·后端·spring
掘金码甲哥5 小时前
3min手搓一个帮助文档站,很合理吧!
后端
ServBay9 小时前
别再用初级写法写Rust了,8个写法你值得拥有
后端·rust
jingling55510 小时前
go | 环境安装和快速入门
开发语言·后端·golang
Darren24510 小时前
流程步骤模板 - @StepStatus 注解方案
后端
小闹54910 小时前
Claude Code 给自己接了一部飞书,从此不用守在工位等它
后端·claude
浮游本尊10 小时前
Java学习第41天 - 复杂查询、多表关联、索引优化与慢 SQL 调优
后端
llz_11210 小时前
web-第五次课后作业
前端·后端·http