从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

相关推荐
追逐时光者27 分钟前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
Jagger_27 分钟前
敏捷开发流程-精简版
前端·后端
苏打水com1 小时前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
间彧2 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧2 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧2 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧2 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧3 小时前
Spring Cloud Gateway详解与应用实战
后端
EnCi Zheng4 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6014 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring