溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

分布式Netty源碼分析

發(fā)布時(shí)間:2022-03-25 09:10:15 來(lái)源:億速云 閱讀:118 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了分布式Netty源碼分析的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇分布式Netty源碼分析文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。

    服務(wù)器端demo

    看下一個(gè)簡(jiǎn)單的Netty服務(wù)器端的例子

    public static void main(String[] args){
    	EventLoopGroup bossGroup=new NioEventLoopGroup(1);
    	EventLoopGroup workerGroup = new NioEventLoopGroup();
    	try {
    		ServerBootstrap serverBootstrap=new ServerBootstrap();
    		serverBootstrap.group(bossGroup,workerGroup)
    			.channel(NioServerSocketChannel.class)
    			.option(ChannelOption.SO_BACKLOG, 200)
    			.childHandler(new ChannelInitializer<SocketChannel>() {
    				@Override
    				protected void initChannel(SocketChannel ch) throws Exception {
    					ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(80,0,4,0,4));
    					ch.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8")));
    					ch.pipeline().addLast(new TcpServerHandler());
    				}
    			});
    		ChannelFuture f=serverBootstrap.bind(8080).sync();
    		f.channel().closeFuture().sync();
    	} catch (InterruptedException e) {
    		e.printStackTrace();
    	}finally {  
            workerGroup.shutdownGracefully();  
            bossGroup.shutdownGracefully();  
        }  
    }

    先來(lái)簡(jiǎn)單說(shuō)說(shuō)上述遇到的類(lèi):

    EventLoopGroup介紹

    它主要包含2個(gè)方面的功能,注冊(cè)Channel和執(zhí)行一些Runnable任務(wù)。

    分布式Netty源碼分析

    功能1:先來(lái)看看注冊(cè)Channel

    即將Channel注冊(cè)到Selector上,由Selector來(lái)調(diào)度Channel的相關(guān)事件,如讀、寫(xiě)、Accept等事件。

    而EventLoopGroup的設(shè)計(jì)是,它包含多個(gè)EventLoop(每一個(gè)EventLoop通常內(nèi)部包含一個(gè)線程),在執(zhí)行上述注冊(cè)過(guò)程中是需要選擇其中的一個(gè)EventLoop來(lái)執(zhí)行上述注冊(cè)行為,這里就出現(xiàn)了一個(gè)選擇策略的問(wèn)題,該選擇策略接口是EventExecutorChooser,你也可以自定義一個(gè)實(shí)現(xiàn)。

    從上面可以看到,EventLoopGroup做的工作大部分是一些總體性的工作如初始化上述多個(gè)EventLoop、EventExecutorChooser等,具體的注冊(cè)Channel還是交給它內(nèi)部的EventLoop來(lái)實(shí)現(xiàn)。

    功能2:執(zhí)行一些Runnable任務(wù)

    EventLoopGroup繼承了EventExecutorGroup,EventExecutorGroup也是EventExecutor的集合,EventExecutorGroup也是掌管著EventExecutor的初始化工作,EventExecutorGroup對(duì)于Runnable任務(wù)的執(zhí)行也是選擇內(nèi)部中的一個(gè)EventExecutor來(lái)做具體的執(zhí)行工作。

    netty中很多任務(wù)都是異步執(zhí)行的,一旦當(dāng)前線程要對(duì)某個(gè)EventLoop執(zhí)行相關(guān)操作,如注冊(cè)Channel到某個(gè)EventLoop,如果當(dāng)前線程和所要操作的EventLoop內(nèi)部的線程不是同一個(gè),則當(dāng)前線程就僅僅向EventLoop提交一個(gè)注冊(cè)任務(wù),對(duì)外返回一個(gè)ChannelFuture。

    總結(jié):EventLoopGroup含有上述2種功能,它更多的是一個(gè)集合,但是具體的功能實(shí)現(xiàn)還是選擇內(nèi)部的一個(gè)item元素來(lái)執(zhí)行相關(guān)任務(wù)。 這里的內(nèi)部item元素通常即實(shí)現(xiàn)了EventLoop,又實(shí)現(xiàn)了EventExecutor,如NioEventLoop等

    ChannelPipeline介紹

    上述EventLoopGroup可以將一個(gè)Channel注冊(cè)到內(nèi)部的一個(gè)EventLoop的Selector上,然后對(duì)于這個(gè)Channel的相關(guān)讀寫(xiě)等事件,Netty專(zhuān)門(mén)設(shè)計(jì)了一個(gè)ChannelPipeline來(lái)進(jìn)行處理。每一個(gè)Channel都有一個(gè)ChannelPipeline來(lái)處理該Channel的讀寫(xiě)等事件。

    分布式Netty源碼分析

    bind過(guò)程

    上述serverBootstrap的bind過(guò)程如下:

    • 創(chuàng)建出你所指定的NioServerSocketChannel,然后初始化一些Socket方面的參數(shù)

    • 為上述Channel的ChannelPipeline配置一個(gè)ChannelHandler,該ChannelHandler的作用就是在該Channel成功注冊(cè)到Selector上的時(shí)候,初始化一些邏輯,即initChannel方法中執(zhí)行一些邏輯,該邏輯就是向ChannelPipeline中添加一個(gè)新的ChannelHandler即ServerBootstrapAcceptor

    • 然后開(kāi)始將該Channel注冊(cè)到上述EventLoopGroup bossGroup中,該EventLoopGroup bossGroup會(huì)選擇內(nèi)部的一個(gè)EventLoop來(lái)執(zhí)行實(shí)際的注冊(cè)行為(這個(gè)時(shí)候就是當(dāng)前線程和操作的EventLoop不是同一個(gè)線程,即該過(guò)程是異步提交一個(gè)Runnable),一旦注冊(cè)完成,就執(zhí)行上述ChannelHandler的initChannel方法

    至此,就完成了整個(gè)bind過(guò)程。一旦EventLoop內(nèi)部的Selector檢測(cè)到NioServerSocketChannel有新的連接到來(lái)的事件,則會(huì)交給NioServerSocketChannel的ChannelPipeline來(lái)處理,重點(diǎn)就是ChannelPipeline中的上述ServerBootstrapAcceptor,ServerBootstrapAcceptor做如下操作:

    • 1 為新的Channel的ChannelPipeline配置我們上述代碼中的childHandler指定的ChannelHandler

    • 2 將新的Channel注冊(cè)到了上述EventLoopGroup workerGroup中

    sync介紹

    bind方法返回的是一個(gè)ChannelFuture,從上面我們也知道該過(guò)程是異步的,sync方法則是一直等待到該異步過(guò)程結(jié)束。

    再看下f.channel().closeFuture().sync()這個(gè)方法

    每一個(gè)ChannelFuture都是和一個(gè)Channel綁定的,所以可以通過(guò)ChannelFuture來(lái)獲取對(duì)應(yīng)綁定的Channel對(duì)象

    每一個(gè)Channel對(duì)象都有一個(gè)CloseFuture closeFuture對(duì)象,上述closeFuture方法并不是去執(zhí)行close方法而是獲取到這個(gè)CloseFuture closeFuture對(duì)象,然后調(diào)用它的sync方法即等待這個(gè)Future的結(jié)束。一般正常情況下是不會(huì)調(diào)用這個(gè)Future的結(jié)束方法的,只是在上述過(guò)程或者其他過(guò)程出現(xiàn)問(wèn)題的時(shí)候,如注冊(cè)到EventLoop失敗等才會(huì)去調(diào)用這個(gè)Feture的結(jié)束方法,所以正常情況下主線程會(huì)一直阻塞在CloseFuture closeFuture的sync方法上。

    誤區(qū)

    上述的bossGroup的創(chuàng)建問(wèn)題。

    我們都知道bossGroup是用來(lái)accept連接,然后將連接綁定到workerGroup中的,一般情況下bossGroup設(shè)置線程數(shù)為1即可(基本只能為1),我們同時(shí)知道Ractor模型中可以使用多個(gè)Acceptor線程來(lái)執(zhí)行accept操作,加快accept的速度。

    如果你想加快accept的速度,想開(kāi)啟多線程來(lái)accept,這時(shí)候想設(shè)置bossGroup的線程數(shù)為多個(gè)的話,就大錯(cuò)特錯(cuò)了,是根本沒(méi)效果的。

    結(jié)合上面的原理,只有在bind端口的時(shí)候才會(huì)創(chuàng)建一個(gè)ServerSocketChannel,然后注冊(cè)到bossGroup內(nèi)部的一個(gè)EventLoop中,仍然是單線程負(fù)責(zé)ServerSocketChannel的accept工作,而bossGroup中的多線程僅僅是為bind多個(gè)端口服務(wù)的。

    我們來(lái)看下tomcat是如何允許多個(gè)Acceptor線程來(lái)執(zhí)行accept操作的:

    • 1 創(chuàng)建了一個(gè)ServerSocketChannel serverSock,并bind到某個(gè)端口

    • 2 開(kāi)啟多個(gè)Acceptor線程,每個(gè)線程邏輯都是執(zhí)行上述serverSock的accept方法

    沒(méi)有使用Selector來(lái)執(zhí)行accept操作,可以多線程并發(fā)執(zhí)行上述serverSock的accept方法。

    一旦使用了Selector,基本上就相當(dāng)于將ServerSocketChannel serverSock綁定到了Selector所在線程上了(Selector不是線程安全的,只能在一個(gè)線程中被調(diào)度執(zhí)行)

    關(guān)于“分布式Netty源碼分析”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“分布式Netty源碼分析”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI