溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

netty的使用方法是什么

發(fā)布時間:2021-12-31 09:25:39 來源:億速云 閱讀:151 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要介紹“netty的使用方法是什么”,在日常操作中,相信很多人在netty的使用方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”netty的使用方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一:Netty簡單認知

Netty 是由 JBOSS 提供的一個異步的、 基于事件驅動的網(wǎng)絡編程框架。Netty 可以幫助你快速、 簡單的開發(fā)出一 個網(wǎng)絡應用, 相當于流程化及簡化了 NIO 的開發(fā)過程。知名的 Elasticsearch 、 Dubbo 框架內(nèi)部都采用了 Netty。

netty的使用方法是什么

1 為什么使用netty

NIO缺點

  • NIO 的類庫和 API 繁雜,使用麻煩。你需要熟練掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等.

  • 可靠性不強,開發(fā)工作量和難度都非常大

  • NIO 的 Bug。例如 Epoll Bug,它會導致 Selector 空輪詢,最終導致 CPU 100%。

Netty優(yōu)點

  • 對各種傳輸協(xié)議提供統(tǒng)一的 API

  • 高度可定制的線程模型——單線程、一個或多個線程池

  • 更好的吞吐量,更低的等待延遲

  • 更少的資源消耗

  • 最小化不必要的內(nèi)存拷貝

2 Reactor線程模型

Reactor模式是基于事件驅動開發(fā)的,核心組成部分包括Reactor和線程池,其中Reactor負責監(jiān)聽和分配事件線程池負責處理事件。Netty線程模型就是Reactor模式的一個實現(xiàn)。

無論是 C++ 還是 Java 編寫的網(wǎng)絡框架,大多數(shù)都是基于 Reactor 模式進行設計和開發(fā),Reactor 模式基于事件驅動,特別適合處理海量的 I/O 事件。

Reactor的數(shù)量和線程池的數(shù)量,又將Reactor分為三種模型:

  • 單線程模型 (單Reactor單線程)

  • 多線程模型 (單Reactor多線程)

  • 主從多線程模型 (多Reactor多線程)。

2.1 Reactor單線程模型

Reactor 單線程模型,指的是所有的 IO 操作(接收請求、業(yè)務邏輯處理)都在同一個 NIO 線程上面完成。

NIO 線程的特點如下:

  • 作為 NIO 服務端,接收客戶端的 TCP 連接

  • 作為 NIO 客戶端,向服務端發(fā)起 TCP 連接;

  • 讀取通信另一端的請求或者應答消息;

  • 向通信另一端發(fā)送請求消息或者應答消息

netty的使用方法是什么

Reactor內(nèi)部通過selector 監(jiān)控連接事件,收到事件后通過dispatch進行分發(fā),如果是連接建立的事件,則由Acceptor處理Acceptor通過accept接受連接,并創(chuàng)建一個Handler來處理連接后續(xù)的各種事件,如果是讀寫事件,直接調(diào)用連接對應的業(yè)務Handler來處理。

適用場景:

  • 對于一些小容量應用場景,可以使用單線程模型。

  • 但是對于高負載、大并發(fā)的應用場景卻不合適。 一個 NIO 線程同時處理成百上千的鏈路,性能上無法支撐,即便 NIO 線程的 CPU 負荷達到 100%,也無法滿足海量消息的編碼、解碼、讀取和發(fā)送。

2.2 Reactor多線程模型

Reactor多線程模型,仍然只有一個Nio線程用于監(jiān)聽連接請求;而業(yè)務邏輯處理由一個線程池負責。

netty的使用方法是什么

  1. 主線程中,Reactor對象通過selector監(jiān)控連接事件,收到事件后通過dispatch進行分發(fā),如果是連接建立事件,則由Acceptor處理,Acceptor通過accept接收連接,并創(chuàng)建一個Handler來處理后續(xù)事件,而Handler只負責響應事件,不進行業(yè)務操作,也就是只進行read讀取數(shù)據(jù)和write寫出數(shù)據(jù),業(yè)務處理交給一個線程池進行處理。

netty的使用方法是什么

  1. 線程池分配一個線程完成真正的業(yè)務處理,然后將響應結果交給主進程的Handler處理,Handler將結果發(fā)送給客戶端

適用場景:

  • 在絕大多數(shù)場景下,Reactor 多線程模型都可以滿足性能需求;

  • 但是,在極個別特殊場景中,一個 NIO 線程負責監(jiān)聽和處理所有的客戶端連接可能會存在性能問題。例如并發(fā)百萬客戶端連接,或者服務端需要對客戶端握手進行安全認證,但是認證本身非常損耗性能。在這類場景下,單獨一個線程可能會存在性能不足問題。

2.3 主從多線程模型(常用)

相對于多線程模型,服務端用于接收客戶端連接的不再是個 1 個單獨的 NIO 線程,而是一個獨立的 NIO 線程池。Acceptor 線程池僅僅只用于客戶端的登陸、握手和安全認證,一旦鏈路建立成功,就將鏈路注冊到后端 subReactor 線程池的 IO 線程上,由 IO 線程負責后續(xù)的 IO 操作。

netty的使用方法是什么

  • 存在多個Reactor,每個Reactor都有自己的selector選擇器,線程和dispatch

  • 主線程中的mainReactor通過自己的selector監(jiān)控連接建立事件,收到事件后通過Accpetor接收,將新的連接分配給某個子線程

  • 子線程中的subReactor將mainReactor分配的連接加入連接隊列中通過自己的selector進行監(jiān)聽,并創(chuàng)建一個Handler用于處理后續(xù)事件

  • Handler完成read->業(yè)務處理->send的完整業(yè)務流程

3 Netty線程模型與Reactor的聯(lián)系

3.1 單線程模型

單線程模型就是只指定一個線程執(zhí)行客戶端連接和讀寫操作,也就是在一個Reactor中完成,對應在Netty中的實現(xiàn)就是將NioEventLoopGroup線程數(shù)設置為1,核心代碼是:

 NioEventLoopGroup group = new NioEventLoopGroup(1);
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(group)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ServerHandlerInitializer());

工作流程如下:

netty的使用方法是什么

3.2 多線程模型

多線程模型就是在一個單Reactor中進行客戶端連接處理,然后業(yè)務處理交給線程池,核心代碼如下:

NioEventLoopGroup eventGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(eventGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ServerHandlerInitializer());

工作流程如下:

netty的使用方法是什么

3.3 主從多線程模型模型

主從多線程模型是有多個Reactor,也就是存在多個selector,所以我們定義一個bossGroup和一個workGroup,核心代碼如下:

NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ServerHandlerInitializer());

工作流程如下:

netty的使用方法是什么

注意:其實在Netty中,bossGroup線程池最終還是只會隨機選擇一個線程用于處理客戶端連接,與此同時,NioServerSocetChannel綁定到bossGroup的線程中,NioSocketChannel綁定到workGroup的線程中

4 Netty核心組件

4.1 ChannelHandler及其實現(xiàn)類

ChannelHandler 接口定義了許多事件處理的方法,可以通過重寫這些方法去實現(xiàn)具體的業(yè)務邏輯。經(jīng)常需要自定義一個 Handler 類去繼承 ChannelInboundHandlerAdapter, 然后通過重寫相應方法實現(xiàn)業(yè)務邏輯

public void channelActive(ChannelHandlerContext ctx), 通道就緒事件
public void channelRead(ChannelHandlerContext ctx, Object msg), 通道讀取數(shù)據(jù)事件
public void channelReadComplete(ChannelHandlerContext ctx) , 數(shù)據(jù)讀取完畢事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause), 通道發(fā)生異常事件

4.2 ChannelPipeline

ChannelPipeline 是一個 Handler 的集合, 它負責處理和攔截 inbound 或者 outbound 的事 件和操作, 相當于 一個貫穿 Netty 的鏈。

ChannelPipeline addFirst(ChannelHandler... handlers), 把一個業(yè)務處理類(handler) 添加到鏈中的第一個位置
ChannelPipeline addLast(ChannelHandler... handlers), 把一個業(yè)務處理類(handler) 添加到鏈中的最后一個位置

netty的使用方法是什么

4.3 ChannelHandlerContext

ChannelHandlerContext是事件處理器上下文對象 ,Pipeline鏈中的實際處理節(jié)點 。每個處理節(jié)點ChannelHandlerContext中包含一個具體的事件處理器ChannelHandler,同時ChannelHandlerContext中也綁定了對應的pipeline和Channel的信息

ChannelFuture close(), 關閉通道
ChannelOutboundInvoker flush(), 刷新
ChannelFuture writeAndFlush(Object msg) , 將數(shù)據(jù)寫到ChannelPipeline中,當前ChannelHandler的下一個ChannelHandler 開始處理(出站)

4.4 ChannelFuture

ChannelFuture用來表示 Channel 中異步 I/O 操作的結果, 在 Netty 中所有的 I/O 操作都是異步的, I/O 的調(diào)用會直接返回, 調(diào)用者并不能立刻獲得結果, 但是可以通過 ChannelFuture 來獲取 I/O 操作的處理狀態(tài)。

Channel channel(), 返回當前正在進行 IO 操作的通道
ChannelFuture sync(), 等待異步操作執(zhí)行完畢

4.5 EventLoopGroup

EventLoopGroup 是一組 EventLoop 的抽象, Netty 為了更好的利用多核 CPU 資源, 一般會有多個 EventLoop 同時工作, 每個EventLoop 維護著一個Selector 實例。

EventLoopGroup 提供 next 接口, 可以從組里面按照一定規(guī)則獲取其中一個 EventLoop 來處理任務。

在 Netty 服務器端編程中,我們一般都需要提供兩個EventLoopGroup, 例如: BossEventLoopGroup和WorkerEventLoopGroup。

4.6 ServerBootstrap 和 Bootstrap

ServerBootstrap 是 Netty 中的服務器端啟動助手,通過它可以完成服務器端的各種配置; Bootstrap 是 Netty 中 的客戶端啟動助手, 通過它可以完成客戶端的各種配置。

ServerBootstrap:

 public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup),該方法用于服務器端, 用來設置兩個 EventLoop
 public B channel(Class<? extends C> channelClass), 該方法用來設置一個服務器端的通道實現(xiàn)
 public <T> B option(ChannelOption<T> option, T value), 用來給 ServerChannel 添加配置
 public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value), 用來給接收到的通道添加配置
 public ServerBootstrap childHandler(ChannelHandler childHandler), 該方法用來設置業(yè)務處理類(自定義的 handler)
 public ChannelFuture bind(int inetPort) , 該方法用于服務器端, 用來設置占用的端口號

Bootstrap:

public ChannelFuture connect(String inetHost, int inetPort) 該方法用于客戶端, 用來連接服務器端
public B group(EventLoopGroup group) , 該方法用于客戶端, 用來設置一個 EventLoop

4.7 netty 的簡單使用

服務端:

    public static void main(String[] args) throws InterruptedException {
        // 1. 創(chuàng)建二個線程池對象
        /**
         * bossGroup 負責接受用戶連接
         */
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        /**
         * workGroup 負責用戶的io讀寫操作
         */
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        /**
         * 2.創(chuàng)建啟動引導類
         */
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        // 3.設置啟動引導類
        // 設置組,第一個bossGroup負責連接, workerGroup負責連接之后的io處理
        serverBootstrap.group(bossGroup,workGroup)
                // channel方法指定服務器監(jiān)聽的通道類型
                .channel(NioServerSocketChannel.class)
                //設置channel handler , 每一個客戶端連接后,給定一個監(jiān)聽器進行處理
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        //獲取傳輸通道
                        ChannelPipeline pipeline = nioSocketChannel.pipeline();
                        //在通道上添加對通道的處理器 , 該處理器可能還是一個監(jiān)聽器
                        pipeline.addFirst(new StringEncoder());
                        pipeline.addLast(new StringDecoder());
                        //監(jiān)聽器隊列上添加我們自己的處理方式..
                        pipeline.addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
                                System.out.println(msg);
                            }
                        });
                    }
                });
        // 4.啟動引導類綁定端口
        ChannelFuture future = serverBootstrap.bind(8888).sync();
        // 5.關閉通道
        Channel channel = future.channel();
        channel.closeFuture().sync();
    }

客戶端:

    public static void main(String[] args) throws InterruptedException {
        // 1.創(chuàng)建連接池對象
        NioEventLoopGroup group = new NioEventLoopGroup();
        // 2. 創(chuàng)建客戶端的啟動引導類
        Bootstrap bootstrap = new Bootstrap();
        // 3. 配置啟動引導類
        bootstrap.group(group)
                // 設置通道為nio
                .channel(NioSocketChannel.class)
                // 設置channel初始化監(jiān)聽
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        // 設置編碼
                        channel.pipeline().addLast(new StringEncoder());
                    }
                });
        // 4.使用啟動引導類連接服務器,獲取一個channel
        Channel channel = bootstrap.connect("127.0.0.1", 8888).channel();
        // 5.循環(huán)寫數(shù)據(jù)給服務器
        while(true){
            // 給服務器寫數(shù)據(jù)
            channel.writeAndFlush("hello server.. this is clint say to you..");
            Thread.sleep(2000);
        }
    }

5 基于Netty實現(xiàn)自定義的RPC

使用Netty自定義實現(xiàn)Rpc

到此,關于“netty的使用方法是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

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

AI