传统Java NIO编程存在以下痛点:
而Netty提供了:
```mermaid
graph TB
A[Bootstrap] --> B[EventLoopGroup]
B --> C[EventLoop]
C --> D[Channel]
D --> E[ChannelPipeline]
E --> F[ChannelHandler]
F --> G[ByteBuf]
```
```mermaid
graph LR
subgraph "MainReactor"
A[EventLoopGroup] -->|注册accept事件| B[ServerSocketChannel]
end
subgraph "SubReactor"
C[EventLoopGroup] -->|处理I/O事件| D[SocketChannel1]
C -->|处理I/O事件| E[SocketChannel2]
C -->|处理I/O事件| F[SocketChannelN]
end
B -->|新连接| C
```
1. EventLoopGroup:
2. ChannelPipeline:
3. ByteBuf:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyEchoServer {
private static final int PORT = 8080;
public static void main(String[] args) throws Exception {
// 创建BossGroup和WorkerGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 主线程组
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 工作线程组
try {
// 创建服务器启动引导类
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer () {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加字符串编解码器
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// 添加业务处理器
pipeline.addLast(new EchoServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128) // 服务器端接受连接的队列长度
.childOption(ChannelOption.SO_KEEPALIVE, true); // 保持长连接
// 绑定端口,开始接收连接
ChannelFuture f = b.bind(PORT).sync();
System.out.println("服务器启动,监听端口: " + PORT);
// 等待服务器关闭
f.channel().closeFuture().sync();
} finally {
// 优雅关闭线程组
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
// 自定义业务处理器
private static class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 收到消息直接回显
String request = (String) msg;
System.out.println("收到客户端消息: " + request);
ctx.writeAndFlush("服务器响应: " + request);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 异常处理
cause.printStackTrace();
ctx.close();
}
}
}
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.util.Scanner;
public class NettyEchoClient {
private static final String HOST = "localhost";
private static final int PORT = 8080;
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
// 创建客户端启动引导类
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加字符串编解码器
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// 添加业务处理器
pipeline.addLast(new EchoClientHandler());
}
});
// 连接服务器
ChannelFuture f = b.connect(HOST, PORT).sync();
System.out.println("已连接到服务器: " + HOST + ":" + PORT);
// 从控制台读取输入并发送到服务器
Scanner scanner = new Scanner(System.in);
while (true) {
String line = scanner.nextLine();
if ("exit".equalsIgnoreCase(line)) {
break;
}
f.channel().writeAndFlush(line);
}
// 关闭连接
f.channel().closeFuture().sync();
} finally {
// 优雅关闭线程组
group.shutdownGracefully();
}
}
// 自定义客户端处理器
private static class EchoClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 处理服务器响应
String response = (String) msg;
System.out.println(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 异常处理
cause.printStackTrace();
ctx.close();
}
}
}
Netty的零拷贝机制:
传统方式:文件 -> 内核缓存 -> 用户空间 -> 网络接口
Netty方式:文件 -> 内核缓存 -> 直接传输到网络接口
启用内存池:
// 全局配置
System.setProperty("io.netty.allocator.type", "pooled");
// 或在Bootstrap中配置
b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
public class WebSocketServer {
private static final int PORT = 8080;
private static final String WEBSOCKET_PATH = "/ws";
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer () {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// HTTP 相关处理器
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(65536));
// WebSocket 握手和协议处理器
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
// 自定义业务处理器
pipeline.addLast(new WebSocketServerHandler());
}
});
ChannelFuture f = b.bind(PORT).sync();
System.out.println("WebSocket服务器启动,访问 ws://localhost:" + PORT + WEBSOCKET_PATH);
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import java.time.LocalDateTime;
public class WebSocketServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
// 处理WebSocket文本消息
String request = msg.text();
System.out.println("收到WebSocket消息: " + request);
// 返回当前时间作为响应
String response = "服务器时间: " + LocalDateTime.now().toString();
ctx.writeAndFlush(new TextWebSocketFrame(response));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端加入: " + ctx.channel().id());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端离开: " + ctx.channel().id());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
1. 合理配置线程数:
// 根据CPU核心数配置WorkerGroup线程数
int workerThreads = Runtime.getRuntime().availableProcessors() * 2;
EventLoopGroup workerGroup = new NioEventLoopGroup(workerThreads);
2. 调整TCP参数:
b.childOption(ChannelOption.SO_RCVBUF, 32 * 1024) // 接收缓冲区大小
.childOption(ChannelOption.SO_SNDBUF, 32 * 1024) // 发送缓冲区大小
.childOption(ChannelOption.TCP_NODELAY, true); // 禁用Nagle算法
3. 优化ByteBuf使用:
问题 |
原因 |
解决方案 |
内存泄漏 |
ByteBuf 未正确释放 |
使用try-with-resources或finally块释放 |
消息堆积 |
业务处理慢阻塞 EventLoop |
将耗时操作提交到独立线程池 |
连接拒绝 |
系统文件描述符限制 |
调整系统参数(如ulimit -n) |
高并发下性能下降 |
锁竞争 |
使用无锁数据结构,减少同步块 |
Netty通过封装Java NIO的复杂性,提供了简单易用、高性能、可扩展的网络编程框架。其核心优势包括:
无论是构建高性能的RPC框架、实时通信系统,还是WebSocket服务,Netty都是理想的选择。通过合理配置和优化,Netty能够满足各种高并发场景的需求。