从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

相关推荐
老华带你飞7 分钟前
旅游|基于Java旅游信息推荐系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot·后端·旅游
kgduu33 分钟前
go ethreum之Trie
开发语言·后端·golang
William_cl39 分钟前
【CSDN 专栏】ASP.NET Controller 过滤器详解:ActionFilter(Action 前后逻辑)从入门到避坑
后端·asp.net
悟空码字1 小时前
SpringBoot实现消息推送:让服务器学会“主动搭讪”
java·spring boot·后端
+VX:Fegn08951 小时前
人力资源管理|基于springboot + vue人力资源管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
GOTXX1 小时前
性能与可靠双突破:openEuler 服务器场景评测报告
运维·服务器·网络·人工智能·后端·python
秋邱1 小时前
AR 技术团队搭建与规模化接单:从个人到团队的营收跃迁
前端·人工智能·后端·python·html·restful
U盘失踪了2 小时前
Django 登录注册功能实现
后端·python·django
U盘失踪了2 小时前
Django 登录注册功能实现-样式优化
后端·python·django
qinyuan152 小时前
使用husky和fabric规范git提交的注释
前端·后端