Netty進階內部元件詳解

小Pig奇發表於2020-10-03

Netty進階

Bootstrap、ServerBootstrap

  1. Bootstrap意思是引導,一個Netty應用通常由一個Bootstrap開始,主要作用是配置整個Netty程式,串聯各個元件,Netty中ServerBootstrap是服務端的啟動引導類,Bootstrap是客戶端引導類

常用方法

方法說明
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup)伺服器端:設定兩個EventLoopGroup
public B channel(Class<? extends C> channelClass)伺服器端:設定通道的實現
public B option(ChannelOption option, T value)伺服器端:為Server Channel新增配置
public ServerBootstrap childOption(ChannelOption childOption, T value)伺服器端:給接收的通道新增配置
public ServerBootstrap childHandler(ChannelHandler childHandler)伺服器端:設定業務處理型別(自定義handler)
public ChannelFuture bind(int inetPort)伺服器端:設定服務埠號
public B group(EventLoopGroup group)客戶端:設定一個EventLoopGroup
public ChannelFuture connect(String inetHost, int inetPort)客戶端:連線服務端

NioEventLoopGroup

NioEventLoopGroupd 執行緒的個數預設是系統 執行緒數 * 2

電腦的執行緒數

在這裡插入圖片描述

EventLoopGroup不傳入引數初始化的執行緒數

在這裡插入圖片描述

原始碼

如果nThreads傳入是空預設會採用DEFAULT_EVENT_LOOP_THREADS

在這裡插入圖片描述

DEFAULT_EVENT_LOOP_THREADS屬性是靜態程式碼塊,NettyRuntime.availableProcessors()方法就可以獲取當前機器處理器的核數

在這裡插入圖片描述

指定NioEventLoop數量

在這裡插入圖片描述

Channel

  1. 在Netty網路通訊元件,能夠用於執行網路I/O操作
  2. 通過Channel可獲得當前網路連線的通道的狀態
  3. 通過Channel可以獲得網路連線的配置引數(例如接收緩衝區大小)
  4. Channel提供非同步I/O操作(如建立連線,讀寫,埠繫結),非同步呼叫意味著任何I/O操作都將會立刻返回,並且不保證呼叫結束時所請求的I/O操作已完成
  5. 呼叫立即返回一個ChannelFuture例項,通過註冊監聽器到ChannelFuture上,可以I/O操作成功,失敗或者取消時回撥通知呼叫方
  6. 不同協議,不同阻塞型別都有不同的Channel型別對應

常用Channel型別

Channel型別協議
NioSocketChannel非同步的客戶端TCP Socket連線
NioServerSocketChannel非同步的服務端TCP Socket連線
NioDatagramChannel非同步的UDP連線
NioSctpChannel非同步的客戶端Sctp連線
NioSctpServerChannel非同步的服務端Sctp連線

channel與pipeline關係

從服務端cxt中分別獲取channel和pipeline

在這裡插入圖片描述

檢視channel屬性

在這裡插入圖片描述

檢視pipeline屬性

在這裡插入圖片描述

結論:通過斷點我們發現channel與pipeline是相互對應的,channel可以獲取到pipeline,pipeline也可以獲取到channel

Pipeline、ChannelPipeline

  1. ChannelPipeline是一個Handler的集合,它負責處理和攔截inbound或者outbound的事件和操作,相當於一個貫穿Netty的鏈條(ChannelPipeline儲存ChannelHandler的List,用於處理或者攔截Channel的入站事件和出站事件操作)
  2. ChannelPipeline例項了一種高階形式的攔截過濾器模式,使使用者可以完全控制事件的處理方式,以及Channel中各個的ChannelHandler如何相互互動

Netty中每一個CHannel都有且僅有一個ChannelPipeline對應

ChannelPipeline其實是一個雙向列表,可以通過head中的next找到下一個需要執行的ChannelHandler,相反我我們可以通過tail的prev得到上一個執行過的ChannelHandler,ChannelHandler真實的型別是ChannelHandlerContext

在這裡插入圖片描述

入/出站說明

入站事件和出站事件在一個雙向連結串列中,入站事件會從連結串列的head往後傳遞到最後一個入站的handler,出站事件會從連結串列的tail往前傳遞到最前一個出站的handler,兩種型別的handler相互不干擾

打斷點檢視

在這裡插入圖片描述

常用方法

方法說明
ChannelPipeline addFirst(String name, ChannelHandler handler)把業務處理類(handler)新增到鏈中的第一個位置
ChannelPipeline addLast(String name, ChannelHandler handler)把業務處理類(handler)新增到鏈中的最後一個位置

ChannelHandler

  1. ChannelHandler是一個介面,處理I/O事件或攔截I/O操作,在ChannelPipeline(業務處理鏈)會存在很多個Handler,處理完成一個Handler後會交給下一個Handler處理
  2. ChannelHandler本身沒有提供很多方法,因為這個介面有許多的方法需要實現,便使用期間,可以繼承他的子類

ChannelHandler關鍵實現類

在這裡插入圖片描述

  1. ChannelInboundHandler用於處理入站I/O事件
  2. ChannelOutboundHandler用於處理出站I/O事件

介面卡

  1. ChannelInboundHandlerAdapter用於處理入站I/O事件
  2. ChannelOutboundHandlerAdapter用於處理出站I/O事件

常用方法

方法說明
public void channelRegistered(ChannelHandlerContext ctx)通道註冊觸發
public void channelUnregistered(ChannelHandlerContext ctx)通道登出觸發
public void channelActive(ChannelHandlerContext ctx)通道就緒觸發
public void channelInactive(ChannelHandlerContext ctx)通道非活動狀態觸發
public void channelRead(ChannelHandlerContext ctx, Object msg)通道有可讀事件觸發
public void channelReadComplete(ChannelHandlerContext ctx)通道讀取完畢後觸發
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)通道發生異常觸發

ChannelHandlerContext

  1. 儲存Channel相關的所有上下文資訊,相同關聯一個ChannelHandler物件
  2. 即ChannelHandlerContext中包含一個具體的事件處理器ChannelHandler,同時也包含了對應的pipeline和Channel的資訊,方便對ChannelHandler進行呼叫

常用方法

方法說明
ChannelFuture close()關閉通道
ChannelHandlerContext flush()重新整理
ChannelFuture writeAndFlush(Object msg)將資料寫到ChannelPipeline中當前ChannelHandler,下一個ChannelHandler開始處理

ChannelOption

  1. Netty在建立Channel例項後,一般需要設定ChannelOption引數

常用引數

引數說明
ChannelOption.SO_BACKLOG對應TCP/IP協議listen函式的backlog引數,用來初始化伺服器可連線佇列大小,服務端處理客戶端連線請求是順序處理的,所以同一時間只能處理一個客戶端連線,多個客戶端來的時候,客戶端不能處理客戶端連線請求放在佇列中等待處理,backlog引數指定佇列的大小
ChannelOption.SO_KEEPALIVE一直儲存連線活動狀態

EventLoopGroup、NioEventLoopGroup

  1. EventLoopGroup是一組EventLoop的抽象,Netty為了更好的利用多核CPU資源,一般會有多個EventLoop同時工作,每個EventLoop維護著一個Selector例項
  2. EventLoopGroup提供next介面,可以從組裡面按照一定規則獲取其中一個EventLoop來處理任務,在Netty伺服器程式設計中,我們一般需要提供兩個EventLoopGroup,一個用於處理Accept事件一個處理其它事件,如:BossEventLoopGroup和WorkerEventLoopGroup

Unpooled

Netty提供一個專門用來操作緩衝區(即Netty的資料日期)的工具類,ByteBuf比NIO的buyeBuffer使用起來更加方便,效能也比較高

使用例子1

在這裡插入圖片描述

使用例子2

在這裡插入圖片描述

TaskQueue

在前面的案例中一直沒有使用到TaskQueue,TaskQueue有什麼用呢?

TaskQueue是任務佇列,在Netty模型中事件處理都是由Handler處理,但如果我們在Handler中有一些業務邏輯複雜的事情要處理,最終還是會導致當前處理的執行緒發生阻塞,這時就需要使用到TaskQueue,進入Handler,直接將這些複雜的業務邏輯提交到TaskQueue佇列中,就會有對應的執行緒非同步處理,這樣子可以做到立刻對客戶端請求響應,無需等待業務執行完畢響應,等業務處理成功後再次回應客戶端

TaskQueue使用場景

  1. 使用者程式自定義的普通任務
  2. 使用者自定義定時任務
  3. 非當前Reactor執行緒呼叫Channel的各種用法

使用者程式自定義的普通任務

在這裡插入圖片描述

在這裡插入圖片描述

結論:我們可以看到伺服器端不阻塞了,提交請求後業務程式碼被提交到了,當前channel().eventLoop()的TaskQueue中後,就直接執行channelReadComplete返回了,然後等待10秒後服務端把業務邏輯處理完成後就會再次返回

如果不相信已經提交到TaskQueue,可以打一個斷點看一下,可以發現ctx.channel().eventLoop().execute執行了後,TaskQueue的Size是1

在這裡插入圖片描述

使用者自定義定時任務

在這裡插入圖片描述

在這裡插入圖片描述

結論:業務邏輯程式碼先會被提交到一個scheduleTaskQueue的佇列中,在等待5秒後才會被執行裡面的程式碼

如果不相信已經提交到scheduleTaskQueue,可以打一個斷點看一下,可以發現ctx.channel().eventLoop().schedule執行了後,scheduleTaskQueue的Size是1

在這裡插入圖片描述

非當前Reactor執行緒呼叫Channel的各種用法

在訊息推送的時候就需要使用到該方法,因為每一個使用者他們繫結的eventLoop不一定都一樣,這樣需要維護一個channel的引用,根據使用者標識獲取到對應的channel這樣子我們就可以取到對應的eventLoop然後使用Write方法就可以給相應的使用者進行一個訊息推送

服務端需要儲存對應使用者的channel

在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

非同步模型

  1. 非同步和同步的概念是相對的,當一個非同步過程呼叫發出後,呼叫者不會立刻得到結果,等實際處理這個呼叫的元件完成後,通過狀態、通知、回撥等來通知呼叫者(JS中回撥函式)
  2. Netty中的I/O操作都是非同步的,包括Bind、Write、Connect等操作會簡單的返回一個ChannelFuture
  3. 呼叫者並不能立刻獲得結果,而是通過Future-Listener機制,使用者可以方便的主動獲取或者通過通知機制獲取IO操作結果
  4. Netty的非同步模型是建立在future和callback的上面的,callback就是回撥(前端Ajax就是典型例子通過回撥來獲取對應的值),終點來說future,核心思想:假如一個方法,計算過程非常耗時,等待方法返回顯然不合適,那麼可以這樣子,你呼叫該方法時我不管有沒有執行完成,我先給你返回一個Future,後續如果你想知道方法執行的怎麼樣了,可以通過Future去監聽該方法執行(即Future-Listener機制)

Future總結

  1. Future是非同步執行結果,可以通過它提供的方法檢測執行是否完成
  2. ChannelFuture是我們使用最多的,ChannelFuture是一個介面,我們可以給ChannelFuture新增監聽器,當監聽的事件被觸發時,就會通知監聽器

Future-Listener機制

  1. 當Future物件剛剛建立時,處於一個非完成狀態,呼叫者可以通過返回的ChannelFuture獲取操作執行的狀態,監聽函式來執行完成後的操作

常見方法

方法名說明
isDone獲取當前操作是否完成
isSuccess獲取已完成操作是否成功
getCause獲取已完成操作失敗的原因
isCancelled獲取已完成的當前操作是否被取消
addListener註冊監聽器後,才能呼叫上面的方法

使用案例

在這裡插入圖片描述

相關文章