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 从 百毫秒降到毫秒级
  • 资源 :线程数 百分之一 ,内存 十分之一
相关推荐
程序员鱼皮几秒前
前特斯拉 AI 总监:AI 编程最大的谎言,是 “提效”
前端·后端·ai·程序员·开发
好好研究1 小时前
SpringBoot使用外置Tomcat
spring boot·后端·tomcat
索荣荣1 小时前
Spring Boot 实现DOCX转PDF(基于docx4j的轻量级开源方案)
spring boot·后端·pdf
mit6.8241 小时前
[todo]10个常见的后端框架
后端
没有bug.的程序员1 小时前
Spring Boot 与 Sleuth:分布式链路追踪的集成、原理与线上故障排查实战
java·spring boot·分布式·后端·分布式链路追踪·sleuth·线上故障排查
爱敲代码的憨仔1 小时前
Spring-AOP
java·后端·spring
短剑重铸之日1 小时前
《设计模式》第四篇:观察者模式
java·后端·观察者模式·设计模式
Hx_Ma161 小时前
SpringBoot注册格式化器
java·spring boot·后端
乔江seven2 小时前
【python轻量级Web框架 Flask 】1 Flask 初识
开发语言·后端·python·flask
知识即是力量ol2 小时前
一次完整的 Spring Security JWT 鉴权链路解析
java·后端·spring·鉴权·springsecurity