Netty from the trenches
June 2015@jordi9
Netty…?
Netty is an asynchronous event-driven
network application framework
for rapid development of
maintainable high performance
protocol servers & clients.
Netty is an asynchronous event-driven
network application framework
for rapid development of
maintainable high performance
protocol servers & clients.
Netty is a NIO client server
framework which enables quick and easy development
of network applications such
as protocol servers and clients. It
greatly simplifies and streamlines
network programming such as TCP and UDP
socket server.
Netty is a NIO client server
framework which enables quick and easy development
of network applications such
as protocol servers and clients. It
greatly simplifies and streamlines
network programming such as TCP and UDP
socket server.
Netty is a NIO client server
framework which enables quick and easy development
of network applications such
as protocol servers and clients. It
greatly simplifies and streamlines
network programming such as TCP and UDP
socket server.
OH, MY
The Freaking Basics
You’ve heard of:
Async apps
You’ve heard of:
Event driven frameworks
You’ve heard of:
non-blockingoperations
You’ve heard of:Node is cooler
because...
I/O
I/O is everywhere
I/O, approx:
CPU Memory
Device
read()
read()
//wait...
read()
//wait...
keepWorkingBro()
Our programBLOCKS
Resources WASTED
You know what I’m talking
about
WebserverRequest
Database
//wait...
OH, Parallelism!
new Thread();
WebserverRequest
Database
//wait...
WebserverRequest
Database
//wait...
Request
Database
//wait...
WebserverRequest
Database
//wait...
Request
Database
//wait...
Request
Database
//wait...
A mess
We can do better
read()
read()
keepWorkingBro()
read()
keepWorkingBro()
//I’m //done!
You (kinda) did this:
Listeners
You (kinda) did this:
Guava’s EventBus
You (kinda) did this:
Javascript callbacks
Hollywood principle
“Don’t call us,we’ll call you”
Keep working, instead of
waiting
Hi, Async I/O
NIOwith Java
java.nio
since 1.4, 2002java.nio
since 1.7: NIO2more goodies
Hi, Complexity
Netty to the Rescue
Built on top of:
java.nio
Built on top of:
java.net
Dependecy-haters:
Just JDK 1.6+
ONEbig difference
All Netty APIsare async
It’s can be one more tool!
What the hell is Netty for?
Think...
HTTP everywhere
Really BRO?
Maybe, you’re trying to
implement a protocol
Finally, hello Netty!
Netty:
Tool to implement network
applications
Netty:
Both from server and client side
Netty:
NIO everywhere
Why Netty?
Netty has been designed carefully
with the experiences
earned from the implementation of a lot of protocols
such as FTP, SMTP, HTTP, and
various binary and text-based legacy
protocols. As a result, Netty has
succeeded to find a way to achieve
ease of development, performance, stability, and
flexibility without a compromise
Netty has been designed carefully
with the experiences
earned from the implementation of a lot of protocols
such as FTP, SMTP, HTTP, and
various binary and text-based legacy
protocols. As a result, Netty has
succeeded to find a way to achieve
ease of development, performance, stability, and
flexibility without a compromise
Netty has been designed carefully
with the experiences
earned from the implementation of a lot of protocols
such as FTP, SMTP, HTTP, and
various binary and text-based legacy
protocols. As a result, Netty has
succeeded to find a way to achieve...
Ease of development
Performance
Stability
Flexibility
Without a compromise
IT’S TRUE
“Implementing a protocol”
NOT THAT HARD
Most common protocols:
out-of-the-box
Boring Protocols:
HTTP
Boring Protocols:
SSL
Boring Protocols:
UDP
Cooler Protocols:
SPDY
Cooler Protocols:
HTTP/2
Cooler Protocols:
Protobuf
Even Protocols:
Memcache
Not only I/O
Powerful Thread model
But, where’s the downside?
Downers:
Constant API changes*
Downers:
Constant API changes*
*For the best
Downers:
Learning curve...
Downers:
Learning curve...
Buy Netty in Action :P
Downers:
Join the mailing list
Downers:
Join the mailing list
You’ll see how STUPID you are
Downers:
Join the mailing list
But you’ll learn ALOT ;)
Netty,The Code
Daytime Protocol
TheServer
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
}
The Hand e
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
// Handler = Business Logic
}
The Hand e
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
// ChannelHandler: handles operations // for that Channel, duh
}
The Hand e
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
// Inbound handler: incoming traffic, // dispatch events to next handler// If we have inbound...
}
The Hand e
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
// Outbound handler: same, but the // other direction. Yeah, there’s some// flow between Handlers (eg: Pipeline)
}
The Hand e
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
// Inbound + Outbound...
}
The Hand e
class SimpleDaytimeHandler extends ChannelInboundHandlerAdapter {
// Inbound + Outbound..
// 5.0: DEPRECATED!// [NOTE: Insert a grumpy cat here]
}
The Hand e
Hand e me hod
@Overridepublic void channelRead( ChannelHandlerContext ctx, Object msg) {
// Will trigger when we receive // some data
}
Hand e me hod
@Overridepublic void channelActive( ChannelHandlerContext ctx, Object msg) {
// Will a Channel is opened, this // method will be called
}
Hand e me hod
@Overridepublic void channelActive(ChannelHandlerContext ctx, Object msg) {
String date = DATE_TIME.print(new DateTime()); // Get the date
}
Hand e wo
@Overridepublic void channelActive(ChannelHandlerContext ctx, Object msg) {
String date = DATE_TIME.print(new DateTime()); ctx.writeAndFlush(ByteBufUtil.encodeString( ctx.alloc(), CharBuffer.wrap(date), CharsetUtil.US_ASCII));
}
Hand e wo
It’s clear, right? :D
Network standard way of
working?byte[]
You said this was fun?
MeetByteBuf
ByteBufUtil
@Overridepublic void channelActive(ChannelHandlerContext ctx, Object msg) {
String date = DATE_TIME.print(new DateTime()); ctx.writeAndFlush(ByteBufUtil.encodeString( ctx.alloc(), CharBuffer.wrap(date), CharsetUtil.US_ASCII)); // We need to encode the String
}
Hand e wo
@Overridepublic void channelActive(ChannelHandlerContext ctx, Object msg) {
String date = DATE_TIME.print(new DateTime()); ctx.writeAndFlush(ByteBufUtil.encodeString( ctx.alloc(), CharBuffer.wrap(date), CharsetUtil.US_ASCII)); // We allocate some space // +Netty: Keeps internal pools
}
Hand e wo
@Overridepublic void channelActive(ChannelHandlerContext ctx, Object msg) {
String date = DATE_TIME.print(new DateTime()); ctx.writeAndFlush(ByteBufUtil.encodeString( ctx.alloc(), CharBuffer.wrap(date), CharsetUtil.US_ASCII)); // Write the message // Request to actually flush the data // back to the Channel
}
Hand e wo
We have our Handler in place
Let’s Bootstrap the server
Ma n asspublic class DaytimeServer { void run() throws Exception { // fun stuff }
public static void main(String[] args) throws Exception { DaytimeServer daytimeServer = new DaytimeServer(); daytimeServer.run(); }
}
java -jar daytimeserver-fat.jar
un()EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();
E en LoopG oup
Netty’s way to handle threads
E en LoopG oupEventLoopGroup contains someEventLoops
E en LoopEventLoop
handles manyChannels
About to die BRO?
E en LoopG oup
E en Loop
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
E en Loop
E en LoopG oup
E en Loop
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
hannehanne
E en Loop
This immutable assignment is
the key
un()EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();
un()EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();
// Boss group accepts connections// Work group handles the work
Se e Boo s apServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(8080) .option(ChannelOption.SO_BACKLOG, 100)
Se e Boo s apServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(8080) .option(ChannelOption.SO_BACKLOG, 100)
// We assign both event loops
Se e Boo s apServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(8080) .option(ChannelOption.SO_BACKLOG, 100)
// We use a ServerSocketChannel// to accept TCP/IP connections// as the RFC says
Se e Boo s apServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(8080) .option(ChannelOption.SO_BACKLOG, 100)
// Simply bind the local address
Se e Boo s apServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .localAddress(8080) .option(ChannelOption.SO_BACKLOG, 100)
// Set some Socket options... why not?// Just remember: This is not handled// by Netty or the JVM, it’s the OS
We’re almost there!
hanne P pe neb.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new SimpleDaytimeHandler()); }});
hanne P pe neb.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new SimpleDaytimeHandler()); }});
// ChannelPipeline to define your// application workflow
hanne P pe neb.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new SimpleDaytimeHandler()); }});
// Append our handlers// ProTip: use LoggingHandler to// understand Netty
hanne P pe neb.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new SimpleDaytimeHandler()); }});
// Finally, we add our handler
RUN!b.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new SimpleDaytimeHandler()); }});
ChannelFuture f = b.bind().sync();f.channel().closeFuture().sync();
// It works!
.I.A.Futures
ByteBuf APICodecs
TransportsZero-file-copy
We can also create
client code
Real lifeInsights
We’re using Netty for Real-Time Bidding
Boo s ap
Tons o op ons
Don’t be afraid of “low-level”
Ta HTTP
Explore what’s inside Netty
Integrate things you love. In my
case: GUICE
Gu e@InjectDaytimeService(Provider<DaytimeServer> daytimeProvider) {}
b.childHandler(() → { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(daytimeProvider.get());});
// Inject a Provider<T> and get // instances
But… is Netty FAST?
2ms*
* Without network latency
2ms*
Yah but… what volume are you talking about?
+10k QPS
1 node*+3k QPS
*Fou 2.79GHz In e Pen um Xeon P o esso s, 7.5GB RAM
But, is this ALOT or not?
Parse example
http://blog.parse.com/learn/how-we-moved-our-api-from-ruby-to-go-and-saved-our-sanity/
(From Ruby to Go) A year and a half in, at the end of 2012, we had 200 API servers running on m1.xlarge instance types with 24 unicorn workers per instance. This was to serve 3000 requests per second for 60,000 mobile apps
We have 16 nodes! 4x Netty nodes10x Kafka, DNS, the usual suspects…
I KNOW IT’S NOT FAIR,
but it’s good stuff for your ego BRO
Lovely ecosystemlike Ratpack,
or users, with vert.x or akka
It will change the way you program some of your apps
Hello, Async problems
Forget about max onn params
One more thing...
(It’s 5:00 in the morning and I had
to say it)
(did you notice the “Apple
background”?)
JUST KIDDINGIt doesn’ really
matter!
Have fun!
THANKS
ProTip: We’re hiring
Q & A
#HiddenTrovitTrack@jordi9