##JVM参数
高并发使用UseParallelOldGC, -XX:+UseParallelOldGC -XX:-UseAdaptiveSizePolicy
大吞吐量使用UseConcMarkSweepGC, -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=65
-Xms不能太小, -Xms4g -Xmx5g
##开发中的一些心得
进行并发开发时,多线程不是最好的选择,我把多线程换成了Disruptor框架http://lmax-exchange.github.io/disruptor/
在Disruptor中,尽量减少IO操作,每个Consumer是单线程的,不要让线程Block;为提高吞吐量,任何线程的Block都是不可接收的;能缓存的数据一定要缓存,Redis/Memcache都是不错的选择;如果追求更高的性能,一些数据直接缓存进进程内,去Redis里面读数据都是一种延迟。
批量执行的速度会远远超过一个一个的执行,比如从kafka读取数据,或往kafka写数据,比如执行结果需要保存到数据库,如果数据量超过并且数据访问比较频繁,则可以考虑批量保存。将结果保存到MQ中,再将结果异步保存到MySQL或Redis,可以大大提高性能。
单线程比想象中的要快很多,前提是没有Block动作
##使用Netty过程中的一些总结
- Linux下,为追求性能,可以使用epoll,即Native Transports。EpollEventLoopGroup替换NioEventLoopGroup,EpollEventLoop替换NioEventLoop,EpollServerSocketChannel替换NioServerSocketChannel,EpollSocketChannel替换NioSocketChannel
EventLoopGroup bossGroup = new EpollEventLoopGroup(this.bossThreds);
EventLoopGroup workerGroup = new EpollEventLoopGroup(this.workerThreads);
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(EpollServerSocketChannel.class).childHandler(serverInitializer);
b.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
b.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
b.option(ChannelOption.TCP_NODELAY, true);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.option(ChannelOption.SO_REUSEADDR, true);
b.option(ChannelOption.SO_RCVBUF, 1048576);
b.option(ChannelOption.SO_SNDBUF, 1048576);
b.option(ChannelOption.SO_BACKLOG, 5000);
b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
b.bind("0.0.0.0", port).sync().channel().closeFuture().sync();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
// e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
开启PooledByteBufAllocator
修改TCP参数TCP_NO_DELAY,SO_SNDBUF,SO_RCVBUF
为获得更大吞吐量,在ChannelHandler的channelRead中,不要Block线程,执行越快越好
在EventLoop中慎用java.util.concurrent中的一些Block性质的操作;数据库操作相当于Block操作,应谨慎使用
使用ctx.writeAndFlush(msg); 而不是ctx.channel().writeAndFlush(msg);
如果业务无状态,可以在ChannelHandler上使用@ChannelHandler.Sharable,可以减少GC
12@ChannelHandler.Sharablepublic class StatelessHandler extends ChannelInboundHandlerAdapter {在encode时,减少内存copy,尽量使用系统的ByteBuf
public class EncodeActsOnByteArray extends MessageToByteEncoder<YourMessage> {
public EncodeActsOnByteArray() { super(false); }
@Override
public encode(ChannelHandlerContext ctx, YourMessage msg, ByteBuf out) {
byte[] array = out.array();
int offset = out.arrayOffset() + out.writerIndex();
out.writeIndex(out.writerIndex() + encode(msg, array, offset));
}
private int encode(YourMessage msg, byte[] array, int offset, int len) { ... }
}