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 从 百毫秒降到毫秒级
  • 资源 :线程数 百分之一 ,内存 十分之一
相关推荐
晓得迷路了27 分钟前
栗子前端技术周刊第 150 期 - Stack Overflow 开发者调查结果、TanStack Start 1.0...
javascript·css·后端
vx_Biye_Design31 分钟前
PHP中医养生馆预约系统60841-计算机课程设计、毕业设计
vue.js·spring boot·后端·mysql·php·课程设计·express
IT_陈寒31 分钟前
Vite性能优化完全指南
前端·人工智能·后端
黄鹂鸟科技1 小时前
软件定制开发设计要点:从需求梳理、原型确认到敏捷交付与持续维护
后端·物联网·系统架构
Profile排查笔记1 小时前
指纹浏览器 GitHub 项目怎么选?先看仓库交付的是工具、内核还是管理器
前端·人工智能·后端·自动化
高频因子挖掘机1 小时前
多股票行情为什么容易对不齐?用 Pandas MultiIndex 管理标的、日期与缺失值
后端·github·api
高频因子挖掘机1 小时前
Python 量化数据接口设计实战:用数据契约解决字段混乱与回测不一致
后端·github·api
猿究院_夏燊9 小时前
Spring Bean 生命周期
java·后端·spring
CCblandy11 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
我是人✓11 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端