我们都知道 bio nio 以及 nio2(也就是 aio),如果不是特别熟悉可以看看我之前写的网络 I/O 模型,那么 netty 为什么还经常看到类似下面的这段代码呢?
EventLoopGroup ……= new NioEventLoopGroup();
……
……
b.group(……).channel(NioSocketChannel.class)……
……
……
ChannelFuture f = b.bind(PORT).sync();
不选择 bio 模型我们知道,那么为什么不选择 aio 模式呢?而还是选择 nio 模式呢?这是一个值得思考的问题,我就一直很好奇,因为在网络 I/O 模型里面介绍的,明显 AIO 要比 NIO 模型还要好。
那么为什么 Netty 还是选择的 NIO 模型呢?
Netty 中这样定义 EventLoop 的,本篇重点不在这里,后续继续介绍 EventLoop。
Will handle all the I/O operations for a
Channel
once registered. OneEventLoop
instance will usually handle more than oneChannel
but this may depend on implementation details and internals.
Netty 中这样定义 EventLoopGroup 的,本篇重点不在这里,后续继续介绍 EventLoopGroup。
Special
EventExecutorGroup
which allows registeringChannel
s that get processed for later selection during the event loop.
Netty 中这样定义 Channel 的,本篇重点不在这里,后续继续介绍 Channel。
A nexus to a network socket or a component which is capable of I/O operations such as read, write, connect, and bind.
A channel provides a user:
- the current state of the channel (e.g. is it open? is it connected?),
- the configuration parameters of the channel (e.g. receive buffer size),
- the I/O operations that the channel supports (e.g. read, write, connect, and bind), and
- the
ChannelPipeline
which handles all I/O events and requests associated with the channel.
Netty 中这样定义 ChannelFuture 的,本篇重点不在这里,后续继续介绍 ChannelFuture。
The result of an asynchronous
Channel
I/O operation.All I/O operations in Netty are asynchronous. It means any I/O calls will return immediately with no guarantee that the requested I/O operation has been completed at the end of the call. Instead, you will be returned with a
ChannelFuture
instance which gives you the information about the result or status of the I/O operation.A
ChannelFuture
is either uncompleted or completed. When an I/O operation begins, a new future object is created. The new future is uncompleted initially - it is neither succeeded, failed, nor cancelled because the I/O operation is not finished yet. If the I/O operation is finished either successfully, with failure, or by cancellation, the future is marked as completed with more specific information, such as the cause of the failure. Please note that even failure and cancellation belong to the completed state.
备注: 这个是参考 netty 实战书籍的。
看看 RocketMQ 里面的写法,等 netty 系列完成了,后续 RocketMQ 会继续分析的。
备注:
If you are running on linux you can use EpollEventLoopGroup and so get better performance, less GC and have more advanced features that are only available on linux.
epoll 对文件描述符有两种操作模式--LT ( level trigger 电平模式)和 ET ( edge trigger 边缘模式)
简单来讲,LT 是 epoll 的默认操作模式,当 epoll_wait 函数检测到有事件发生并将通知应用程序,而应用程序不一定必须立即进行处理,这样 epoll_wait 函数再次检测到此事件的时候还会通知应用程序,直到事件被处理。
而 ET 模式,只要 epoll_wait 函数检测到事件发生,通知应用程序立即进行处理,后续的 epoll_wait 函数将不再检测此事件。因此 ET 模式在很大程度上降低了同一个事件被 epoll 触发的次数,因此效率比 LT 模式高。
解释为什么 epoll 默认是 LT 的原因(超哥解释,个人觉得还是非常不错的) LT(level triggered):LT 是缺省的工作方式,并且同时支持 block 和 no-block socket。在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的 fd 进行 IO 操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的 select/poll 都是这种模型的代表。
感谢超哥提供地址: https://github.com/netty/netty/commit/9330172f803f340df677c370464126cd6112204a#diff-67591dfc9d4c7ea8dbe03ab24ff1669c,EpollEventLoopGroup 和 NioEventLoopGroup 两者之间细微的差距。欢迎继续留言进行补充。
根据这个疑问搜索了下,查看到 github 上面的说明: https://github.com/netty/netty/issues/2515。
备注: 总的来说可能支持 AIO Not faster than NIO (epoll) on unix systems (which is true) 而且性价比不高,可能觉得不值得,反正 netty 已经封装好,用户调用起来也很简单和底层用 nio 或者 aio 其实用户不需要关心的,只要快就行。
由于自己水平问题,可能很多理解不到位,欢迎大家积极在留言区进行留言讨论,感谢。在后面合适的机会我们继续讨论,AIO Not faster than NIO (epoll) on unix systems (which is true) 这是为什么呢? 目前我还是先学习 netty 主干,后续会继续回到这个话题上面。
1
mightofcode 2020-01-15 23:19:10 +08:00
据我所知,因为 linux 下面没有真的 AIO,是 netty 包装了一层,属于脱裤子放屁
|