Netty源碼學習(一)Netty線程模型


給你一台4路E7-4820V2(32核心64線程),512G內存的服務器,你該如何編程才能支持百萬長連接?

 

最直接的想法是采用BIO的模式,為每個連接新建一個線程,在一一對應的線程中直接處理連接上的數據請求。

但在Java中,新建線程的開銷非常昂貴(默認情況下每個線程會占據1M多的內存,百萬連接就是1T內存,這顯然是不可接受的)

 

優化點的想法是使用Java NIO,用一個線程來處理所有客戶端的請求。

但是根據我之前的測試,單個線程最多同時處理5w/s的echo message,此時單個core已經跑滿,如果再接着加大負載會導致請求堆積。

 

進一步的優化是將線程分離,使用一個線程作為acceptor,一堆線程作為worker

acceptor監聽服務端口的accept事件,如果有accept事件被觸發,說明有客戶端連接進來,acceptor獲取連接(Channel)並將其分派給某個worker,worker監聽這個Channel的read事件,一旦Channel可讀,worker就會做出相應的處理。

也就是說將連接均分到各個worker,減輕壓力,也可以讓多個core被利用起來,使單機處理百萬長連接成為可能。

 

這就是所謂Reactor模型了,也是Netty所采用的線程模型。(還有更進一步的主從多線程模型,用於處理認證較為耗時的情況,這里不做介紹)

借用一下Doug Lea老爺子的示例圖:

 

用這個思想分析一下Netty的示例代碼:

    public void go(int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);//acceptor線程
        EventLoopGroup workerGroup = new NioEventLoopGroup();//worker線程組
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx,
                                        Object msg) { //ehco to client
                                    ctx.write(msg);
                                    ctx.flush();
                                }
                            });
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

可以猜出所謂的bossGroup就是Reactor模型中的acceptor,負責處理客戶端產生的TCP連接請求,workerGroup則是worker,真正負責IO讀寫操作。具體實現我們后續再做分析。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM