《Netty - One Framework to rule them all》演讲笔记
最后更新于
最后更新于
这次演讲的讲师是 Netty 项目领导者,同时也是经典书籍 的作者 。
Netty 3 存在诸多明显的设计缺陷:
很多内存垃圾(在高并发的场景下,GC 的负担会变得更重);
很多内存拷贝(Java Heap -> OS 内存 -> Socket);
缺少一个好的内存池(频繁地创建和销毁直接内存将会非常损耗性能);
缺少对于 Linux 操作系统的优化(不能使用 Linux 操作系统下的特性);
不太合理的线程模型(Inbound 和 Outbound 的操作是在不同线程中的)。
Netty 4 对以上问题做了优化:
产生更少的内存垃圾,也会更少地触发 GC;
使用 JNI 来支持某些 Linux 操作系统下仅有的特性;
提供了一个高性能的 Buffer Pool;
定义了一个易于使用的线程模型。
Netty 中的 Channel 是对 Socket 的抽象,可以用于网络数据的读取和写入。每个 Channel 会对应一个 ChannelPipeline,ChannelPipeline 是一个包含了不同 ChannelHandler 的双向链表,ChannelHandler 可以用于处理 Inbound 和 Outbound 事件。
Netty 中引入了一个非常轻量级的对象池。在 Netty 中存在着许多可以被复用的对象,并且这些对象会被限制在同一个线程中,例如在把 Byte 转换为 List<Object> 的编解码器中,Netty 不需要每次都创建一个新的 List,而是会把这个 List 缓存起来并且会重用它。
JDK 中的 NIO 是对 Socket 的抽象,可以运行在不同操作系统上,但是 NIO 并没有针对具体的操作系统来做优化。
Netty 使用 JNI 来提供了 NIO 中所有没有提供的、与操作系统相关的高级特性,例如 epoll。
JDK 中提供的 ByteBuffer 接口并不友好,Netty 中实现了一套更加友好的 Buffer 实现:ByteBuf。
Netty 中的 ByteBuf 是基于引用计数算法来管理内存的,并且 Netty 提供了一个内存溢出的检测器:ResourceLeakDetector
,可以用于检测潜在的资源泄漏问题。
Netty 中的 EventLoop
是对 I/O 线程的抽象,用于处理 I/O 操作和触发事件。EventLoop
继承了 EventExecutor
,EventExecutor
继承了 ScheduledExecutorService
,这意味着开发者可以在一个处理 Channel 的 I/O 线程里编排事件。
Netty 提供了 EventExecutor
,可以用于处理 Handler 中的一些可能会导致阻塞的事件。
当在 Java 中做很多底层性能相关的事情,例如网络编程,便会经常接触到 JVM。
在 JVM 中,对直接内存的管理仅是通过 finalizer 或 cleaner 机制来实现的,并且 JVM 只有在堆空间耗尽的时候才会进行 GC。然而,Netty 在被用于网络编程的时候,可以确切地知道某个对象在何时应该被回收,因此 JVM 对直接内存的管理方式并不适用于 Netty。
在 JVM 中,JIT 编译器会重新布局 class 文件,为了减少内存间隙和避免浪费内存。但有时,这会产生内存伪共享(False-Sharing)问题。
在 JDK 中的 NIO 也存在诸多问题:
NIO2 并没有真正地提供 NIO 的可用性;
NIO 会产生很多内存垃圾,例如 Selector、Keyset 等等;
ByteBuffer API 并不友好;