1、如何模拟百万连接
sever开启8000-8100端口
client开启1025-65535
统计连接数
package com.xiaofeiyang; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * @author: yangchun * @description: * @date: Created in 2020-04-24 12:48 */ public class ConnectionCountHandler extends ChannelInboundHandlerAdapter { private AtomicInteger count = new AtomicInteger(); public ConnectionCountHandler(){ Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(()->{ System.out.println("connections:"+count.get()); },0,2, TimeUnit.SECONDS); } @Override public void channelActive(ChannelHandlerContext context){ count.getAndIncrement(); } @Override public void channelInactive(ChannelHandlerContext context){ count.getAndDecrement(); } }
2、突破局部文件句柄限制
ulimit -n 默认一个jvm可以打开1024个文件句柄,还需要打开class文件句柄
/etc/security/limits.conf
* hard nofile 1000000
* soft nofile 1000000
3、突破全局文件句柄限制
cat /proc/sys/fs/file-max
echo 20000 > /proc/sys/fs/file-max
要修改
/etc/sysctl.conf
fs.file-max=1000000
4、统计应用级别qps
package com.imooc.netty.ch12.thread; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @ChannelHandler.Sharable public class ClientBusinessHandler extends SimpleChannelInboundHandler<ByteBuf> { public static final ChannelHandler INSTANCE = new ClientBusinessHandler(); private static AtomicLong beginTime = new AtomicLong(0); private static AtomicLong totalResponseTime = new AtomicLong(0); private static AtomicInteger totalRequest = new AtomicInteger(0); public static final Thread THREAD = new Thread(() -> { try { while (true) { long duration = System.currentTimeMillis() - beginTime.get(); if (duration != 0) { System.out.println("qps: " + 1000 * totalRequest.get() / duration + ", " + "avg response time: " + ((float) totalResponseTime.get()) / totalRequest.get()); Thread.sleep(2000); } } } catch (InterruptedException ignored) { } }); @Override public void channelActive(ChannelHandlerContext ctx) { ctx.executor().scheduleAtFixedRate(() -> { ByteBuf byteBuf = ctx.alloc().ioBuffer(); byteBuf.writeLong(System.currentTimeMillis()); ctx.channel().writeAndFlush(byteBuf); }, 0, 1, TimeUnit.SECONDS); } @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { totalResponseTime.addAndGet(System.currentTimeMillis() - msg.readLong()); totalRequest.incrementAndGet(); if (beginTime.compareAndSet(0, System.currentTimeMillis())) { THREAD.start(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // ignore } }
package com.imooc.netty.ch12.thread; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import java.util.concurrent.ThreadLocalRandom; @ChannelHandler.Sharable public class ServerBusinessHandler extends SimpleChannelInboundHandler<ByteBuf> { public static final ChannelHandler INSTANCE = new ServerBusinessHandler(); @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { ByteBuf data = Unpooled.directBuffer(); data.writeBytes(msg); Object result = getResult(data); ctx.channel().writeAndFlush(result); } protected Object getResult(ByteBuf data) { // 90.0% == 1ms // 95.0% == 10ms 1000 50 > 10ms // 99.0% == 100ms 1000 10 > 100ms // 99.9% == 1000ms1000 1 > 1000ms int level = ThreadLocalRandom.current().nextInt(1, 1000); int time; if (level <= 900) { time = 1; } else if (level <= 950) { time = 10; } else if (level <= 990) { time = 100; } else { time = 1000; } try { Thread.sleep(time); } catch (InterruptedException e) { } return data; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // ignore } }
提升性能可以开始采用线程池来提升
package com.imooc.netty.ch12.thread; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @ChannelHandler.Sharable public class ServerBusinessThreadPoolHandler extends ServerBusinessHandler { public static final ChannelHandler INSTANCE = new ServerBusinessThreadPoolHandler(); private static ExecutorService threadPool = Executors.newFixedThreadPool(1000); @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { ByteBuf data = Unpooled.directBuffer(); data.writeBytes(msg); threadPool.submit(() -> { Object result = getResult(data); ctx.channel().writeAndFlush(result); }); } }
handle放入一个线程池中操作
package com.imooc.netty.ch12.thread; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.FixedLengthFrameDecoder; import static com.imooc.netty.ch12.thread.Constant.PORT; public class Server { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup businessGroup = new NioEventLoopGroup(1000); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup); bootstrap.channel(NioServerSocketChannel.class); bootstrap.childOption(ChannelOption.SO_REUSEADDR, true); bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast(new FixedLengthFrameDecoder(Long.BYTES)); ch.pipeline().addLast(businessGroup, ServerBusinessHandler.INSTANCE); // ch.pipeline().addLast(ServerBusinessThreadPoolHandler.INSTANCE); } }); bootstrap.bind(PORT).addListener((ChannelFutureListener) future -> System.out.println("bind success in port: " + PORT)); } }