Madan Jampani

Netty performance improvements

1 package org.onlab.netty; 1 package org.onlab.netty;
2 2
3 import io.netty.buffer.ByteBuf; 3 import io.netty.buffer.ByteBuf;
4 +import io.netty.channel.ChannelHandler.Sharable;
4 import io.netty.channel.ChannelHandlerContext; 5 import io.netty.channel.ChannelHandlerContext;
5 import io.netty.handler.codec.MessageToByteEncoder; 6 import io.netty.handler.codec.MessageToByteEncoder;
6 7
7 /** 8 /**
8 * Encode InternalMessage out into a byte buffer. 9 * Encode InternalMessage out into a byte buffer.
9 */ 10 */
11 +@Sharable
10 public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { 12 public class MessageEncoder extends MessageToByteEncoder<InternalMessage> {
11 13
12 // onosiscool in ascii 14 // onosiscool in ascii
......
...@@ -11,6 +11,7 @@ import io.netty.bootstrap.ServerBootstrap; ...@@ -11,6 +11,7 @@ import io.netty.bootstrap.ServerBootstrap;
11 import io.netty.buffer.PooledByteBufAllocator; 11 import io.netty.buffer.PooledByteBufAllocator;
12 import io.netty.channel.Channel; 12 import io.netty.channel.Channel;
13 import io.netty.channel.ChannelFuture; 13 import io.netty.channel.ChannelFuture;
14 +import io.netty.channel.ChannelHandler;
14 import io.netty.channel.ChannelHandlerContext; 15 import io.netty.channel.ChannelHandlerContext;
15 import io.netty.channel.ChannelInitializer; 16 import io.netty.channel.ChannelInitializer;
16 import io.netty.channel.ChannelOption; 17 import io.netty.channel.ChannelOption;
...@@ -37,14 +38,19 @@ public class NettyMessagingService implements MessagingService { ...@@ -37,14 +38,19 @@ public class NettyMessagingService implements MessagingService {
37 38
38 private final Logger log = LoggerFactory.getLogger(getClass()); 39 private final Logger log = LoggerFactory.getLogger(getClass());
39 40
40 - private GenericKeyedObjectPool<Endpoint, Channel> channels;
41 -
42 private final int port; 41 private final int port;
42 + private final Endpoint localEp;
43 private final EventLoopGroup bossGroup = new NioEventLoopGroup(); 43 private final EventLoopGroup bossGroup = new NioEventLoopGroup();
44 private final EventLoopGroup workerGroup = new NioEventLoopGroup(); 44 private final EventLoopGroup workerGroup = new NioEventLoopGroup();
45 private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>(); 45 private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>();
46 - private Cache<Long, AsyncResponse<?>> responseFutures; 46 + private final Cache<Long, AsyncResponse<?>> responseFutures = CacheBuilder.newBuilder()
47 - private final Endpoint localEp; 47 + .maximumSize(100000)
48 + .weakValues()
49 + // TODO: Once the entry expires, notify blocking threads (if any).
50 + .expireAfterWrite(10, TimeUnit.MINUTES)
51 + .build();
52 + private final GenericKeyedObjectPool<Endpoint, Channel> channels
53 + = new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory());
48 54
49 protected Serializer serializer; 55 protected Serializer serializer;
50 56
...@@ -65,15 +71,8 @@ public class NettyMessagingService implements MessagingService { ...@@ -65,15 +71,8 @@ public class NettyMessagingService implements MessagingService {
65 } 71 }
66 72
67 public void activate() throws Exception { 73 public void activate() throws Exception {
68 - channels = new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory());
69 channels.setTestOnBorrow(true); 74 channels.setTestOnBorrow(true);
70 channels.setTestOnReturn(true); 75 channels.setTestOnReturn(true);
71 - responseFutures = CacheBuilder.newBuilder()
72 - .maximumSize(100000)
73 - .weakValues()
74 - // TODO: Once the entry expires, notify blocking threads (if any).
75 - .expireAfterWrite(10, TimeUnit.MINUTES)
76 - .build();
77 startAcceptingConnections(); 76 startAcceptingConnections();
78 } 77 }
79 78
...@@ -145,7 +144,8 @@ public class NettyMessagingService implements MessagingService { ...@@ -145,7 +144,8 @@ public class NettyMessagingService implements MessagingService {
145 private void startAcceptingConnections() throws InterruptedException { 144 private void startAcceptingConnections() throws InterruptedException {
146 ServerBootstrap b = new ServerBootstrap(); 145 ServerBootstrap b = new ServerBootstrap();
147 b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); 146 b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
148 - b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024); 147 + b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
148 + // TODO: Need JVM options to configure PooledByteBufAllocator.
149 b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); 149 b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
150 b.group(bossGroup, workerGroup) 150 b.group(bossGroup, workerGroup)
151 .channel(NioServerSocketChannel.class) 151 .channel(NioServerSocketChannel.class)
...@@ -172,19 +172,18 @@ public class NettyMessagingService implements MessagingService { ...@@ -172,19 +172,18 @@ public class NettyMessagingService implements MessagingService {
172 172
173 @Override 173 @Override
174 public Channel makeObject(Endpoint ep) throws Exception { 174 public Channel makeObject(Endpoint ep) throws Exception {
175 - Bootstrap b = new Bootstrap(); 175 + Bootstrap bootstrap = new Bootstrap();
176 - b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); 176 + bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
177 - b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); 177 + bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
178 - b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024); 178 + bootstrap.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
179 - b.group(workerGroup); 179 + bootstrap.group(workerGroup);
180 // TODO: Make this faster: 180 // TODO: Make this faster:
181 // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 181 // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0
182 - b.channel(NioSocketChannel.class); 182 + bootstrap.channel(NioSocketChannel.class);
183 - b.option(ChannelOption.SO_KEEPALIVE, true); 183 + bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
184 - b.handler(new OnosCommunicationChannelInitializer()); 184 + bootstrap.handler(new OnosCommunicationChannelInitializer());
185 -
186 // Start the client. 185 // Start the client.
187 - ChannelFuture f = b.connect(ep.host(), ep.port()).sync(); 186 + ChannelFuture f = bootstrap.connect(ep.host(), ep.port()).sync();
188 return f.channel(); 187 return f.channel();
189 } 188 }
190 189
...@@ -201,12 +200,15 @@ public class NettyMessagingService implements MessagingService { ...@@ -201,12 +200,15 @@ public class NettyMessagingService implements MessagingService {
201 200
202 private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { 201 private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> {
203 202
203 + private final ChannelHandler dispatcher = new InboundMessageDispatcher();
204 + private final ChannelHandler encoder = new MessageEncoder(serializer);
205 +
204 @Override 206 @Override
205 protected void initChannel(SocketChannel channel) throws Exception { 207 protected void initChannel(SocketChannel channel) throws Exception {
206 channel.pipeline() 208 channel.pipeline()
207 - .addLast("encoder", new MessageEncoder(serializer)) 209 + .addLast("encoder", encoder)
208 .addLast("decoder", new MessageDecoder(NettyMessagingService.this, serializer)) 210 .addLast("decoder", new MessageDecoder(NettyMessagingService.this, serializer))
209 - .addLast("handler", new InboundMessageDispatcher()); 211 + .addLast("handler", dispatcher);
210 } 212 }
211 } 213 }
212 214
...@@ -222,10 +224,11 @@ public class NettyMessagingService implements MessagingService { ...@@ -222,10 +224,11 @@ public class NettyMessagingService implements MessagingService {
222 224
223 @Override 225 @Override
224 public void run() { 226 public void run() {
225 - channel.writeAndFlush(message); 227 + channel.writeAndFlush(message, channel.voidPromise());
226 } 228 }
227 } 229 }
228 230
231 + @ChannelHandler.Sharable
229 private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> { 232 private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> {
230 233
231 @Override 234 @Override
...@@ -248,7 +251,6 @@ public class NettyMessagingService implements MessagingService { ...@@ -248,7 +251,6 @@ public class NettyMessagingService implements MessagingService {
248 handler.handle(message); 251 handler.handle(message);
249 } 252 }
250 253
251 -
252 @Override 254 @Override
253 public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { 255 public void exceptionCaught(ChannelHandlerContext context, Throwable cause) {
254 context.close(); 256 context.close();
......