第5部分:Netty性能优化与调优策略

作者:lpfasd123日期:2025/10/21

第5部分:Netty性能优化与调优策略

5.1 参数调优

线程数调优

1. EventLoopGroup线程数配置
1public class ThreadOptimization {
2    public void configureThreads() {
3        // 获取CPU核心数
4        int cpuCores = Runtime.getRuntime().availableProcessors();
5        
6        // Boss线程组:通常1个即可,处理连接建立
7        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
8        
9        // Worker线程组:建议CPU核心数 * 2
10        EventLoopGroup workerGroup = new NioEventLoopGroup(cpuCores * 2);
11        
12        // 业务线程组:处理耗时业务逻辑
13        EventLoopGroup businessGroup = new NioEventLoopGroup(cpuCores * 4);
14    }
15}
16
2. 线程池配置优化
1public class ThreadPoolOptimization {
2    public void configureThreadPool() {
3        // 自定义线程工厂
4        ThreadFactory threadFactory = new ThreadFactory() {
5            private final AtomicInteger counter = new AtomicInteger(0);
6            
7            @Override
8            public Thread newThread(Runnable r) {
9                Thread t = new Thread(r, "Netty-Thread-" + counter.incrementAndGet());
10                t.setDaemon(false); // 非守护线程
11                t.setPriority(Thread.NORM_PRIORITY);
12                return t;
13            }
14        };
15        
16        // 使用自定义线程工厂
17        EventLoopGroup group = new NioEventLoopGroup(8, threadFactory);
18    }
19}
20

缓冲区大小调优

1. ByteBuf分配器配置
1public class BufferOptimization {
2    public void configureBuffer() {
3        ServerBootstrap bootstrap = new ServerBootstrap();
4        
5        // 配置ByteBuf分配器
6        bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
7        bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
8        
9        // 配置接收缓冲区大小
10        bootstrap.option(ChannelOption.SO_RCVBUF, 64 * 1024); // 64KB
11        bootstrap.option(ChannelOption.SO_SNDBUF, 64 * 1024); // 64KB
12        
13        // 配置接收缓冲区低水位线
14        bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, 
15            new AdaptiveRecvByteBufAllocator(64, 1024, 65536));
16    }
17}
18
2. 内存分配策略
1public class MemoryAllocationStrategy {
2    public void configureMemoryAllocation() {
3        // 使用内存池分配器
4        ByteBufAllocator allocator = new PooledByteBufAllocator(
5            true,  // 优先使用直接内存
6            0,     // 页大小,0表示使用默认值
7            0,     // 最大顺序分配,0表示使用默认值
8            8192,  // 小对象阈值
9            0,     // 小对象页大小,0表示使用默认值
10            0,     // 小对象最大顺序分配,0表示使用默认值
11            true   // 使用缓存
12        );
13        
14        // 配置到Bootstrap
15        ServerBootstrap bootstrap = new ServerBootstrap();
16        bootstrap.option(ChannelOption.ALLOCATOR, allocator);
17        bootstrap.childOption(ChannelOption.ALLOCATOR, allocator);
18    }
19}
20

网络参数调优

1. TCP参数优化
1public class TcpOptimization {
2    public void configureTcpOptions() {
3        ServerBootstrap bootstrap = new ServerBootstrap();
4        
5        // 服务端选项
6        bootstrap.option(ChannelOption.SO_BACKLOG, 1024)           // 连接队列大小
7                .option(ChannelOption.SO_REUSEADDR, true)          // 地址重用
8                .option(ChannelOption.SO_KEEPALIVE, true)          // 保持连接
9                .option(ChannelOption.TCP_NODELAY, true)           // 禁用Nagle算法
10                .option(ChannelOption.SO_LINGER, 0)                // 关闭时立即返回
11                .option(ChannelOption.SO_TIMEOUT, 30000)           // 超时时间
12                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000); // 连接超时
13        
14        // 客户端选项
15        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true)
16                .childOption(ChannelOption.TCP_NODELAY, true)
17                .childOption(ChannelOption.SO_RCVBUF, 64 * 1024)
18                .childOption(ChannelOption.SO_SNDBUF, 64 * 1024);
19    }
20}
21
2. Linux系统参数优化
1# 修改系统参数
2echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf
3echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
4echo 'net.ipv4.tcp_max_syn_backlog = 65535' >> /etc/sysctl.conf
5echo 'net.ipv4.tcp_fin_timeout = 30' >> /etc/sysctl.conf
6echo 'net.ipv4.tcp_keepalive_time = 1200' >> /etc/sysctl.conf
7echo 'net.ipv4.tcp_keepalive_probes = 3' >> /etc/sysctl.conf
8echo 'net.ipv4.tcp_keepalive_intvl = 15' >> /etc/sysctl.conf
9
10# 应用配置
11sysctl -p
12

5.2 零拷贝、DirectBuffer、Pooling策略

零拷贝技术

1. 文件传输零拷贝
1public class ZeroCopyExample {
2    public void fileTransfer(ChannelHandlerContext ctx, File file) throws IOException {
3        // 使用FileRegion实现零拷贝文件传输
4        FileRegion region = new DefaultFileRegion(file, 0, file.length());
5        
6        // 发送文件
7        ChannelFuture future = ctx.writeAndFlush(region);
8        
9        // 添加完成监听器
10        future.addListener(new ChannelFutureListener() {
11            @Override
12            public void operationComplete(ChannelFuture future) {
13                if (future.isSuccess()) {
14                    System.out.println("文件传输完成");
15                } else {
16                    System.err.println("文件传输失败: " + future.cause());
17                }
18            }
19        });
20    }
21}
22
2. CompositeByteBuf零拷贝
1public class CompositeByteBufExample {
2    public void compositeBuffers(ChannelHandlerContext ctx) {
3        // 创建组合缓冲区
4        CompositeByteBuf composite = ctx.alloc().compositeBuffer();
5        
6        // 添加多个ByteBuf
7        ByteBuf header = ctx.alloc().buffer(4);
8        header.writeInt(1001);
9        
10        ByteBuf body = ctx.alloc().buffer(1024);
11        body.writeBytes("Hello, Netty!".getBytes());
12        
13        // 组合缓冲区,不进行数据拷贝
14        composite.addComponents(true, header, body);
15        
16        // 发送组合缓冲区
17        ctx.writeAndFlush(composite);
18    }
19}
20

DirectBuffer优化

1. 直接内存配置
1public class DirectBufferOptimization {
2    public void configureDirectBuffer() {
3        // 配置JVM参数
4        // -XX:MaxDirectMemorySize=2g
5        // -XX:+UseDirectMemoryForDirectBuffers
6        
7        // 使用直接内存分配器
8        ByteBufAllocator allocator = new PooledByteBufAllocator(
9            true,  // 优先使用直接内存
10            0,     // 页大小
11            0,     // 最大顺序分配
12            8192,  // 小对象阈值
13            0,     // 小对象页大小
14            0,     // 小对象最大顺序分配
15            true   // 使用缓存
16        );
17        
18        // 配置到Channel
19        ServerBootstrap bootstrap = new ServerBootstrap();
20        bootstrap.option(ChannelOption.ALLOCATOR, allocator);
21        bootstrap.childOption(ChannelOption.ALLOCATOR, allocator);
22    }
23}
24
2. 直接内存监控
1public class DirectMemoryMonitor {
2    public void monitorDirectMemory() {
3        // 获取直接内存使用情况
4        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
5        MemoryUsage directMemory = memoryBean.getNonHeapMemoryUsage();
6        
7        System.out.println("直接内存使用: " + directMemory.getUsed() / 1024 / 1024 + "MB");
8        System.out.println("直接内存最大: " + directMemory.getMax() / 1024 / 1024 + "MB");
9        
10        // 获取Netty内存池统计信息
11        PooledByteBufAllocator allocator = (PooledByteBufAllocator) 
12            PooledByteBufAllocator.DEFAULT;
13        
14        // 打印内存池统计信息
15        System.out.println("内存池统计: " + allocator.dumpStats());
16    }
17}
18

内存池策略

1. 内存池配置
1public class MemoryPoolConfiguration {
2    public void configureMemoryPool() {
3        // 配置内存池参数
4        PooledByteBufAllocator allocator = new PooledByteBufAllocator(
5            true,  // 优先使用直接内存
6            8192,  // 页大小
7            11,    // 最大顺序分配(2^11 = 2048)
8            256,   // 小对象阈值
9            9,     // 小对象页大小(2^9 = 512)
10            7,     // 小对象最大顺序分配(2^7 = 128)
11            true   // 使用缓存
12        );
13        
14        // 配置到Bootstrap
15        ServerBootstrap bootstrap = new ServerBootstrap();
16        bootstrap.option(ChannelOption.ALLOCATOR, allocator);
17        bootstrap.childOption(ChannelOption.ALLOCATOR, allocator);
18    }
19}
20
2. 内存池监控
1public class MemoryPoolMonitor {
2    public void monitorMemoryPool() {
3        PooledByteBufAllocator allocator = (PooledByteBufAllocator) 
4            PooledByteBufAllocator.DEFAULT;
5        
6        // 获取内存池统计信息
7        PooledByteBufAllocatorMetric metric = allocator.metric();
8        
9        System.out.println("直接内存使用: " + metric.usedDirectMemory());
10        System.out.println("堆内存使用: " + metric.usedHeapMemory());
11        System.out.println("直接内存池数量: " + metric.numDirectArenas());
12        System.out.println("堆内存池数量: " + metric.numHeapArenas());
13        
14        // 打印详细统计信息
15        System.out.println(allocator.dumpStats());
16    }
17}
18

5.3 对象复用与Recycler

对象池化

1. 使用Recycler
1public class RecyclerExample {
2    // 定义可回收对象
3    private static final Recycler<RecyclableObject> RECYCLER = new Recycler<RecyclableObject>() {
4        @Override
5        protected RecyclableObject newObject(Handle<RecyclableObject> handle) {
6            return new RecyclableObject(handle);
7        }
8    };
9    
10    public static class RecyclableObject {
11        private final Recycler.Handle<RecyclableObject> handle;
12        private String data;
13        
14        public RecyclableObject(Recycler.Handle<RecyclableObject> handle) {
15            this.handle = handle;
16        }
17        
18        public void setData(String data) {
19            this.data = data;
20        }
21        
22        public String getData() {
23            return data;
24        }
25        
26        public void recycle() {
27            // 重置状态
28            data = null;
29            // 回收到对象池
30            handle.recycle(this);
31        }
32    }
33    
34    public void useRecyclableObject() {
35        // 从对象池获取对象
36        RecyclableObject obj = RECYCLER.get();
37        
38        try {
39            // 使用对象
40            obj.setData("Hello, Recycler!");
41            System.out.println(obj.getData());
42        } finally {
43            // 回收对象
44            obj.recycle();
45        }
46    }
47}
48
2. 自定义对象池
1public class CustomObjectPool<T> {
2    private final Queue<T> pool = new ConcurrentLinkedQueue<>();
3    private final Supplier<T> factory;
4    private final Consumer<T> resetter;
5    
6    public CustomObjectPool(Supplier<T> factory, Consumer<T> resetter) {
7        this.factory = factory;
8        this.resetter = resetter;
9    }
10    
11    public T get() {
12        T obj = pool.poll();
13        if (obj == null) {
14            obj = factory.get();
15        }
16        return obj;
17    }
18    
19    public void returnObject(T obj) {
20        if (obj != null) {
21            resetter.accept(obj);
22            pool.offer(obj);
23        }
24    }
25    
26    public int size() {
27        return pool.size();
28    }
29}
30

对象复用最佳实践

1. Handler对象复用
1@ChannelHandler.Sharable
2public class ReusableHandler extends ChannelInboundHandlerAdapter {
3    // 使用@Sharable注解,表示Handler可以被多个Channel共享
4    // 注意:Handler必须是线程安全的
5    
6    @Override
7    public void channelRead(ChannelHandlerContext ctx, Object msg) {
8        // 处理消息
9        System.out.println("收到消息: " + msg);
10        
11        // 转发给下一个Handler
12        ctx.fireChannelRead(msg);
13    }
14}
15
2. 避免频繁创建对象
1public class ObjectReuseExample {
2    // 重用StringBuilder
3    private final ThreadLocal<StringBuilder> stringBuilder = 
4        ThreadLocal.withInitial(StringBuilder::new);
5    
6    // 重用ByteBuf
7    private final ThreadLocal<ByteBuf> byteBuf = 
8        ThreadLocal.withInitial(() -> Unpooled.buffer(1024));
9    
10    public void processMessage(String message) {
11        // 使用重用的StringBuilder
12        StringBuilder sb = stringBuilder.get();
13        sb.setLength(0); // 清空内容
14        sb.append("处理: ").append(message);
15        
16        // 使用重用的ByteBuf
17        ByteBuf buf = byteBuf.get();
18        buf.clear();
19        buf.writeBytes(sb.toString().getBytes());
20        
21        // 处理数据
22        // ...
23    }
24}
25

5.4 Backpressure与流量控制

背压处理

1. 写入缓冲区监控
1public class BackpressureHandler extends ChannelInboundHandlerAdapter {
2    private static final int HIGH_WATER_MARK = 64 * 1024; // 64KB
3    private static final int LOW_WATER_MARK = 32 * 1024;  // 32KB
4    
5    @Override
6    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
7        if (ctx.channel().isWritable()) {
8            System.out.println("Channel可写,恢复发送");
9            // 恢复发送数据
10        } else {
11            System.out.println("Channel不可写,暂停发送");
12            // 暂停发送数据
13        }
14        
15        super.channelWritabilityChanged(ctx);
16    }
17    
18    @Override
19    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
20        // 检查写入缓冲区大小
21        ChannelOutboundBuffer outboundBuffer = ctx.channel().unsafe().outboundBuffer();
22        if (outboundBuffer != null) {
23            long pendingBytes = outboundBuffer.totalPendingWriteBytes();
24            
25            if (pendingBytes > HIGH_WATER_MARK) {
26                System.out.println("写入缓冲区过大,暂停读取");
27                ctx.channel().config().setAutoRead(false);
28            } else if (pendingBytes < LOW_WATER_MARK) {
29                System.out.println("写入缓冲区正常,恢复读取");
30                ctx.channel().config().setAutoRead(true);
31            }
32        }
33        
34        super.channelRead(ctx, msg);
35    }
36}
37
2. 流量控制实现
1public class FlowControlHandler extends ChannelInboundHandlerAdapter {
2    private final AtomicLong pendingWrites = new AtomicLong(0);
3    private final int maxPendingWrites = 1000;
4    
5    @Override
6    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
7        // 检查待写入数量
8        if (pendingWrites.get() >= maxPendingWrites) {
9            System.out.println("待写入数量过多,丢弃消息");
10            return;
11        }
12        
13        // 增加待写入计数
14        pendingWrites.incrementAndGet();
15        
16        // 异步写入
17        ctx.writeAndFlush(msg).addListener(new ChannelFutureListener() {
18            @Override
19            public void operationComplete(ChannelFuture future) {
20                // 减少待写入计数
21                pendingWrites.decrementAndGet();
22                
23                if (future.isSuccess()) {
24                    System.out.println("写入成功");
25                } else {
26                    System.err.println("写入失败: " + future.cause());
27                }
28            }
29        });
30    }
31}
32

流量控制策略

1. 基于时间的流量控制
1public class TimeBasedFlowControl {
2    private final RateLimiter rateLimiter;
3    
4    public TimeBasedFlowControl(double permitsPerSecond) {
5        this.rateLimiter = RateLimiter.create(permitsPerSecond);
6    }
7    
8    public boolean tryAcquire() {
9        return rateLimiter.tryAcquire();
10    }
11    
12    public void acquire() {
13        rateLimiter.acquire();
14    }
15}
16
2. 基于队列的流量控制
1public class QueueBasedFlowControl {
2    private final BlockingQueue<Object> messageQueue;
3    private final int maxQueueSize;
4    
5    public QueueBasedFlowControl(int maxQueueSize) {
6        this.maxQueueSize = maxQueueSize;
7        this.messageQueue = new LinkedBlockingQueue<>(maxQueueSize);
8    }
9    
10    public boolean offer(Object message) {
11        return messageQueue.offer(message);
12    }
13    
14    public Object poll() {
15        return messageQueue.poll();
16    }
17    
18    public int getQueueSize() {
19        return messageQueue.size();
20    }
21    
22    public boolean isFull() {
23        return messageQueue.size() >= maxQueueSize;
24    }
25}
26

5.5 Linux epoll、SO_BACKLOG、TCP_NODELAY等配置

epoll优化

1. epoll参数配置
1# 修改epoll相关参数
2echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf
3echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
4echo 'net.ipv4.tcp_max_syn_backlog = 65535' >> /etc/sysctl.conf
5echo 'net.ipv4.tcp_fin_timeout = 30' >> /etc/sysctl.conf
6echo 'net.ipv4.tcp_keepalive_time = 1200' >> /etc/sysctl.conf
7echo 'net.ipv4.tcp_keepalive_probes = 3' >> /etc/sysctl.conf
8echo 'net.ipv4.tcp_keepalive_intvl = 15' >> /etc/sysctl.conf
9echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf
10echo 'net.ipv4.tcp_tw_recycle = 1' >> /etc/sysctl.conf
11echo 'net.ipv4.tcp_congestion_control = bbr' >> /etc/sysctl.conf
12
13# 应用配置
14sysctl -p
15
2. 使用epoll传输
1public class EpollOptimization {
2    public void configureEpoll() {
3        // 使用epoll传输(仅Linux)
4        if (Epoll.isAvailable()) {
5            EventLoopGroup bossGroup = new EpollEventLoopGroup(1);
6            EventLoopGroup workerGroup = new EpollEventLoopGroup();
7            
8            ServerBootstrap bootstrap = new ServerBootstrap();
9            bootstrap.group(bossGroup, workerGroup)
10                    .channel(EpollServerSocketChannel.class)
11                    .childHandler(new ChannelInitializer<SocketChannel>() {
12                        @Override
13                        protected void initChannel(SocketChannel ch) {
14                            // 配置Handler
15                        }
16                    });
17        } else {
18            // 回退到NIO
19            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
20            EventLoopGroup workerGroup = new NioEventLoopGroup();
21            
22            ServerBootstrap bootstrap = new ServerBootstrap();
23            bootstrap.group(bossGroup, workerGroup)
24                    .channel(NioServerSocketChannel.class)
25                    .childHandler(new ChannelInitializer<SocketChannel>() {
26                        @Override
27                        protected void initChannel(SocketChannel ch) {
28                            // 配置Handler
29                        }
30                    });
31        }
32    }
33}
34

SO_BACKLOG配置

1. 连接队列配置
1public class BacklogConfiguration {
2    public void configureBacklog() {
3        ServerBootstrap bootstrap = new ServerBootstrap();
4        
5        // 设置连接队列大小
6        bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
7        
8        // 设置其他相关选项
9        bootstrap.option(ChannelOption.SO_REUSEADDR, true)
10                .option(ChannelOption.SO_KEEPALIVE, true)
11                .option(ChannelOption.TCP_NODELAY, true);
12    }
13}
14
2. 连接队列监控
1public class BacklogMonitor {
2    public void monitorBacklog(ServerSocketChannel channel) {
3        try {
4            // 获取连接队列大小
5            int backlog = channel.socket().getReceiveBufferSize();
6            System.out.println("连接队列大小: " + backlog);
7            
8            // 获取待处理连接数
9            int pendingConnections = channel.socket().getSoTimeout();
10            System.out.println("待处理连接数: " + pendingConnections);
11            
12        } catch (SocketException e) {
13            e.printStackTrace();
14        }
15    }
16}
17

TCP_NODELAY配置

1. 禁用Nagle算法
1public class TcpNodelayConfiguration {
2    public void configureTcpNodelay() {
3        ServerBootstrap bootstrap = new ServerBootstrap();
4        
5        // 禁用Nagle算法,减少延迟
6        bootstrap.option(ChannelOption.TCP_NODELAY, true);
7        bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
8        
9        // 设置其他TCP选项
10        bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
11                .option(ChannelOption.SO_REUSEADDR, true)
12                .option(ChannelOption.SO_LINGER, 0);
13    }
14}
15
2. TCP参数调优
1public class TcpParameterTuning {
2    public void tuneTcpParameters() {
3        ServerBootstrap bootstrap = new ServerBootstrap();
4        
5        // TCP参数调优
6        bootstrap.option(ChannelOption.SO_BACKLOG, 1024)           // 连接队列
7                .option(ChannelOption.SO_REUSEADDR, true)          // 地址重用
8                .option(ChannelOption.SO_KEEPALIVE, true)          // 保持连接
9                .option(ChannelOption.TCP_NODELAY, true)           // 禁用Nagle
10                .option(ChannelOption.SO_LINGER, 0)                // 立即关闭
11                .option(ChannelOption.SO_TIMEOUT, 30000)           // 超时时间
12                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000) // 连接超时
13                .option(ChannelOption.SO_RCVBUF, 64 * 1024)        // 接收缓冲区
14                .option(ChannelOption.SO_SNDBUF, 64 * 1024)        // 发送缓冲区
15                .option(ChannelOption.RCVBUF_ALLOCATOR, 
16                    new AdaptiveRecvByteBufAllocator(64, 1024, 65536)); // 自适应缓冲区
17    }
18}
19

5.6 性能监控与排查方法

JMH性能测试

1. 创建JMH测试
1@BenchmarkMode(Mode.Throughput)
2@OutputTimeUnit(TimeUnit.SECONDS)
3@State(Scope.Benchmark)
4public class NettyPerformanceTest {
5    
6    private EventLoopGroup group;
7    private Channel channel;
8    
9    @Setup
10    public void setup() throws Exception {
11        group = new NioEventLoopGroup(1);
12        Bootstrap bootstrap = new Bootstrap();
13        bootstrap.group(group)
14                .channel(NioSocketChannel.class)
15                .handler(new ChannelInitializer<SocketChannel>() {
16                    @Override
17                    protected void initChannel(SocketChannel ch) {
18                        ch.pipeline().addLast(new EchoHandler());
19                    }
20                });
21        
22        channel = bootstrap.connect("localhost", 8080).sync().channel();
23    }
24    
25    @TearDown
26    public void tearDown() throws Exception {
27        channel.close().sync();
28        group.shutdownGracefully();
29    }
30    
31    @Benchmark
32    public void testEcho() throws Exception {
33        String message = "Hello, Netty!";
34        ChannelFuture future = channel.writeAndFlush(message);
35        future.sync();
36    }
37}
38
2. 运行JMH测试
1# 编译测试
2mvn clean compile
3
4# 运行基准测试
5java -jar target/benchmarks.jar NettyPerformanceTest
6
7# 运行特定测试
8java -jar target/benchmarks.jar NettyPerformanceTest -f 1 -wi 5 -i 10
9

JFR性能分析

1. 启用JFR
1# 启动应用时启用JFR
2java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=60s,filename=netty.jfr -jar netty-app.jar
3
4# 或者运行时启用JFR
5jcmd <pid> JFR.start duration=60s filename=netty.jfr
6
2. 分析JFR数据
1public class JfrAnalysis {
2    public void analyzeJfrData() {
3        // 使用JFR API分析数据
4        try {
5            RecordingFile recordingFile = new RecordingFile(Paths.get("netty.jfr"));
6            
7            while (recordingFile.hasMoreEvents()) {
8                RecordedEvent event = recordingFile.readEvent();
9                
10                if (event.getEventType().getName().equals("jdk.GCPhaseParallel")) {
11                    System.out.println("GC事件: " + event.getStartTime());
12                }
13            }
14            
15            recordingFile.close();
16        } catch (IOException e) {
17            e.printStackTrace();
18        }
19    }
20    
21    // 注意:JFR API在Java 11+中有所变化,建议使用JMC工具进行分析
22    public void analyzeWithJMC() {
23        // 推荐使用JMC (Java Mission Control) 工具进行JFR数据分析
24        // 或者使用命令行工具:jmc
25        System.out.println("建议使用JMC工具分析JFR文件");
26    }
27}
28

Netty自带指标

1. 启用Netty指标
1public class NettyMetrics {
2    public void enableMetrics() {
3        // 启用详细的内存分配跟踪
4        System.setProperty("io.netty.leakDetection.level", "ADVANCED");
5        System.setProperty("io.netty.leakDetection.targetRecords", "100");
6        
7        // 启用性能统计
8        System.setProperty("io.netty.allocator.type", "pooled");
9        System.setProperty("io.netty.allocator.maxCachedBufferCapacity", "32k");
10    }
11    
12    public void printMetrics() {
13        // 打印内存分配统计
14        PooledByteBufAllocator allocator = (PooledByteBufAllocator) 
15            PooledByteBufAllocator.DEFAULT;
16        
17        System.out.println("内存分配统计:");
18        System.out.println(allocator.dumpStats());
19        
20        // 打印GC信息
21        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
22        System.out.println("堆内存使用: " + memoryBean.getHeapMemoryUsage());
23        System.out.println("非堆内存使用: " + memoryBean.getNonHeapMemoryUsage());
24    }
25}
26
2. 自定义指标收集
1public class CustomMetrics {
2    private final AtomicLong messagesProcessed = new AtomicLong(0);
3    private final AtomicLong bytesProcessed = new AtomicLong(0);
4    private final AtomicLong errors = new AtomicLong(0);
5    
6    public void recordMessage(int bytes) {
7        messagesProcessed.incrementAndGet();
8        bytesProcessed.addAndGet(bytes);
9    }
10    
11    public void recordError() {
12        errors.incrementAndGet();
13    }
14    
15    public void printMetrics() {
16        System.out.println("处理消息数: " + messagesProcessed.get());
17        System.out.println("处理字节数: " + bytesProcessed.get());
18        System.out.println("错误数: " + errors.get());
19        
20        if (messagesProcessed.get() > 0) {
21            System.out.println("平均消息大小: " + 
22                bytesProcessed.get() / messagesProcessed.get() + " bytes");
23        }
24    }
25}
26

5.7 总结

通过本部分的学习,我们掌握了Netty性能优化与调优的关键策略:

  1. 参数调优:合理配置线程数、缓冲区大小、网络参数
  2. 零拷贝技术:使用DirectBuffer、FileRegion、CompositeByteBuf
  3. 内存管理:配置内存池、对象复用、Recycler
  4. 流量控制:实现背压处理、流量控制策略
  5. 系统优化:配置epoll、SO_BACKLOG、TCP_NODELAY等参数
  6. 性能监控:使用JMH、JFR、Netty指标进行性能分析

这些优化策略能够显著提升Netty应用的性能,在下一部分中,我们将学习使用Netty的常见坑与注意事项。


第5部分:Netty性能优化与调优策略》 是转载文章,点击查看原文


相关推荐


如何将 iPhone 联系人同步到 Mac
Digitally2025/10/20

将 iPhone 联系人同步到 Mac 有许多好处。也许你换了新手机,想保留联系人列表,或者你只是想在使用 Mac 时访问 iPhone 联系人。听起来可能有些麻烦,但实际上同步联系人非常简单。使用苹果产品的一大好处是它们能够无缝协作。你的 iPhone 和 Mac 可以轻松共享数据,包括联系人。在这篇指南中,我们将向你介绍 6 种将 iPhone 联系人同步到 Mac 的简单方法。让我们开始吧! 方法 1:如何使用 iReaShare iPhone Manager 将 iPhone 联系


Java kubernetes
自由的疯2025/10/19

Kubernetes,通常简称为 K8s,是一个开源的容器编排平台,用于自动化容器化应用的部署、管理和扩展。Kubernetes 最初由 Google 的工程师设计开发,并于2014年开源,随后在2015年捐赠给云原生计算基金会(CNCF)。Kubernetes 的设计基于 Google 在内部使用的大规模容器管理系统 Borg 的经验和教训。 Kubernetes 的主要功能 自动化部署和回滚:Kubernetes 可以自动部署应用程序,并在检测到问题时自动回滚到之前的稳定版本。 自我修复:


基于springboot的民谣网站的设计与实现
舒克日记2025/10/17

作者主页:舒克日记 简介:Java领域优质创作者、Java项目、学习资料、技术互助 项目介绍 系统主要分为管理员角色和用户角色 本系统主要功能需求包括歌曲信息管理、歌曲留言管理等模块。其中,密码信息、用户信息、歌曲信息、歌曲留言信息等都是非常重要的数据记录,在系统设计的过程中,需要进行一定的加密处理,确保数据安全性,切实的保护好用户的重要信息。 环境要求 1.运行环境:最好是java jdk1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Ec


Jmeter 线程组、定时器、监听器、后置处理器常用配置说明
wdlnancy2025/10/16

目录 1、线程组 1.1 多线程组关系 1.2、线程组的设置参数含义 ​编辑1.3 如何查看线程数是否全部启动成功? 2、定时器 2.1 常数吞吐量定时器 3、监听器 3.1 查看结果树 3.1.1 多个线程并发时,查看结果树频繁刷屏,如果有失败,无法停止后看到想看的失败信息,如何解决? ​编辑4.1.2 取样器结果里展示的字段都什么含义 3.2 聚合报告 3.2.1:聚合报告如何查看http请求的平均响应时间: 4、后置处理器 4.1 正则表达式提取器


1+X Web前端初级考试html涉及的知识点
期待~明天2025/10/14

HTML 基础概念 HTML(超文本标记语言)是构建网页的核心技术,用于定义网页结构和内容。考试通常涵盖以下基础知识点: HTML 文档基本结构:<!DOCTYPE> 声明、<html>、<head>(包含 <title>、<meta> 等)、<body>。常用标签:段落 <p>、标题 <h1>-<h6>、链接 <a href="">、图像 <img src="" alt="">、列表 <ul>/<ol>/<li>。文本格式化标签:<strong>、<em>、<br>、<hr>。 表单与输


Subagent 自进化:从使用中迭代出最契合场景的agent
是魔丸啊2025/10/13

为什么做这个subagent 我一直有这样一个观点:Prompt不是一次性设计出来的,而是在使用过程中不断迭代和沉淀的。 过去在 Cursor 时代,有许多优秀的规则体系,比如 Devin.CursorRules。它最大的价值在于可以在使用中持续积累经验(Lessons模块),用户可以将其中表现良好的部分提炼进 UserRules 或 ProjectRules,逐渐形成符合自己风格和使用场景的提示词体系。 进入 Claude Code 时代后,平台提供了自动生成 Subagent 的机制,这是非


服务器指标多到“洪水泛滥”?试试InfluxDB?
AAA专业写后端刘哥2025/10/11

你是否也曾面对成山倒海的服务器监控数据,感到头皮发麻?CPU、内存、磁盘IO、网络流量……这些随着时间不断涌来的数据,就像一场永不停歇的洪水。别慌!今天我给你介绍一位专治“数据洪水”的狠角色——InfluxDB,它能把这些“洪水”收拾得服服帖帖,还能让你优雅地“翻旧账”。 一、InfluxDB 是谁?它为啥能“治水”? 简单说,InfluxDB 是一个专为时序数据打造的高性能数据库。 时序数据是个啥? 想象一下,你给你家猫主子装了个智能称重器,它每天早上去称一下,你就会得到这样一系列数据: (


微信小程序开发从零基础到项目发布的全流程实战教程(四)
Terio_my2025/10/10

小程序开发实战课程笔记 第一章:项目初始化与纯净环境搭建 在正式进入开发前,我们需要先创建一个干净的小程序项目环境,以便后续教学不受模板或默认配置干扰。 1.1 创建新项目 操作步骤: 打开 微信开发者工具。点击左上角「+」号或「新建项目」按钮。配置项目信息: 项目名称:demo002项目目录:选择本地存储路径AppID:填写自己的小程序 AppID(可使用测试号)项目类型:选择“小程序”不使用云服务不使用模板 ✅ 提示:务必勾选“不使用模板”,否则会自动引入 pa


Vue3 响应式核心源码全解析:Dep、Link 与 track/trigger 完整执行机制详解
excel2025/10/8

逐行解读 Vue3 的响应式系统是整个框架的灵魂,它让开发者能够在不显式调用更新的情况下自动响应数据变化。本文将带你深入阅读 Vue3 的核心响应式模块源码,重点讲解 Dep、Link、track、trigger 等关键机制,并用通俗的语言串联其工作流程,让你真正理解 Vue3 响应式系统的运行原理。 一、响应式系统的设计思路 Vue3 的响应式系统基于 依赖收集(track) 与 派发更新(trigger) 两大过程: track:在读取响应式数据时记录依赖,建立「谁依赖了谁」的关系; t


JMeter接口测试
鱼鱼说测试2025/10/7

1小时postman接口测试从入门到精通教程 1、创建测试任务 添加线程组,右击测试计划,在快捷菜单单击添加-》线程(用户)-》线程组。设置线程组主要包含三个参数:线程数、Ramp-Up、循环次数。 线程数:设置虚拟用户数。一个虚拟用户占用一个进程或线程。线程数就相当于虚拟用户数。 Ramp-Up:设置的线程数启动时长,单位为秒。如果线程数为100,准备时长为20秒,那么需要20秒启动100个线程,平均每秒启动5个线程。 循环次数:每个线程发送请求的个数。如果线程数为100,

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0