Nicholas Jiang created HBASE-21973: -------------------------------------- Summary: NettyRpcServer performance improve based on Netty Key: HBASE-21973 URL: https://issues.apache.org/jira/browse/HBASE-21973 Project: HBase Issue Type: Improvement Reporter: Nicholas Jiang
In NettyRpcServer#NettyRpcServer constructor method, we have the following: {code:java} ServerBootstrap bootstrap = new ServerBootstrap().group(eventLoopGroup).channel(channelClass) .childOption(ChannelOption.TCP_NODELAY, tcpNoDelay) .childOption(ChannelOption.SO_KEEPALIVE, tcpKeepAlive) .childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); FixedLengthFrameDecoder preambleDecoder = new FixedLengthFrameDecoder(6); preambleDecoder.setSingleDecode(true); pipeline.addLast("preambleDecoder", preambleDecoder); pipeline.addLast("preambleHandler", createNettyRpcServerPreambleHandler()); pipeline.addLast("frameDecoder", new NettyRpcFrameDecoder(maxRequestSize)); pipeline.addLast("decoder", new NettyRpcServerRequestDecoder(allChannels, metrics)); pipeline.addLast("encoder", new NettyRpcServerResponseEncoder(metrics)); } }); try { serverChannel = bootstrap.bind(this.bindAddress).sync().channel(); LOG.info("Bind to {}", serverChannel.localAddress()); } catch (InterruptedException e) { throw new InterruptedIOException(e.getMessage()); } {code} In build ServerBootstrap, we would configure ServerSocketChannel options and SocketChannel child options to improve rpc perfermance.These options and child options are as follows: {code:java} .option(ChannelOption.SO_BACKLOG, transportConfig.getBacklog()) .option(ChannelOption.SO_REUSEADDR, transportConfig.isReuseAddr()) .option(ChannelOption.RCVBUF_ALLOCATOR, NettyHelper.getRecvByteBufAllocator()) .option(ChannelOption.ALLOCATOR, NettyHelper.getByteBufAllocator()) .childOption(ChannelOption.SO_KEEPALIVE, transportConfig.isKeepAlive()) .childOption(ChannelOption.TCP_NODELAY, transportConfig.isTcpNoDelay()) .childOption(ChannelOption.SO_RCVBUF, 8192 * 128) .childOption(ChannelOption.SO_SNDBUF, 8192 * 128) .childOption(ChannelOption.ALLOCATOR, NettyHelper.getByteBufAllocator()) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark( transportConfig.getBufferMin(), transportConfig.getBufferMax())) {code} What's more,ChannelPipeline includes NettyRpcFrameDecoder,this decorder extends ByteToMessageDecoder.ChannelPipeline is as follows: {code:java} .childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); FixedLengthFrameDecoder preambleDecoder = new FixedLengthFrameDecoder(6); preambleDecoder.setSingleDecode(true); pipeline.addLast("preambleDecoder", preambleDecoder); pipeline.addLast("preambleHandler", createNettyRpcServerPreambleHandler()); pipeline.addLast("frameDecoder", new NettyRpcFrameDecoder(maxRequestSize)); pipeline.addLast("decoder", new NettyRpcServerRequestDecoder(allChannels, metrics)); pipeline.addLast("encoder", new NettyRpcServerResponseEncoder(metrics)); } }); {code} Netty provides a convenient decoding tool class ByteToMessageDecoder , this class has accumulate bulk unpacking ability, can read bytes from the socket as much as possible, then synchronously call the decode method, decode the business object, and form a List. Finally, the traversal traverses the List and submits it to ChannelPipeline for processing. Here we can make a small change, submit the submitted content from a single command to the entire List, which can reduce the number of pipeline execution and increase throughput. This mode has no advantage in low-concurrency scenarios, and has a significant performance boost in boost throughput in high-concurrency scenarios. Will provide an patch and some perf-comparison for this. -- This message was sent by Atlassian JIRA (v7.6.3#76005)