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-transportsTomcat 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)呢?

    其实只需将相应的类替换即可
    image.png
    很多优秀的源码中对此都进行了兼容性处理,比如 rocketmq

    1. //源于org.apache.rocketmq.remoting.netty
    2. public class NettyRemotingServer extends NettyRemotingAbstract implements RemotingServer {
    3. public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
    4. final ChannelEventListener channelEventListener) {
    5. super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
    6. this.serverBootstrap = new ServerBootstrap();
    7. this.nettyServerConfig = nettyServerConfig;
    8. this.channelEventListener = channelEventListener;
    9. int publicThreadNums = nettyServerConfig.getServerCallbackExecutorThreads();
    10. if (publicThreadNums <= 0) {
    11. publicThreadNums = 4;
    12. }
    13. this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new ThreadFactory() {
    14. private AtomicInteger threadIndex = new AtomicInteger(0);
    15. @Override
    16. public Thread newThread(Runnable r) {
    17. return new Thread(r, "NettyServerPublicExecutor_" + this.threadIndex.incrementAndGet());
    18. }
    19. });
    20. if (useEpoll()) {
    21. this.eventLoopGroupBoss = new EpollEventLoopGroup(1, new ThreadFactory() {
    22. private AtomicInteger threadIndex = new AtomicInteger(0);
    23. @Override
    24. public Thread newThread(Runnable r) {
    25. return new Thread(r, String.format("NettyEPOLLBoss_%d", this.threadIndex.incrementAndGet()));
    26. }
    27. });
    28. this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
    29. private AtomicInteger threadIndex = new AtomicInteger(0);
    30. private int threadTotal = nettyServerConfig.getServerSelectorThreads();
    31. @Override
    32. public Thread newThread(Runnable r) {
    33. return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
    34. }
    35. });
    36. } else {
    37. this.eventLoopGroupBoss = new NioEventLoopGroup(1, new ThreadFactory() {
    38. private AtomicInteger threadIndex = new AtomicInteger(0);
    39. @Override
    40. public Thread newThread(Runnable r) {
    41. return new Thread(r, String.format("NettyNIOBoss_%d", this.threadIndex.incrementAndGet()));
    42. }
    43. });
    44. this.eventLoopGroupSelector = new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
    45. private AtomicInteger threadIndex = new AtomicInteger(0);
    46. private int threadTotal = nettyServerConfig.getServerSelectorThreads();
    47. @Override
    48. public Thread newThread(Runnable r) {
    49. return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
    50. }
    51. });
    52. }
    53. loadSslContext();
    54. }
    55. private boolean useEpoll() {
    56. return RemotingUtil.isLinuxPlatform()
    57. && nettyServerConfig.isUseEpollNativeSelector()
    58. && Epoll.isAvailable();
    59. }
    60. }

    [

    ](https://blog.csdn.net/alex_xfboy/article/details/89643638)