从RocketMQ通信模块聊聊EpollEventLoopGroup和NioEventLoopGroup

这里是weihubeats ,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党

背景

最近在排查RocketMQ一个网络问题的时候,排查到了Netty相关的处理,然后看到了RocketMQ在构建workGroup的时候,发现了有如下代码

java 复制代码
private EventLoopGroup buildEventLoopGroupSelector() {
        if (useEpoll()) {
            return new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
                private final AtomicInteger threadIndex = new AtomicInteger(0);
                private final int threadTotal = nettyServerConfig.getServerSelectorThreads();

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
                }
            });
        } else {
            return new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
                private final AtomicInteger threadIndex = new AtomicInteger(0);
                private final int threadTotal = nettyServerConfig.getServerSelectorThreads();

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
                }
            });
        }
    }

可以看到有一个很核心的判断

java 复制代码
if (useEpoll()) {
  //...
}


private boolean useEpoll() {
        return NetworkUtil.isLinuxPlatform()
            && nettyServerConfig.isUseEpollNativeSelector()
            && Epoll.isAvailable();
    }

这里判断是否使用linux中的epoll网络IO模型,可以看到最终构建的Group有区别,分别是:

  • EpollEventLoopGroup
  • NioEventLoopGroup

EpollEventLoopGroupNioEventLoopGroup的区别

  • NioEventLoopGroup:基于 Java NIO(New I/O)库实现,使用 Java 原生的 Selector 类来处理事件驱动。它在大多数操作系统上都能正常工作,并且具有良好的跨平台性能。NioEventLoopGroup 是 Netty 的默认事件循环组

  • EpollEventLoopGroup:基于 Linuxepoll 机制实现,利用了 Linux 内核提供的事件通知机制来实现高性能的事件驱动。它在适用于 Linux 的环境下提供更好的性能和扩展性。EpollEventLoopGroup 需要依赖于 Netty 的 netty-transport-native-epoll 模块,并且只能在支持 epoll 的操作系统上使用,如 Linux

可以看到这里的说明是EpollEventLoopGrouplinux平台的性能是要高于NioEventLoopGroup

网上也是大多这个说法,那么有没有什么数据证明呢?

相关issues及说明

其实如果我们去netty github仓库会发现,不止我们有这方面的疑问,一些老外也有。

在这个issues讨论中给了一个stackoverflow的链接

我们过去看看

大致说EpollEventLoopGroup有如下优势

  1. nettyepoll传输使用epoll边缘触发,而Java的NIO库使用水平触发。除此之外,epoll传输还提供了Java的NIO库所没有的配置选项,例如TCP_CORK、SO_REUSEPORT等。
  2. Netty提供了以下特定于平台的JNI传输:
scss 复制代码
Linux (since 4.0.16)
MacOS/BSD (since 4.1.11)

与基于NIO的传输相比,这些JNI传输添加了特定于特定平台的特性,生成更少的垃圾,并且通常提高了性能。

简单聊聊水平触发和边缘触发

  • 水平触发(Level-Triggered):在水平触发模式下,当一个文件描述符上有可读或可写事件发生时,如果应用程序没有对该事件进行处理,那么下次调用 epoll_wait() 函数时,仍然会返回该事件。也就是说,只要文件描述符上的状态还是可读或可写,就会不断地触发事件通知。这意味着如果应用程序没有及时处理事件,可能会导致事件的堆积和重复处理。
  • 边缘触发(Edge-Triggered):在边缘触发模式下,当一个文件描述符上有可读或可写事件发生时,只会触发一次事件通知,并且只有在文件描述符的状态发生变化时才会再次触发。也就是说,边缘触发模式只关注状态的变化,对于未处理的事件不会重复通知。应用程序需要确保在处理完事件后,及时读取或写入数据,以避免错过事件。

总结来说,水平触发模式下,只要文件描述符上的状态保持可读或可写,就会不断触发事件通知;而边缘触发模式下,只有在文件描述符的状态发生变化时才会触发事件通知。边缘触发模式更加精确和高效,因为它只通知状态变化的事件,减少了不必要的事件通知和处理开销。但是,边缘触发模式对于应用程序的处理要求更高,需要确保在处理完事件后及时读取或写入数据,否则可能会错过事件

总结

总的来说网上大多说明EpollEventLoopGroup在linux性能是更高于NioEventLoopGroup,但暂时没有找到相关的基准测试数据。总的来说在linux上面使用EpollEventLoopGroup似乎是更优的选择,所以我们在部署RocketMQ的时候我们可以将参数useEpollNativeSelector配置为true

相关推荐
码上一元2 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
枫叶_v4 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
杜杜的man4 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang
java小吕布5 小时前
Java中Properties的使用详解
java·开发语言·后端
2401_857610036 小时前
Spring Boot框架:电商系统的技术优势
java·spring boot·后端
杨哥带你写代码8 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_8 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
背水8 小时前
初识Spring
java·后端·spring
晴天飛 雪8 小时前
Spring Boot MySQL 分库分表
spring boot·后端·mysql
weixin_537590459 小时前
《Spring boot从入门到实战》第七章习题答案
数据库·spring boot·后端