Netty使用案例 -客戶端連接池使用

將Netty強大的NIO當做BIO使用

設置啓動的poolSize爲150 先創建150個線程EventLoopGroup,這裏我設置JVM的參數爲

//由於用的是jdk8,所以好多數據會在元空間存放
-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=60m -Xmx50m

//具體代碼如下
public class InitNettyPool {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        initClientPool(Integer.valueOf(args[0]));
    }
    static void initClientPool(int poolSize) throws InterruptedException {
        for (int i = 0; i < poolSize; i++) {
            EventLoopGroup group = new NioEventLoopGroup();
            //創建不要使用多線程創建。
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new LoggingHandler());
                        }
                    });
            ChannelFuture sync = bootstrap.connect("61.135.169.125", 80).sync();
            sync.channel().closeFuture().addListener((r) -> {
                System.out.println("執行shutdown");
                group.shutdownGracefully();
            });
        }
    }
}

運行後的結果看到創建了200個nioEventLoopGroup-xx-1的線程,並且堆的大小我們最大設置的50,老年代幾乎已經滿了。可以看到創建大量的EventLoopGroup線程池,由於每個線程本身需要佔用一定的內存,所以連接數比較多的時候會佔有大量的內存。
在這裏插入圖片描述
將上邊的運行代碼傳入參數調整一下創建的數量。設置啓動的poolSize 調整爲200。發現啓動後報堆空間不夠了。
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
在這裏插入圖片描述
GC次數一直在增加,但是並不起左右,這裏說明內存泄漏了。看到服務還是正常運行的。這個時候除非暴力的重啓沒有別的辦法了。想想下如果生產環境也創建過多的線程是不是也只有重啓才能解決。上邊的代碼在創建時候調用的數和創建的數都是一樣的。典型的BIO。
錯誤的使用NIO通信框架,不僅沒有達到優化的效果,而且還發生了OOM異常。

正確使用Netty的NIO

//設置啓動的poolSize爲1000
public class InitNettyPool {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        initClientPool(Integer.valueOf(args[0]));
    }
    static void initClientPool(int poolSize) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        //創建不要使用多線程創建。多線程不安全
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        p.addLast(new LoggingHandler());
                    }
                });
        for (int i = 0; i < poolSize; i++) {
        	//線程安全
            ChannelFuture sync = bootstrap.connect("61.135.169.125", 80).sync();
            sync.channel().closeFuture().addListener((r) -> {
                System.out.println("執行shutdown");
                group.shutdownGracefully();
            });
        }
    }
}

調整之後。發現創建1000個連接都沒有發生OOM,具體的系統線程資源佔用,爲CPU內核數的2倍,與TCP的連接數沒有關係,搞定了線程爆發增長的問題。
在這裏插入圖片描述
作爲高性能的通信框架,Netty解決了傳統的BIO模型遇到的問題,在NIO線程中聚合了多路複用器Selector,Selector會不斷地輪訓註冊在其上的Channel。如果某個Channel上邊有新的TCP連接接入,讀和寫事件,這個Channel就處於就像狀態,會被Selector輪詢出來。然後通過key獲得就緒Channel的集合,一個多路複用器上可以輪詢多個Channel,意味着只需要一個線程做輪訓的操作,就可以接入成千上萬的客戶端。

注意事項

  • 這裏注意不要多線程的操作同一個Bootstrap實例,Bootstrap是I/O操作工具類,真正的操作在EventLoop線程負責,所以通常多線程操作同一個Bootstrap實例沒有什麼意義。
  • 使用Netty注意不要處理和線程組不能同時創建,創建線程組後再創建操作的連接。

創建機制原理分析

由於這裏沒有太明白,代碼跟丟了,所以以後補充吧。
看看Channel的接構圖
在這裏插入圖片描述

在這裏插入圖片描述
具體看地址
https://www.jianshu.com/p/d7f62e3e4abc

客戶端創建流程

在這裏插入圖片描述
https://blog.csdn.net/crazyzhb2012/article/details/78132346

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章