netty5/src/docbook/en-US/module/architecture.xml
2011-10-10 17:42:15 +09:00

347 lines
15 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!--
* Copyright 2009 Red Hat, Inc.
*
* Red Hat licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd" [
<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
%CustomDTD;
]>
<chapter id="architecture">
<title>Architectural Overview</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/architecture.png" format="PNG" scale="50" scalefit="1" align="center" />
</imageobject>
<textobject>
<phrase>The Architecture Diagram of Netty</phrase>
</textobject>
</mediaobject>
<para>
In this chapter, we will examine what core functionalities are provided in
Netty and how they constitute a complete network application development
stack on top of the core. Please keep this diagram in mind as you read this
chapter.
</para>
<section>
<title>Rich Buffer Data Structure</title>
<para>
Netty uses its own buffer API instead of NIO <classname>ByteBuffer</classname>
to represent a sequence of bytes. This approach has significant advantages
over using <classname>ByteBuffer</classname>. Netty's new buffer type,
&ChannelBuffer; has been designed from the ground up to address the problems
of <classname>ByteBuffer</classname> and to meet the daily needs of
network application developers. To list a few cool features:
<itemizedlist>
<listitem>
<para>
You can define your own buffer type if necessary.
</para>
</listitem>
<listitem>
<para>
Transparent zero copy is achieved by a built-in composite buffer type.
</para>
</listitem>
<listitem>
<para>
A dynamic buffer type is provided out-of-the-box, whose capacity is
expanded on demand, just like <classname>StringBuffer</classname>.
</para>
</listitem>
<listitem>
<para>
There's no need to call <methodname>flip()</methodname> anymore.
</para>
</listitem>
<listitem>
<para>
It is often faster than <classname>ByteBuffer</classname>.
</para>
</listitem>
</itemizedlist>
</para>
<para>
For more information, please refer to the
<ulink url="&API;buffer/package-summary.html#package_description"><literal>org.jboss.netty.buffer</literal> package description</ulink>.
</para>
</section>
<section>
<title>Universal Asynchronous I/O API</title>
<para>
Traditional I/O APIs in Java provide different types and methods for
different transport types. For example,
<classname>java.net.Socket</classname> and
<classname>java.net.DatagramSocket</classname> do not have any common
super type and therefore they have very different ways to perform socket
I/O.
</para>
<para>
This mismatch makes porting a network application from one transport to
another tedious and difficult. The lack of portability between
transports becomes a problem when you need to support additional
transports, as this often entails rewriting the network layer of the
application. Logically, many protocols can run on more than one
transport such as TCP/IP, UDP/IP, SCTP, and serial port communication.
</para>
<para>
To make matters worse, Java's New I/O (NIO) API introduced
incompatibilities with the old blocking I/O (OIO) API and will continue
to do so in the next release, NIO.2 (AIO). Because all these APIs are
different from each other in design and performance characteristics, you
are often forced to determine which API your application will depend on
before you even begin the implementation phase.
</para>
<para>
For instance, you might want to start with OIO because the number of
clients you are going to serve will be very small and writing a socket
server using OIO is much easier than using NIO. However, you are going
to be in trouble when your business grows exponentially and your server
needs to serve tens of thousands of clients simultaneously. You could
start with NIO, but doing so may hinder rapid development by greatly
increasing development time due to the complexity of the NIO Selector
API.
</para>
<para>
Netty has a universal asynchronous I/O interface called a &Channel;, which
abstracts away all operations required for point-to-point communication.
That is, once you wrote your application on one Netty transport, your
application can run on other Netty transports. Netty provides a number
of essential transports via one universal API:
<itemizedlist>
<listitem>
<para>
NIO-based TCP/IP transport
(See <literal>org.jboss.netty.channel.socket.nio</literal>),
</para>
</listitem>
<listitem>
<para>
OIO-based TCP/IP transport
(See <literal>org.jboss.netty.channel.socket.oio</literal>),
</para>
</listitem>
<listitem>
<para>OIO-based UDP/IP transport, and</para>
</listitem>
<listitem>
<para>
Local transport (See <literal>org.jboss.netty.channel.local</literal>).
</para>
</listitem>
</itemizedlist>
Switching from one transport to another usually takes just a couple
lines of changes such as choosing a different &ChannelFactory;
implementation.
</para>
<para>
Also, you are even able to take advantage of new transports which aren't
yet written (such as serial port communication transport), again
by replacing just a couple lines of constructor calls. Moreover, you can
write your own transport by extending the core API.
</para>
</section>
<section>
<title>Event Model based on the Interceptor Chain Pattern</title>
<para>
A well-defined and extensible event model is a must for an event-driven
application. Netty has a well-defined event model focused on I/O. It
also allows you to implement your own event type without breaking the
existing code because each event type is distinguished from another by
a strict type hierarchy. This is another differentiator against other
frameworks. Many NIO frameworks have no or a very limited notion of an
event model. If they offer extension at all, they often break the
existing code when you try to add custom event types
</para>
<para>
A &ChannelEvent; is handled by a list of &ChannelHandler;s in a
&ChannelPipeline;. The pipeline implements an advanced form of the
<ulink url="http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html">Intercepting Filter</ulink>
pattern to give a user full control over how an event is handled and how
the handlers in the pipeline interact with each other. For example,
you can define what to do when data is read from a socket:
</para>
<programlisting>public class MyReadHandler implements &SimpleChannelHandler; {
public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; evt) {
Object message = evt.getMessage();
// Do something with the received message.
...
// And forward the event to the next handler.
ctx.sendUpstream(evt);
}
}</programlisting>
<para>
You can also define what to do when a handler receives a write request:
</para>
<programlisting>public class MyWriteHandler implements &SimpleChannelHandler; {
public void writeRequested(&ChannelHandlerContext; ctx, &MessageEvent; evt) {
Object message = evt.getMessage();
// Do something with the message to be written.
...
// And forward the event to the next handler.
ctx.sendDownstream(evt);
}
}</programlisting>
<para>
For more information on the event model, please refer to the
API documentation of &ChannelEvent; and &ChannelPipeline;.
</para>
</section>
<section>
<title>Advanced Components for More Rapid Development</title>
<para>
On top of the core components mentioned above, that already enable the
implementation of all types of network applications, Netty provides a set
of advanced features to accelerate the page of development even more.
</para>
<section>
<title>Codec framework</title>
<para>
As demonstrated in <xref linkend="start.pojo"/>, it is always a good
idea to separate a protocol codec from business logic. However, there
are some complications when implementing this idea from scratch. You
have to deal with the fragmentation of messages. Some protocols are
multi-layered (i.e. built on top of other lower level protocols). Some
are too complicated to be implemented in a single state machine.
</para>
<para>
Consequently, a good network application framework should provide an
extensible, reusable, unit-testable, and multi-layered codec framework
that generates maintainable user codecs.
</para>
<para>
Netty provides a number of basic and advanced codecs to address most
issues you will encounter when you write a protocol codec regardless
if it is simple or not, binary or text - simply whatever.
</para>
</section>
<section>
<title>SSL / TLS Support</title>
<para>
Unlike old blocking I/O, it is a non-trivial task to support SSL in NIO.
You can't simply wrap a stream to encrypt or decrypt data but you have
to use <classname>javax.net.ssl.SSLEngine</classname>.
<classname>SSLEngine</classname> is a state machine which is as complex
as SSL itself. You have to manage all possible states such as cipher
suite and encryption key negotiation (or re-negotiation), certificate
exchange, and validation. Moreover, <classname>SSLEngine</classname> is
not even completely thread-safe, as one would expect.
</para>
<para>
In Netty, &SslHandler; takes care of all the gory details and pitfalls
of <classname>SSLEngine</classname>. All you need to do is to configure
the &SslHandler; and insert it into your &ChannelPipeline;. It also
allows you to implement advanced features like
<ulink url="http://en.wikipedia.org/wiki/Starttls">StartTLS</ulink>
very easily.
</para>
</section>
<section>
<title>HTTP Implementation</title>
<para>
HTTP is definitely the most popular protocol in the Internet. There are
already a number of HTTP implementations such as a Servlet container.
Then why does Netty have HTTP on top of its core?
</para>
<para>
Netty's HTTP support is very different from the existing HTTP libraries.
It gives you complete control over how HTTP messages are exchanged at a
low level. Because it is basically the combination of an HTTP codec and
HTTP message classes, there is no restriction such as an enforced thread
model. That is, you can write your own HTTP client or server that works
exactly the way you want. You have full control over everything that's
in the HTTP specification, including the thread model, connection life
cycle, and chunked encoding.
</para>
<para>
Thanks to its highly customizable nature, you can write a very efficient
HTTP server such as:
<itemizedlist>
<listitem>
<para>
Chat server that requires persistent connections and server push
technology (e.g. <ulink url="http://en.wikipedia.org/wiki/Comet_%28programming%29">Comet</ulink>
and <ulink url="http://en.wikipedia.org/wiki/WebSockets">WebSockets</ulink>)
</para>
</listitem>
<listitem>
<para>
Media streaming server that needs to keep the connection open
until the whole media is streamed (e.g. 2 hours of video)
</para>
</listitem>
<listitem>
<para>
File server that allows the uploading of large files without
memory pressure (e.g. uploading 1GB per request)
</para>
</listitem>
<listitem>
<para>
Scalable mash-up client that connects to tens of thousands of 3rd
party web services asynchronously
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Google Protocol Buffer Integration</title>
<para>
<ulink url="http://code.google.com/apis/protocolbuffers/docs/overview.html">Google Protocol Buffers</ulink>
are an ideal solution for the rapid implementation of a highly efficient
binary protocols that evolve over time. With &ProtobufEncoder; and
&ProtobufDecoder;, you can turn the message classes generated by the
Google Protocol Buffers Compiler (protoc) into Netty codec. Please take
a look into the
<ulink url="&XRef;example/localtime/package-summary.html">'LocalTime' example</ulink>
that shows how easily you can create a high-performing binary protocol
client and server from the
<ulink url="http://anonsvn.jboss.org/repos/netty/trunk/src/main/java/org/jboss/netty/example/localtime/LocalTimeProtocol.proto">sample protocol definition</ulink>.
</para>
</section>
</section>
<section>
<title>Summary</title>
<para>
In this chapter, we reviewed the overall architecture of Netty from the
feature standpoint. Netty has a simple, yet powerful architecture.
It is composed of three components - buffer, channel, and event model -
and all advanced features are built on top of the three core components.
Once you understood how these three work together, it should not be
difficult to understand the more advanced features which were covered
briefly in this chapter.
</para>
<para>
You might still have unanswered questions about what the overall
architecture looks like exactly and how each of the features work
together. If so, it is a good idea to
<ulink url="&Community;">talk to us</ulink> to improve this guide.
</para>
</section>
</chapter>