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