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 从 百毫秒降到毫秒级
  • 资源 :线程数 百分之一 ,内存 十分之一
相关推荐
IT_陈寒10 小时前
Java中equals方法比了个寂寞?原来这才是正确的重写姿势
前端·人工智能·后端
Thneonl10 小时前
Celery 生产踩坑:1000 任务积压与 acks_late 双重执行
后端·python
卷福同学10 小时前
第一次当面试官有感
后端·面试
苏三说技术10 小时前
为什么越来越多人用 OnlyOffice?
后端
知守观10 小时前
@Transactional 事务失效排查,try-catch 吞异常导致回滚失败(附源码分析)
后端·spring
羑悻10 小时前
Codex + Seed-2.1-pro 实测:多模态理解 + Coding Agent 能扛住真实仓库吗?
后端
颜进强10 小时前
14 · NestJS ExecutionContext 执行上下文:守卫、拦截器、过滤器拿到的"同一个 context",为什么能力不一样?
前端·后端·ai编程
小小张说故事10 小时前
Python 多线程为什么跑不快?asyncio 入门指南:异步并发从零上手
后端·python
明月_清风10 小时前
数据进入平台后怎么处理?一文搞懂 ETL
大数据·后端·数据分析
初学AI的小高10 小时前
LangGraph断点恢复与幂等执行实战
后端·架构