何為Netty
??Netty是一個異步事件驅動的網路應用程式框架,用于快速開發可維護的高性能協議服務器和客戶端,
何為事件驅動
事件處理的兩道工序:
| 方法 | 說明 |
|---|---|
| 事件分離器(Event Demultiplexer) | 將事件源(socket/file)的I/O時間分離出來(IO就緒事件,IO完成事件),并分傳遞到對應的I/O事件處理器, |
| 事件處理器(Event Handler) | 應用預先注冊需要處理的事件及其事件處理器(回呼函式), |
事件分離器的兩種模式:
| 模式 | 說明 |
|---|---|
| Reactor | 事件分離器負責等待檔案描述符或socket為讀寫操作準備就緒,然后將就緒事件傳遞給對應的處理器,最后由處理器負責完成實際的讀寫作業,I/O操作由應用完成,呼叫事件處理器時,表示I/O就緒, |
| Proactor | demultiplexor事件處理器負責發起異步I/O操作,將用戶定義的資料緩沖區地址和資料大小傳遞給作業系統,作業系統進行I/O操作,事件分離器捕獲IO操作完成事件,然后將事件傳遞給對應處理器,I/O操作由系統完成,呼叫事件處理器時,表示I/O完成, |
何為異步I/O
??常見的I/O模式有一下幾種,Netty是多路復用模式,假設場景:用戶想從水管管道取5000L水,但是這個水管的水流是斷斷續續的,那么他有以下幾種方法:
| 模式 | 大白話 | 說明 |
|---|---|---|
| 阻塞 I/O(blocking IO) | 他打開水龍頭,在必須原地等待水量達到5000L,然后這個任務才完成, | 阻塞,同步I/O |
| 非阻塞 I/O(nonblocking IO) | 他打開水龍頭,然后去做別的事情,兩分鐘過來查看一次(輪詢),直到水位達到500L,然后這個任務才完成, | 非阻塞,同步I/O |
| I/O 多路復用( IO multiplexing)(事件驅動I/O) | 他加裝多個水龍頭,然后在水龍頭的前端安裝水滴傳感器(阻塞),他在后臺輪詢各個傳感器的資料,一旦得到A水龍頭的水滴傳感器已經被觸發時,他就打開水龍頭A接水,有一下幾種機制select,epoll,iocp,kqueue,poll, | 非阻塞,同步I/O |
| 信號驅動 I/O( signal driven IO) | 他加裝多個水龍頭,然后在水龍頭的前端安裝水滴傳感器,當水龍頭A的水滴傳感器觸發時,主動通知他,他就打開水龍頭A接水, | 非阻塞,同步I/O |
| 異步 I/O(asynchronous IO) | 他加裝多個水龍頭,然后在水龍頭的前端安裝水量傳感器,并且將水龍頭打開,然后他就去做其他的事情了,當水來時,水量傳感器統計已取的水量,達到5000L時,將多個水桶的水匯聚到一個桶里,讓他直接使用, | 非阻塞,異步I/O |
I/O多路復用模式
| 模式 | 方法 | 說明 | 最大連接數 | 效率 | 訊息傳遞方式 |
|---|---|---|---|---|---|
| select | 輪詢 | 同步非阻塞 | FD_SETSIZE宏定義 | FD的增加會造成線性遍歷速度慢的“線性下降性能問題” | 內核需要將訊息傳遞到用戶空間,都需要內核拷貝動作 |
| kQueue | 回呼 | 同步非阻塞 | 與epoll相似 | 與epoll相似 | 與epoll相似 |
| iocp | 通知 | 異步 | 待了解 | 待了解 | 待了解 |
| poll | 輪詢 | 同步非阻塞 | 基于鏈表來存盤沒有最大連接數的限制 | 與select一樣 | 與select一樣 |
| ePoll | 回呼 | 同步非阻塞 | 連接數有上限,效率與連接數成反比 | socket活躍大會有性能問題 | 通過內核和用戶空間共享一塊記憶體來實作 |
Netty示例決議
以下是一個經典示例:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.mqtt.MqttDecoder;
import io.netty.handler.codec.mqtt.MqttEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.yb.iot.mqtt.handler.ChannelPipelineHandler;
import org.yb.iot.mqtt.handler.InboundMessageHandler;
import java.util.concurrent.TimeUnit;
public class NettyServer {
public static void main(String[] args) {
/**
* NioEventLoopGroup是處理I / O操作的多執行緒事件回圈,多種實作可選,
* 使用多少個執行緒以及如何將它們映射到創建的通道取決于EventLoopGroup實作,甚至可以通過建構式進行配置,
* 在上文中提到,I/O多路復用機制有多種,Netty中提供了多種實作,,以Group尾綴的為多執行緒實作,
*/
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
/**
* 設定服務器的幫助程式類,
*/
ServerBootstrap serverBootstrap = new ServerBootstrap();
/**
* bossGroup通常稱為“老板”,接受傳入的連接,
* workerGroup通常稱為“工人”,一旦老板接受連接并將注冊的連接注冊給工人,便處理已接受連接的流量,
*/
serverBootstrap.group(bossGroup, workerGroup)
/**
* 指定IO模型
*/
.channel(NioServerSocketChannel.class)
/**
* 配置自定義的事件處理器,
*/
.childHandler(new ChannelInitializer<SocketChannel>() {
@Autowired
private InboundMessageHandler inboundMessageHandler;
/**
* 初始化channel模型的背景關系
* @param socketChannel
* @throws Exception
*/
@Override
public void initChannel(SocketChannel socketChannel) {
/**
* 事件處理器責任鏈,可以動態增刪
* 可以進行例如協議編碼解碼,心跳,內容長度,粘包分包處理,讀寫處理等,
* Netty已經默認提供了多種標準協議的解碼編碼實作,全都在io.netty.handler.codec.*下,如MQTT,HTTP等,
*/
ChannelPipeline pipeline = socketChannel.pipeline();
/** 最大內容長度 */
pipeline.addLast(new HttpObjectAggregator(1024 * 1024 * 64));
/** 心跳時間 */
pipeline.addLast("idleStateHandler", new IdleStateHandler(120, 120, 120, TimeUnit.SECONDS));
/** 協議編碼 */
pipeline.addLast(MqttEncoder.INSTANCE);
/** 協議解碼 */
pipeline.addLast(new MqttDecoder(1024 * 1024 * 64));
/** 訊息處理 */
pipeline.addLast(inboundMessageHandler);
}
})
/**
* 配置EventLoopGroup模型的引數
*/
.option(ChannelOption.SO_BACKLOG, 128)
/**
* 配置Channel模型的引數
*/
.childOption(ChannelOption.SO_KEEPALIVE, true);
/**
* 系結并開始接受傳入的連接,ChannelFuture支持I/O完成事件監聽,
*/
ChannelFuture channelFuture = serverBootstrap.bind(1883).sync();
/**
* 注冊等待Socket服務器關閉,
*/
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
/**
* 優雅的關閉并退出服務
*/
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
EventLoopGroup與Channel的實作對應關系如下:
| 單執行緒模型 | 多執行緒模型/主從執行緒模型 | 通道模型 | 模式 |
|---|---|---|---|
| EpollEventLoop.class | EpollEventLoopGroup.class | EpollServerSocketChannel.class | epoll |
| KQueueEventLoop.class | KQueueEventLoopGroup.class | KQueueServerSocketChannel.class | kQueue |
| NioEventLoop.class | NioEventLoopGroup.class | NioServerSocketChannel.class | select |
Netty重要組件:
| 類 | 說明 |
|---|---|
| Channel | 管道物件 |
| ChannelPipeline | 管道事件處理器責任鏈 |
| ChannelHandler | 管道事件處理器的介面 |
| ChannelHandlerContext | 管道事件處理器的背景關系 |
| ChannelFuture | 管道異步操作的結果 |
| ByteBuf | 管道一幀資料的物件,位元組容器,通過參考計數的方式實作記憶體回收 |
參考檔案
Netty Wiki
Netty 實戰 中文版
Netty設計原理
并發編程網 Netty
linux下select/poll/epoll機制的比較
Linux IO模式及 select、poll、epoll詳解
Netty 系列之 Netty 執行緒模型
深入研究Netty之執行緒模型詳解
Netty學習之IO模型
著作權宣告
- 本文作者: 大魚叔叔
- 本文鏈接: https://www.huangdayu.cn/blog/42
- 著作權宣告: 本文著作權歸作者所有,禁止爬蟲,禁止轉載,禁止一切法律不允許的行為!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/247273.html
標籤:Java
