Netty背後的事件驅動機制

weixin_33861800發表於2018-11-21

Netty簡介

Netty是 一個非同步事件驅動的網路應用程式框架,用於快速開發可維護的高效能協議伺服器和客戶端。

事件驅動模型

通常,我們設計一個事件處理模型的程式有兩種思路
輪詢方式
執行緒不斷輪詢訪問相關事件發生源有沒有發生事件,有發生事件就呼叫事件處理邏輯。
事件驅動方式
事件發生時主執行緒把事件放入事件佇列,在另外執行緒不斷迴圈消費事件列表中的事件,呼叫事件對應的處理邏輯處理事件。事件驅動方式也被稱為訊息通知方式,其實是設計模式中觀察者模式的思路。

借用O'Reilly大神關於事件驅動模型解釋圖

11222983-71d582050fe05761.png
事件驅動模型圖.png

主要包括4個基本元件:
事件佇列(event queue):接收事件的入口,儲存待處理事件
分發器(event mediator):將不同的事件分發到不同的業務邏輯單元
事件通道(event channel):分發器與處理器之間的聯絡渠道
事件處理器(event processor):實現業務邏輯,處理完成後會發出事件,觸發下一步操作

可以看到,相對傳統輪詢模式,事件驅動有如下優點:
可擴充套件性好,分散式的非同步架構,事件處理器之間高度解耦,可以方便擴充套件事件處理邏輯
高效能,基於佇列暫存事件,能方便並行非同步處理事件

下圖描述了Netty進行事件處理的流程。Channel是連線的通道,是ChannelEvent的產生者,而ChannelPipeline可以理解為ChannelHandler的集合。

11222983-973f17ed9994f4b8.png
Netty事件處理流程

事件分為上行(Upstream)和下行(Downstream)兩種
當伺服器從客戶端收到一個訊息,那麼與之相關的就是一個上行事件(Upstream Event),Pipeline中的UpstreamChannelHandler會處理它;如果伺服器要響應這個客戶端,那麼與響應訊息對應的就是下行事件(Downstream Event),Pipeline中的DownstreamChannelHandler會處理它。

ChannelEvent是資料或者狀態的載體,例如傳輸的資料對應MessageEvent,狀態的改變對應ChannelStateEvent。當對Channel進行操作時,會產生一個ChannelEvent,併傳送到ChannelPipeline。ChannelPipeline會選擇一個ChannelHandler進行處理。這個ChannelHandler處理之後,可能會產生新的ChannelEvent,並流轉到下一個ChannelHandler。

我們引用Netty官方包裡的一個例子,一個簡單的EchoServer,它接受客戶端輸入,並將輸入原樣返回。

 public void run() {
        // Configure the server.
        ServerBootstrap bootstrap = new ServerBootstrap(
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));
        // Set up the pipeline factory.
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new EchoServerHandler());
            }
        });
        // Bind and start to accept incoming connections.
        bootstrap.bind(new InetSocketAddress(port));
    }

EchoServerHandler是這裡的業務處理邏輯

public class EchoServerHandler extends SimpleChannelUpstreamHandler {
        @Override
        public void messageReceived(
                ChannelHandlerContext ctx, MessageEvent e) {
            // Send back the received message to the remote peer.
            e.getChannel().write(e.getMessage());
        }
    }

其中MessageEvent就是一個事件。這個事件攜帶了一些資訊(ChannelBuffer),例如這裡e.getMessage()就是訊息的內容,而EchoServerHandler則描述了處理這種事件的方式,一旦某個事件觸發,相應的Handler則會被呼叫,並進行處理(解碼成了一個資料物件),並生成了一個新的MessageEvent,並傳遞給下一步進行處理。

在Netty裡,所有事件都來自ChannelEvent介面,這些事件涵蓋監聽埠、建立連線、讀寫資料等網路通訊的各個階段。而事件的處理者就是ChannelHandler,這樣,不但是業務邏輯,連網路通訊流程中底層的處理,都可以通過實現ChannelHandler來完成了。事實上,Netty內部的連線處理、協議編解碼、超時等機制,都是通過Handler完成的。


技術討論 & 疑問建議 & 個人部落格

版權宣告: 本部落格所有文章除特別宣告外,均採用 CC BY-NC-SA 3.0 許可協議,轉載請註明出處!

參考:https://github.com/code4craft/netty-learning/blob/master/publish/all.md

相關文章