38 Compare Java Standard Nio Libraries, Do You Know How Netty Achieves Higher Performance

Netty 是一个基于 Java NIO 的网络应用框架,它提供了一些高级的抽象和组件,使得网络编程变得更加简单和高效。

Netty 之所以能实现更高性能,主要有以下几个方面的优势:

1. 异步非阻塞:Netty 使用了非阻塞的事件驱动模型,这意味着一个线程可以同时处理多个客户端连接,而不需要为每个连接创建一个线程。这种异步非阻塞的方式大大减少了线程的开销,并提高了系统的扩展性和吞吐量。

2. 高度可定制:Netty 提供了丰富的可定制性,开发者可以根据自己的需求灵活地定制网络通信的各个组件,包括编码解码、事件处理、流量控制等。这种高度可定制性使得开发者能够更好地适应不同的业务场景,并进行性能优化。

3. 零拷贝:Netty 通过使用直接内存缓冲区和零拷贝技术,避免了数据在用户态和内核态之间的多次复制。这种优化减少了系统的 CPU 消耗和内存占用,提升了数据传输的效率。

4. 底层优化:Netty 对底层的 NIO 组件进行了优化,通过避免一些常见的性能陷阱,减少了系统的上下文切换和内存拷贝等开销。此外,Netty 还使用了一些高级特性,如零拷贝传输,SSL/TLS 加速等,进一步提高了性能和安全性。

总的来说,Netty 在设计上充分考虑了高性能和可扩展性的需求,通过优化底层实现、提供可定制的组件和使用高级特性,使得它比 Java 标准 NIO 类库更适合构建高性能的网络应用。

38 Compare Java standard NIO libraries, do you know how Netty achieves higher performance #

From a performance perspective, Netty has made many improvements on top of basic NIO libraries, such as:

  • More elegant implementation of the Reactor pattern, flexible thread models, innovative mechanisms like EventLoop, which can efficiently manage hundreds or thousands of channels.
  • Making full use of Java’s Zero-Copy mechanism and reducing the overhead of memory allocation and deallocation from various perspectives. For example, using pooled Direct Buffers to reduce object creation and destruction while improving IO performance, directly manipulating SelectionKeys using reflection instead of using Java containers, and so on.
  • Utilizing more native code. For example, directly calling Open SSL using JNI to achieve better performance than Java’s built-in SSL engine.
  • Optimization in other aspects such as communication protocols, serialization, etc.

In summary, Netty does not have the strong universality and cross-platform burden of Java’s core libraries. Instead, it adopts some extreme optimization methods for specific performance goals and specific environments like Linux.

Examination Point Analysis #

This is a relatively open question. The answer I provide is a summary example. The interviewer is likely to use this open question as an introduction and delve into your understanding at different levels based on your answer.

In interview preparation, it is important to consider the overall picture while also selecting specific key points for in-depth understanding and mastery. It is best to conduct deep reading and experiments at the source code level. If you want to learn more about Netty’s performance-oriented techniques at the coding level, you can refer to Norman’s presentation at Devoxx, where many of the techniques have some reference value for achieving ultimate performance in API implementation, but should be used with caution in general business development.

Although Netty is often associated with high performance, its advantages are not limited to just this aspect.

Below, I will focus on two aspects:

  • Give an overall introduction to Netty to help you understand its basic components.
  • Starting with a simple example, compare it with the examples based on IO, NIO, and other standard APIs in [Lesson 11], analyze its technical points, and provide you with a further learning path.

Knowledge Expansion #

First, let’s get an overall understanding of Netty. According to the official definition, Netty is an asynchronous, event-driven Client/Server network framework that aims to provide a simple and fast way to build network applications while ensuring high throughput, low latency, and high reliability.

What are the differences between Netty and Java’s own NIO framework in terms of design ideas and objectives?

We know that Java’s standard library, due to its fundamental and general nature, often focuses too much on abstracting technical models rather than thinking from the perspective of frontline application developers. As I mentioned before, one important reason for introducing the concurrency package is that application developers find it painful to use the Thread API, as they not only need to focus on business logic but also have to take care of mapping it to the Thread model. Java NIO has similar characteristics in its design, requiring developers to have a deep understanding of concepts such as threads, I/O, and networks. The learning curve is long, and it is easy to end up with complex and obscure code. Even experienced engineers find it difficult to write highly reliable implementations quickly.

Netty’s design emphasizes “Separation Of Concerns” by isolating business logic from unrelated technical logic through a cleverly designed event mechanism. Through various convenient abstractions, it bridges the gap between the underlying platform and business development to a certain extent, making it more conducive to popularizing industry best practices in application development.

Furthermore, Netty is greater than java.nio + java.net!

In terms of API capabilities, Netty is a significantly larger set of features compared to the Java NIO framework. You can refer to the module division provided by the Netty official documentation.

Netty Modules

In addition to the core event mechanism, Netty also provides many additional features, such as:

  • In terms of network protocols, Netty not only supports transport layer protocols like UDP, TCP, SCTP, but also supports various application layer protocols including HTTP(s) and WebSocket. It is not an API for a single protocol.
  • In applications, there is a need to convert data from Java objects to various application protocol data formats or perform reverse conversions. Netty provides a series of extended encoding and decoding frameworks that seamlessly integrate with application development scenarios and have good performance.
  • It extends Java NIO Buffer, provides its own implementation of ByteBuf, and deeply supports technologies like Direct Buffer, even hacking Java’s internal allocation and destruction of Direct Buffers. At the same time, Netty also provides a more complete implementation of the Scatter/Gather mechanism.

As we can see, the capabilities of Netty far exceed the Java core library’s NIO and other APIs. It can be said that it is a product from the perspective of application development.

Of course, Netty also has its unique insights into basic API design. In the future, improvements to the Java NIO API may be based on this. If you are interested, you can refer to JDK-8187540.

Next, let’s take a look at a simple code example to see what a Netty application looks like.

Similar to “Lesson 11”, let’s use a simplified Echo Server as an example. The following code is the Server part provided by Netty’s official documentation. For the complete example, please click here.

In the example above, although the code is short, it already demonstrates several core concepts of Netty. Please pay attention to the parts I marked with red boxes:

  • ServerBootstrap, the entry point for server-side applications. This is a Bootstrapping mechanism introduced by Netty to simplify network program configuration, shutdown, and other lifecycle management tasks. The creation of channels, port binding, and handler registration that we usually need to do can all be done through this unified entry point using a Fluent API, which simplifies the API usage. On the other hand, Bootstrap is the usual entry point for the client side.
  • Channel, as an extension framework based on NIO, the concepts of channels and selectors are still fundamental components of Netty. However, Netty provides relatively easy-to-use abstractions based on specific application development requirements.
  • EventLoop, this is the core mechanism for event handling in Netty. The example uses EventLoopGroup. Common tasks we usually do in NIO, such as registering interested events and scheduling corresponding handlers, are handled by EventLoop.
  • ChannelFuture, this is one of the foundations for Netty’s asynchronous I/O, ensuring the order of invocation for operations on the same channel. Netty extends the standard Java Future and provides its own definition of Future specific to its own scenario.
  • ChannelHandler, this is the main place where application developers place their business logic, and it embodies the “Separation of Concerns” principle I mentioned earlier.
  • ChannelPipeline, it is the container for the chain of ChannelHandlers, with each Channel automatically being assigned a ChannelPipeline upon creation. In the example above, we registered a ChannelInitializer through ServerBootstrap, and implemented the initChannel method, which is responsible for installing other handlers to the ChannelPipeline.

You can refer to the simplified diagram below to understand the operation flow and correspondence between these basic units, ignoring the details of Inbound/Outbound Handlers.

Compared to the standard Java NIO code, Netty provides a relatively high-level abstraction that reduces the manipulation of details such as selectors. The mechanisms such as EventLoop and Pipeline also simplify the programming model, eliminating the need for developers to worry about concurrency issues, and to some extent, simplifying the development of application code. What’s even more commendable is that all of this does not come at the expense of reliability and scalability, but rather greatly enhances them.

In the “Weekend Bonus” section, I have already recommended the book “Netty in Action” by Norman Maurer and others. If you want to learn Netty systematically, it will be a good starting reference. Some implementation principles of Netty might become topics in interviews, such as:

  • Reactor pattern and Netty thread model.
  • Design and implementation details of pipelining, EventLoop, etc.
  • Netty’s memory management mechanism, reference counting, and other special techniques.
  • Sometimes interviewers like to compare Java standard NIO API, for example, do you know about the empty looping problem of Epoll in earlier versions of Java NIO (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6670302), and how Netty solves it, etc.

There are already many in-depth explanations available for these knowledge points. When studying, I hope you won’t get overwhelmed by the complex details from the beginning. Instead, you can gradually and purposefully learn by combining examples. One suggestion I have is to try drawing corresponding diagrams, as it can greatly help with understanding and presenting your own ideas clearly.

Today, I briefly introduced the Netty framework starting with performance issues, and compared Netty’s design with Java NIO using the example of an Echo Server. However, these are just the tip of the iceberg, and mastering Netty comprehensively requires a lot more effort.

Practice Lesson #

Do you have a clear understanding of the topic we discussed today? Today’s question for reflection is: What is the thread model of Netty?

Please write your thoughts on this question in the comments section. I will select well-thought-out comments and reward you with a learning coupon. Feel free to discuss with me.

Are your friends also preparing for interviews? You can “invite friends to read” and share today’s question with them. Perhaps you can help them.