Netty一:我和NIO不得不說的關係

Netty後端架構

先看定義:linux

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.redis

可見Netty就是基於NIO的網絡(Socket)客戶端服務端實現框架,它簡化了TCP/UDP客戶端服務端編程,開發人員再也不關注底層的Socket讀取和寫入,並且Netty提供了很多的handler(如http、mqtt、redis協議等)實現,簡化了基於網絡協議的編程複雜度。算法

啥是NIO?

NIO三件套:
  • Channel:Channel保存了socket鏈接的有關信息,以及ChannelPipeLine(串起ChannelHandlerContext)/Unsafe(實現底層傳輸)/EventLoop(對應一個IO線程)/SelectionKey(若是爲NIO模式,標識該Channel此時的鏈接讀寫事件)等有效信息,NIO服務端負責響應鏈接的是NioServerSocketChannel,客戶端爲NioSocketChannel
  • Buffer:緩衝區,用於和NIO Channel交互,從Channel中讀取數據到Buffer,從Buffer將數據寫入到Channel
  • Selector:選擇器,實現一個線程就能監聽多個Channel(Channel需先register到Selector)的讀寫等狀態,而後觸發ChannelPipeLine的fireChannelRead操做(串行ChannelHandlerContext持有的ChannelHandler)/底層Channel的數據寫入(數據來源於Buffer)

傳統的IO基於流(Stream),讀寫都是阻塞的,在讀取寫入Socket數據過程當中,線程什麼都不能作,而NIO裏面有個Selector,由它來監聽全部Channel相關的文件描述符(在linux中,設備、Socket鏈接等都對應文件描述符)狀態,這樣其餘線程(業務開發的工做線程)就能夠釋放出來,不被阻塞掉(若是涉及IO,能夠走Future異步處理),固然真正讀取數據的時候Channel對應的IO線程(在NIO中爲NioEventLoop)仍是阻塞讀寫的,但數據被保存到了Buffer中,後面的處理都是面向Buffer,再也不是面向流的了。編程

selector模型

咱們來看看Netty(NIO模式)是怎麼和NIO對應的
  • 見頂圖,處理客戶端鏈接的EventLoopGroup通常包含一個NioEventLoop,NioEventLoop即爲一個Selector(也是一個線程,負責NIO),負責處理NioServerSocketChannel的狀態監測,當有鏈接到來時,執行accept(),新建一個NioSocketChannel負責與Client端的通訊,NioSocketChannel從Worker EventLoopGroup(NioEventLoop數量根據配置生成)中選擇一個NioEventLoop register進去,該Channel後續全部的NIO操做均由該NioEventLoop負責處理

NioEventLoop繼承體系

NioEventLoop主要包含兩部分操做:後端

  • processSelectedKeys() :即selector功能
  • runAllTasks():執行任務隊列中的任務,主要是定時任務和外部工做線程添加的讀寫任務
Netty中,耗時的業務代碼能夠寫在哪?

Netty容許在非NIO線程中寫消息,若是當前線程是Channel對應的NIO線程則直接寫,若是不是,則寫消息操做會被封裝成一個WriteTask,而後再由NioEventLoop的runAllTasks()按期處理promise

相關代碼(見AbstractChannelHandlerContext.class):bash

private void write(Object msg, boolean flush, ChannelPromise promise) {
        AbstractChannelHandlerContext next = findContextOutbound();
        final Object m = pipeline.touch(msg, next);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            if (flush) {
                next.invokeWriteAndFlush(m, promise);
            } else {
                next.invokeWrite(m, promise);
            }
        } else {
            AbstractWriteTask task;
            if (flush) {
                task = WriteAndFlushTask.newInstance(next, m, promise);
            }  else {
                task = WriteTask.newInstance(next, m, promise);
            }
            safeExecute(executor, task, promise, m);
        }
    }
複製代碼

歷史文章:網絡

相關文章
相關標籤/搜索