Java NIO 根据操作系统不同,对 Selector 有不同的实现。比如:
- macosx 是 KQueueSelectorProvider
- windows 有 WindowsSelectorProvider
- Linux 有 EPollSelectorProvider (Linux kernels >= 2.6,是 epoll 模式)或 PollSelectorProvider(selector模式)
自4.0.16起,Netty 为 Linux 通过 JNI 的方式提供了 native socket transport。
Oracle jdk 会自动选择合适的 Selector,Oracle JDK 在 Linux 已经默认使用 epoll 方式, 为什么netty还要提供一个基于 epoll 的实现呢?
stackoverflow 也解释过,具体可参阅官方 native-transports,Tomcat Native
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.
- Netty 的 epoll transport 使用 epoll edge-triggered 而 java 的 nio 使用 level-triggered
- Netty的 epoll transport 暴露了更多的nio没有的配置参数, 如 TCP_CORK, SO_REUSEADDR等。
- C 代码,更少 GC,更少 synchronized
总之,linux 上使用 EpollEventLoopGroup 会有较少的 gc 有更高级的特性,性能更好~!
那该如何使用 native socket transport(epoll)呢?
其实只需将相应的类替换即可
很多优秀的源码中对此都进行了兼容性处理,比如 rocketmq
//源于org.apache.rocketmq.remoting.netty
public class NettyRemotingServer extends NettyRemotingAbstract implements RemotingServer {
public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
final ChannelEventListener channelEventListener) {
super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
this.serverBootstrap = new ServerBootstrap();
this.nettyServerConfig = nettyServerConfig;
this.channelEventListener = channelEventListener;
int publicThreadNums = nettyServerConfig.getServerCallbackExecutorThreads();
if (publicThreadNums <= 0) {
publicThreadNums = 4;
}
this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "NettyServerPublicExecutor_" + this.threadIndex.incrementAndGet());
}
});
if (useEpoll()) {
this.eventLoopGroupBoss = new EpollEventLoopGroup(1, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyEPOLLBoss_%d", this.threadIndex.incrementAndGet()));
}
});
this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
private int threadTotal = nettyServerConfig.getServerSelectorThreads();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
}
});
} else {
this.eventLoopGroupBoss = new NioEventLoopGroup(1, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyNIOBoss_%d", this.threadIndex.incrementAndGet()));
}
});
this.eventLoopGroupSelector = new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
private int threadTotal = nettyServerConfig.getServerSelectorThreads();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
}
});
}
loadSslContext();
}
private boolean useEpoll() {
return RemotingUtil.isLinuxPlatform()
&& nettyServerConfig.isUseEpollNativeSelector()
&& Epoll.isAvailable();
}
}
[
](https://blog.csdn.net/alex_xfboy/article/details/89643638)