Heap Buffers
The most common bytebuf pattern is to store data in the JVM's heap space. This pattern is called the support array
(backing array), which provides fast allocation and deallocation without pooling.
Direct buffers
The contents of the direct buffer will reside outside the regular garbage-collected heap. Direct buffers are an ideal choice for network data transfer. Because if your data is contained in a buffer allocated on the heap, in fact, before sending it through a socket, the JVM will internally copy your buffer into a direct buffer.
The main disadvantage of direct buffers is that they are more expensive to allocate and release relative to heap-based buffers. Therefore, this type of memory is only more efficient in sending and receiving packets of memory, not suitable in the Netty application layer.
Composite buffers
Let's consider a message that consists of two parts-the head and the body-that will be transmitted over the HTTP protocol. These two parts are generated by different modules of the application and will be assembled when the message is sent. The application can choose to reuse the same message body for multiple messages. When this happens, a new header is created for each message.
Because we don't want to reassign both buffers for each message, using COMPOSITEBYTEBUF is a
The perfect choice.
It is important to note that Netty uses COMPOSITEBYTEBUF to optimize socket I/O operations and to eliminate as much as possible
Penalties for performance and memory usage resulting from the implementation of the JDK's buffers. This optimization takes place in the core code of Netty and is therefore not exposed, but you should know the impact it brings.
Bytebuf allocation method Pooling of allocations Pooledbytebufallocator is the default way of Bytebufallocator
Can be passed through the Channel (each can have a different bytebufallocator instance) or bound to
Channelhandler's channelhandlercontext gets a reference to Bytebufallocator.
Bytebuf instances are pooled to improve performance and minimize memory fragmentation. This implementation uses an efficient method called Jemalloc that has been used by a large number of modern operating systems to allocate memory.
This is the default mode in Netty.
Non-pooled allocation unpooledbytebufallocator
There may be cases where you fail to get a reference to Bytebufallocator. For this scenario, Netty provides a simple tool class called unpooled, which provides a static helper method to create an BYTEBUF instance that is not pooled.
Performance testing with HTTP Netty HTTP code
HttpServer.java
PackageHttp.server;ImportOrg.apache.commons.logging.Log;Importorg.apache.commons.logging.LogFactory;ImportIo.netty.bootstrap.ServerBootstrap;Importio.netty.channel.ChannelFuture;ImportIo.netty.channel.ChannelInitializer;Importio.netty.channel.ChannelOption;ImportIo.netty.channel.EventLoopGroup;ImportIo.netty.channel.nio.NioEventLoopGroup;ImportIo.netty.channel.socket.SocketChannel;ImportIo.netty.channel.socket.nio.NioServerSocketChannel;ImportIo.netty.handler.codec.http.HttpRequestDecoder;ImportIo.netty.handler.codec.http.HttpResponseEncoder; Public classHttpserver {Private StaticLog log = Logfactory.getlog (httpserver.class); Public voidStartintPortthrowsException {eventloopgroup bossgroup=NewNioeventloopgroup (); Eventloopgroup Workergroup=NewNioeventloopgroup (); Try{Serverbootstrap b=NewServerbootstrap (); B.group (Bossgroup, Workergroup). Channel (Nioserversocketchannel.class). Childhandler (NewChannelinitializer<socketchannel>() {@Override Public voidInitchannel (Socketchannel ch)throwsException {//server side sends HttpResponse, so use Httpresponseencoder to encodeCh.pipeline (). AddLast (NewHttpresponseencoder ()); //Server side received HttpRequest, so use Httprequestdecoder to decodeCh.pipeline (). AddLast (NewHttprequestdecoder ()); Ch.pipeline (). AddLast (NewHttpserverinboundhandler ()); }}). option (Channeloption.so_backlog,128). Childoption (Channeloption.so_keepalive,true); Channelfuture F=B.bind (port). sync (); F.channel (). Closefuture (). sync (); } finally{workergroup.shutdowngracefully (); Bossgroup.shutdowngracefully (); } } Public Static voidMain (string[] args)throwsException {httpserver server=NewHttpserver (); Log.info ("Http Server listening on 5656 ..."); Server.start (5656); }}
Httpserverinboundhandler.java
PackageHttp.server;Import StaticIo.netty.handler.codec.http.HttpResponseStatus.OK;ImportOrg.apache.commons.logging.Log;Importorg.apache.commons.logging.LogFactory;ImportIo.netty.buffer.ByteBuf;Importio.netty.buffer.Unpooled;ImportIo.netty.channel.ChannelHandlerContext;ImportIo.netty.channel.ChannelInboundHandlerAdapter;ImportIo.netty.handler.codec.http.DefaultFullHttpResponse;ImportIo.netty.handler.codec.http.FullHttpResponse;ImportIo.netty.handler.codec.http.HttpHeaderNames;Importio.netty.handler.codec.http.HttpVersion; Public classHttpserverinboundhandlerextendsChannelinboundhandleradapter {Private StaticLog log = Logfactory.getlog (Httpserverinboundhandler.class); //private HttpRequest request; //static Bytebuf buf = Unpooled.wrappedbuffer ("Hello World". GetBytes ()); byte[] bs = "Hello World". GetBytes (); @Override Public voidChannelread (Channelhandlercontext ctx, Object msg)throwsException {//if (msg instanceof HttpRequest) {//request = (HttpRequest) msg; // //String uri = Request.uri (); // //System.out.println ("uri:" + uri); // } //if (msg instanceof httpcontent) {//httpcontent content = (httpcontent) msg; //bytebuf buf = Content.content (); // //System.out.println (buf.tostring (io.netty.util.CharsetUtil.UTF_8)); //buf.release (); //String res = "Hello World"; //bytebuf buf = Unpooled.wrappedbuffer (BS); //bytebuf buf = Unpooled.directbuffer (); //bytebuf buf = Unpooled.buffer (); //bytebuf buf = Ctx.alloc (). Heapbuffer ();//pooling of heap memory//bytebuf buf = Ctx.alloc (). Directbuffer ();//pooling of direct memory//bytebuf buf = Unpooled.buffer ();//Non-pooled heap memoryBytebuf buf = Unpooled.directbuffer ();//Non-pooled heap memoryBuf.writebytes (BS); Fullhttpresponse Response=Newdefaultfullhttpresponse (httpversion.http_1_1, OK, buf); //response.headers (). Set (Httpheadernames.content_type, "Text/plain");response.headers (). Set (Httpheadernames.content_length, Response.content (). Readablebytes ()); /** IF (httpheaders.iskeepalive (Request)) {response.headers (). Set (CONNECTION, values.keep_alive);} */Ctx.write (response); //Ctx.flush (); // }} @Override Public voidChannelreadcomplete (Channelhandlercontext ctx)throwsException {ctx.flush (); } @Override Public voidexceptioncaught (Channelhandlercontext ctx, throwable cause) {Log.error (Cause.getmessage ()); Ctx.close (); }}
Pooled heap Memory Ctx.alloc (). Heapbuffer ()
Running 20s test @ http://127.0.0.1:5656/ 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 3.76ms 9.31ms 180.34ms 92.96% Req/Sec 138.20k 43.16k 210.22k 66.50% 10957832 requests in 20.09s, 522.51MB readRequests/sec: 545332.08Transfer/sec: 26.00MBreal 0m20.104suser 0m10.441ssys 0m44.703s
Pooling of Direct Memory Ctx.alloc (). Directbuffer ()
Running 20s test @ http://127.0.0.1:5656/ 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.47ms 9.99ms 149.70ms 91.76% Req/Sec 138.51k 41.31k 209.94k 63.38% 10981466 requests in 20.09s, 523.64MB readRequests/sec: 546684.37Transfer/sec: 26.07MBreal 0m20.098suser 0m10.890ssys 0m45.081s
Non-pooled heap memory Unpooled.buffer ()
Running 20s test @ http://127.0.0.1:5656/ 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.00ms 8.72ms 150.05ms 91.52% Req/Sec 138.84k 42.05k 209.72k 63.81% 11017442 requests in 20.09s, 525.35MB readRequests/sec: 548379.99Transfer/sec: 26.15MBreal 0m20.101suser 0m10.639ssys 0m45.191s
Non-pooled Direct Memory Unpooled.directbuffer ()
Running 20s test @ http://127.0.0.1:5656/ 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 3.64ms 9.36ms 156.79ms 92.71% Req/Sec 124.55k 33.90k 191.90k 71.61% 9890536 requests in 20.07s, 471.62MB readRequests/sec: 492854.62Transfer/sec: 23.50MBreal 0m20.076suser 0m9.774ssys 0m41.801s
"Netty this thing." Bytebuf usage patterns