面試必問的Netty框架知識匯總

1.BIO擅这、NIO和AIO的區(qū)別仲翎?

  • BIO:一個連接一個線程溯香,客戶端有連接請求時服務器端就需要啟動一個線程進行處理玫坛。線程開銷大湿镀。
    偽異步IO:將請求連接放入線程池勉痴,一對多蒸矛,但線程還是很寶貴的資源雏掠。

  • NIO:一個請求一個線程磁玉,但客戶端發(fā)送的連接請求都會注冊到多路復用器上蚊伞,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理时迫。

  • AIO:一個有效請求一個線程掠拳,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理溺欧,

  • BIO是面向流的姐刁,NIO是面向緩沖區(qū)的聂使;BIO的各種流是阻塞的柏靶。而NIO是非阻塞的屎蜓;BIO的Stream是單向的梆靖,而NIO的channel是雙向的返吻。

  • NIO的特點:事件驅(qū)動模型测僵、單線程處理多任務捍靠、非阻塞I/O榨婆,I/O讀寫不再阻塞磁携,而是返回0、基于block的傳輸比基于流的傳輸更高效良风、更高級的IO函數(shù)zero-copy谊迄、IO多路復用大大提高了Java網(wǎng)絡應用的可伸縮性和實用性⊙萄耄基于Reactor線程模型统诺。

  • 在Reactor模式中,事件分發(fā)器等待某個事件或者可應用或個操作的狀態(tài)發(fā)生粮呢,事件分發(fā)器就把這個事件傳給事先注冊的事件處理函數(shù)或者回調(diào)函數(shù),由后者來做實際的讀寫操作钞艇。如在Reactor中實現(xiàn)讀:注冊讀就緒事件和相應的事件處理器啄寡、事件分發(fā)器等待事件、事件到來哩照,激活分發(fā)器这难,分發(fā)器調(diào)用事件對應的處理器、事件處理器完成實際的讀操作葡秒,處理讀到的數(shù)據(jù)姻乓,注冊新的事件,然后返還控制權眯牧。

2.NIO的組成蹋岩?

  • Buffer:與Channel進行交互,數(shù)據(jù)是從Channel讀入緩沖區(qū)学少,從緩沖區(qū)寫入Channel中的

    • flip方法 : 反轉(zhuǎn)此緩沖區(qū)剪个,將position給limit,然后將position置為0版确,其實就是切換讀寫模式
    • clear方法 :清除此緩沖區(qū)扣囊,將position置為0,把capacity的值給limit绒疗。
    • rewind方法 : 重繞此緩沖區(qū)侵歇,將position置為0
  • DirectByteBuffer可減少一次系統(tǒng)空間到用戶空間的拷貝。但Buffer創(chuàng)建和銷毀的成本更高吓蘑,不可控惕虑,通常會用內(nèi)存池來提高性能坟冲。直接緩沖區(qū)主要分配給那些易受基礎系統(tǒng)的本機I/O 操作影響的大型、持久的緩沖區(qū)溃蔫。如果數(shù)據(jù)量比較小的中小應用情況下健提,可以考慮使用heapBuffer,由JVM進行管理伟叛。

  • Channel:表示 IO 源與目標打開的連接私痹,是雙向的,但不能直接訪問數(shù)據(jù)统刮,只能與Buffer 進行交互紊遵。通過源碼可知,F(xiàn)ileChannel的read方法和write方法都導致數(shù)據(jù)復制了兩次网沾!

  • Selector可使一個單獨的線程管理多個Channel癞蚕,open方法可創(chuàng)建Selector,register方法向多路復用器器注冊通道辉哥,可以監(jiān)聽的事件類型:讀桦山、寫、連接醋旦、accept恒水。注冊事件后會產(chǎn)生一個SelectionKey:它表示SelectableChannel 和Selector 之間的注冊關系,wakeup方法:使尚未返回的第一個選擇操作立即返回饲齐,喚醒的原因是:注冊了新的channel或者事件钉凌;channel關閉,取消注冊捂人;優(yōu)先級更高的事件觸發(fā)(如定時器事件)御雕,希望及時處理。

  • Selector在Linux的實現(xiàn)類是EPollSelectorImpl滥搭,委托給EPollArrayWrapper實現(xiàn)酸纲,其中三個native方法是對epoll的封裝,而EPollSelectorImpl. implRegister方法瑟匆,通過調(diào)用epoll_ctl向epoll實例中注冊事件闽坡,還將注冊的文件描述符(fd)與SelectionKey的對應關系添加到fdToKey中,這個map維護了文件描述符與SelectionKey的映射愁溜。

  • fdToKey有時會變得非常大疾嗅,因為注冊到Selector上的Channel非常多(百萬連接);過期或失效的Channel沒有及時關閉冕象。fdToKey總是串行讀取的代承,而讀取是在select方法中進行的,該方法是非線程安全的交惯。

  • Pipe:兩個線程之間的單向數(shù)據(jù)連接次泽,數(shù)據(jù)會被寫到sink通道穿仪,從source通道讀取

  • NIO的服務端建立過程:Selector.open():打開一個Selector席爽;ServerSocketChannel.open():創(chuàng)建服務端的Channel意荤;bind():綁定到某個端口上。并配置非阻塞模式只锻;register():注冊Channel和關注的事件到Selector上玖像;select()輪詢拿到已經(jīng)就緒的事件

3.Netty的特點?

  • 一個高性能齐饮、異步事件驅(qū)動的NIO框架捐寥,它提供了對TCP、UDP和文件傳輸?shù)闹С?/li>
  • 使用更高效的socket底層祖驱,對epoll空輪詢引起的cpu占用飆升在內(nèi)部進行了處理握恳,避免了直接使用NIO的陷阱,簡化了NIO的處理方式捺僻。
  • 采用多種decoder/encoder 支持乡洼,對TCP粘包/分包進行自動化處理
  • 可使用接受/處理線程池,提高連接效率匕坯,對重連束昵、心跳檢測的簡單支持
  • 可配置IO線程數(shù)、TCP參數(shù)葛峻, TCP接收和發(fā)送緩沖區(qū)使用直接內(nèi)存代替堆內(nèi)存锹雏,通過內(nèi)存池的方式循環(huán)利用ByteBuf
  • 通過引用計數(shù)器及時申請釋放不再引用的對象,降低了GC頻率
  • 使用單線程串行化的方式术奖,高效的Reactor線程模型
  • 大量使用了volitale礁遵、使用了CAS和原子類、線程安全類的使用采记、讀寫鎖的使用

4.Netty的線程模型佣耐?

  • Netty通過Reactor模型基于多路復用器接收并處理用戶請求,內(nèi)部實現(xiàn)了兩個線程池挺庞,boss線程池和work線程池晰赞,其中boss線程池的線程負責處理請求的accept事件,當接收到accept事件的請求時选侨,把對應的socket封裝到一個NioSocketChannel中掖鱼,并交給work線程池,其中work線程池負責請求的read和write事件援制,由對應的Handler處理戏挡。

  • 單線程模型:所有I/O操作都由一個線程完成,即多路復用晨仑、事件分發(fā)和處理都是在一個Reactor線程上完成的褐墅。既要接收客戶端的連接請求,向服務端發(fā)起連接拆檬,又要發(fā)送/讀取請求或應答/響應消息。一個NIO 線程同時處理成百上千的鏈路妥凳,性能上無法支撐竟贯,速度慢,若線程進入死循環(huán)逝钥,整個程序不可用屑那,對于高負載、大并發(fā)的應用場景不合適艘款。

  • 多線程模型:有一個NIO 線程(Acceptor) 只負責監(jiān)聽服務端持际,接收客戶端的TCP 連接請求;NIO 線程池負責網(wǎng)絡IO 的操作哗咆,即消息的讀取蜘欲、解碼、編碼和發(fā)送晌柬;1 個NIO 線程可以同時處理N 條鏈路姥份,但是1 個鏈路只對應1 個NIO 線程,這是為了防止發(fā)生并發(fā)操作問題。但在并發(fā)百萬客戶端連接或需要安全認證時,一個Acceptor 線程可能會存在性能不足問題渠缕。

  • 主從多線程模型:Acceptor 線程用于綁定監(jiān)聽端口泊脐,接收客戶端連接,將SocketChannel 從主線程池的Reactor 線程的多路復用器上移除,重新注冊到Sub 線程池的線程上,用于處理I/O 的讀寫等操作,從而保證mainReactor只負責接入認證凯砍、握手等操作;

5.TCP 粘包/拆包的原因及解決方法拴竹?

  • TCP是以流的方式來處理數(shù)據(jù)悟衩,一個完整的包可能會被TCP拆分成多個包進行發(fā)送,也可能把小的封裝成一個大的數(shù)據(jù)包發(fā)送栓拜。

  • TCP粘包/分包的原因:

    • 應用程序?qū)懭氲淖止?jié)大小大于套接字發(fā)送緩沖區(qū)的大小座泳,會發(fā)生拆包現(xiàn)象,而應用程序?qū)懭霐?shù)據(jù)小于套接字緩沖區(qū)大小幕与,網(wǎng)卡將應用多次寫入的數(shù)據(jù)發(fā)送到網(wǎng)絡上挑势,這將會發(fā)生粘包現(xiàn)象;
    • 進行MSS大小的TCP分段啦鸣,當TCP報文長度-TCP頭部長度>MSS的時候?qū)l(fā)生拆包
    • 以太網(wǎng)幀的payload(凈荷)大于MTU(1500字節(jié))進行ip分片潮饱。
  • 解決方法

    • 消息定長:FixedLengthFrameDecoder類
    • 包尾增加特殊字符分割:行分隔符類:LineBasedFrameDecoder或自定義分隔符類 :DelimiterBasedFrameDecoder
    • 將消息分為消息頭和消息體:LengthFieldBasedFrameDecoder類。分為有頭部的拆包與粘包诫给、長度字段在前且有頭部的拆包與粘包香拉、多擴展頭部的拆包與粘包啦扬。

6.了解哪幾種序列化協(xié)議?

  • 序列化(編碼)是將對象序列化為二進制形式(字節(jié)數(shù)組)凫碌,主要用于網(wǎng)絡傳輸扑毡、數(shù)據(jù)持久化等;而反序列化(解碼)則是將從網(wǎng)絡证鸥、磁盤等讀取的字節(jié)數(shù)組還原成原始對象僚楞,主要用于網(wǎng)絡傳輸對象的解碼勤晚,以便完成遠程調(diào)用枉层。

  • 影響序列化性能的關鍵因素:序列化后的碼流大小(網(wǎng)絡帶寬的占用)赐写、序列化的性能(CPU資源占用)鸟蜡;是否支持跨語言(異構系統(tǒng)的對接和開發(fā)語言切換)。

  • Java默認提供的序列化:無法跨語言挺邀、序列化后的碼流太大揉忘、序列化的性能差

  • XML,優(yōu)點:人機可讀性好端铛,可指定元素或特性的名稱泣矛。缺點:序列化數(shù)據(jù)只包含數(shù)據(jù)本身以及類的結構,不包括類型標識和程序集信息禾蚕;只能序列化公共屬性和字段您朽;不能序列化方法;文件龐大换淆,文件格式復雜哗总,傳輸占帶寬。適用場景:當做配置文件存儲數(shù)據(jù)倍试,實時數(shù)據(jù)轉(zhuǎn)換讯屈。

  • JSON,是一種輕量級的數(shù)據(jù)交換格式县习,優(yōu)點:兼容性高涮母、數(shù)據(jù)格式比較簡單,易于讀寫躁愿、序列化后數(shù)據(jù)較小叛本,可擴展性好,兼容性好攘已、與XML相比炮赦,其協(xié)議比較簡單,解析速度比較快样勃。缺點:數(shù)據(jù)的描述性比XML差吠勘、不適合性能要求為ms級別的情況性芬、額外空間開銷比較大。適用場景(可替代XML):跨防火墻訪問剧防、可調(diào)式性要求高植锉、基于Web browser的Ajax請求、傳輸數(shù)據(jù)量相對小峭拘,實時性要求相對低(例如秒級別)的服務俊庇。

  • Fastjson,采用一種“假定有序快速匹配”的算法鸡挠。優(yōu)點:接口簡單易用辉饱、目前java語言中最快的json庫。缺點:過于注重快拣展,而偏離了“標準”及功能性彭沼、代碼質(zhì)量不高,文檔不全备埃。適用場景:協(xié)議交互姓惑、Web輸出、Android客戶端

  • Thrift按脚,不僅是序列化協(xié)議于毙,還是一個RPC框架。優(yōu)點:序列化后的體積小, 速度快辅搬、支持多種語言和豐富的數(shù)據(jù)類型唯沮、對于數(shù)據(jù)字段的增刪具有較強的兼容性、支持二進制壓縮編碼伞辛。缺點:使用者較少烂翰、跨防火墻訪問時,不安全蚤氏、不具有可讀性甘耿,調(diào)試代碼時相對困難、不能與其他傳輸層協(xié)議共同使用(例如HTTP)竿滨、無法支持向持久層直接讀寫數(shù)據(jù)佳恬,即不適合做數(shù)據(jù)持久化序列化協(xié)議。適用場景:分布式系統(tǒng)的RPC解決方案

  • Avro于游,Hadoop的一個子項目毁葱,解決了JSON的冗長和沒有IDL的問題。優(yōu)點:支持豐富的數(shù)據(jù)類型贰剥、簡單的動態(tài)語言結合功能倾剿、具有自我描述屬性、提高了數(shù)據(jù)解析速度、快速可壓縮的二進制數(shù)據(jù)形式前痘、可以實現(xiàn)遠程過程調(diào)用RPC凛捏、支持跨編程語言實現(xiàn)。缺點:對于習慣于靜態(tài)類型語言的用戶不直觀芹缔。適用場景:在Hadoop中做Hive坯癣、Pig和MapReduce的持久化數(shù)據(jù)格式。

  • Protobuf最欠,將數(shù)據(jù)結構以.proto文件進行描述示罗,通過代碼生成工具可以生成對應數(shù)據(jù)結構的POJO對象和Protobuf相關的方法和屬性。優(yōu)點:序列化后碼流小芝硬,性能高蚜点、結構化數(shù)據(jù)存儲格式(XML JSON等)、通過標識字段的順序吵取,可以實現(xiàn)協(xié)議的前向兼容禽额、結構化的文檔更容易管理和維護。缺點:需要依賴于工具生成代碼皮官、支持的語言相對較少,官方只支持Java 实辑、C++ 捺氢、python。適用場景:對性能要求高的RPC調(diào)用剪撬、具有良好的跨防火墻的訪問屬性摄乒、適合應用層對象的持久化

  • 其它

    • protostuff 基于protobuf協(xié)議,但不需要配置proto文件残黑,直接導包即可
    • Jboss marshaling 可以直接序列化java類馍佑, 無須實java.io.Serializable接口
    • Message pack 一個高效的二進制序列化格式
    • Hessian 采用二進制協(xié)議的輕量級remoting onhttp工具
    • kryo 基于protobuf協(xié)議,只支持java語言,需要注冊(Registration)梨水,然后序列化(Output)拭荤,反序列化(Input)

7.如何選擇序列化協(xié)議?

  • 具體場景

    • 對于公司間的系統(tǒng)調(diào)用疫诽,如果性能要求在100ms以上的服務舅世,基于XML的SOAP協(xié)議是一個值得考慮的方案。
    • 基于Web browser的Ajax奇徒,以及Mobile app與服務端之間的通訊雏亚,JSON協(xié)議是首選。對于性能要求不太高摩钙,或者以動態(tài)類型語言為主罢低,或者傳輸數(shù)據(jù)載荷很小的的運用場景,JSON也是非常不錯的選擇胖笛。
    • 對于調(diào)試環(huán)境比較惡劣的場景网持,采用JSON或XML能夠極大的提高調(diào)試效率宜肉,降低系統(tǒng)開發(fā)成本。
    • 當對性能和簡潔性有極高要求的場景翎碑,Protobuf谬返,Thrift,Avro之間具有一定的競爭關系日杈。
    • 對于T級別的數(shù)據(jù)的持久化應用場景遣铝,Protobuf和Avro是首要選擇。如果持久化后的數(shù)據(jù)存儲在hadoop子項目里莉擒,Avro會是更好的選擇酿炸。
    • 對于持久層非Hadoop項目,以靜態(tài)類型語言為主的應用場景涨冀,Protobuf會更符合靜態(tài)類型語言工程師的開發(fā)習慣填硕。由于Avro的設計理念偏向于動態(tài)類型語言,對于動態(tài)語言為主的應用場景鹿鳖,Avro是更好的選擇扁眯。
    • 如果需要提供一個完整的RPC解決方案,Thrift是一個好的選擇翅帜。
    • 如果序列化之后需要支持不同的傳輸層協(xié)議姻檀,或者需要跨防火墻訪問的高性能場景,Protobuf可以優(yōu)先考慮涝滴。
  • protobuf的數(shù)據(jù)類型有多種:bool绣版、double、float歼疮、int32杂抽、int64、string韩脏、bytes缩麸、enum、message骤素。protobuf的限定符:required: 必須賦值匙睹,不能為空、optional:字段可以賦值济竹,也可以不賦值痕檬、repeated: 該字段可以重復任意次數(shù)(包括0次)、枚舉送浊;只能用指定的常量集中的一個值作為其值梦谜;

  • protobuf的基本規(guī)則:每個消息中必須至少留有一個required類型的字段、包含0個或多個optional類型的字段;repeated表示的字段可以包含0個或多個數(shù)據(jù)唁桩;[1,15]之內(nèi)的標識號在編碼的時候會占用一個字節(jié)(常用)闭树,[16,2047]之內(nèi)的標識號則占用2個字節(jié),標識號一定不能重復荒澡、使用消息類型报辱,也可以將消息嵌套任意多層,可用嵌套消息類型來代替組单山。

  • protobuf的消息升級原則:不要更改任何已有的字段的數(shù)值標識碍现;不能移除已經(jīng)存在的required字段,optional和repeated類型的字段可以被移除米奸,但要保留標號不能被重用昼接。新添加的字段必須是optional或repeated。因為舊版本程序無法讀取或?qū)懭胄略龅膔equired限定符的字段悴晰。

  • 編譯器為每一個消息類型生成了一個.java文件慢睡,以及一個特殊的Builder類(該類是用來創(chuàng)建消息類接口的)。如:UserProto.User.Builder builder = UserProto.User.newBuilder();builder.build()铡溪;

  • Netty中的使用:ProtobufVarint32FrameDecoder 是用于處理半包消息的解碼類漂辐;ProtobufDecoder(UserProto.User.getDefaultInstance())這是創(chuàng)建的UserProto.java文件中的解碼類;ProtobufVarint32LengthFieldPrepender 對protobuf協(xié)議的消息頭上加上一個長度為32的整形字段佃却,用于標志這個消息的長度的類者吁;ProtobufEncoder 是編碼類

  • 將StringBuilder轉(zhuǎn)換為ByteBuf類型:copiedBuffer()方法

8.Netty的零拷貝實現(xiàn)?

  • Netty的接收和發(fā)送ByteBuffer采用DIRECT BUFFERS饲帅,使用堆外直接內(nèi)存進行Socket讀寫,不需要進行字節(jié)緩沖區(qū)的二次拷貝瘤泪。堆內(nèi)存多了一次內(nèi)存拷貝灶泵,JVM會將堆內(nèi)存Buffer拷貝一份到直接內(nèi)存中,然后才寫入Socket中对途。ByteBuffer由ChannelConfig分配赦邻,而ChannelConfig創(chuàng)建ByteBufAllocator默認使用Direct Buffer

  • CompositeByteBuf 類可以將多個 ByteBuf 合并為一個邏輯上的 ByteBuf, 避免了傳統(tǒng)通過內(nèi)存拷貝的方式將幾個小Buffer合并成一個大的Buffer。addComponents方法將 header 與 body 合并為一個邏輯上的 ByteBuf, 這兩個 ByteBuf 在CompositeByteBuf 內(nèi)部都是單獨存在的, CompositeByteBuf 只是邏輯上是一個整體

  • 通過 FileRegion 包裝的FileChannel.tranferTo方法 實現(xiàn)文件傳輸, 可以直接將文件緩沖區(qū)的數(shù)據(jù)發(fā)送到目標 Channel实檀,避免了傳統(tǒng)通過循環(huán)write方式導致的內(nèi)存拷貝問題惶洲。

  • 通過 wrap方法, 我們可以將 byte[] 數(shù)組、ByteBuf膳犹、ByteBuffer等包裝成一個 Netty ByteBuf 對象, 進而避免了拷貝操作恬吕。

  • Selector BUG:若Selector的輪詢結果為空,也沒有wakeup或新消息處理须床,則發(fā)生空輪詢铐料,CPU使用率100%,

  • Netty的解決辦法:對Selector的select操作周期進行統(tǒng)計,每完成一次空的select操作進行一次計數(shù)钠惩,若在某個周期內(nèi)連續(xù)發(fā)生N次空輪詢柒凉,則觸發(fā)了epoll死循環(huán)bug。重建Selector篓跛,判斷是否是其他線程發(fā)起的重建請求膝捞,若不是則將原SocketChannel從舊的Selector上去除注冊,重新注冊到新的Selector上愧沟,并將原來的Selector關閉蔬咬。

9.Netty的高性能表現(xiàn)在哪些方面?

  • 心跳央渣,對服務端:會定時清除閑置會話inactive(netty5)计盒,對客戶端:用來檢測會話是否斷開,是否重來芽丹,檢測網(wǎng)絡延遲北启,其中idleStateHandler類 用來檢測會話狀態(tài)

  • 串行無鎖化設計,即消息的處理盡可能在同一個線程內(nèi)完成拔第,期間不進行線程切換咕村,這樣就避免了多線程競爭和同步鎖。表面上看蚊俺,串行化設計似乎CPU利用率不高懈涛,并發(fā)程度不夠。但是泳猬,通過調(diào)整NIO線程池的線程參數(shù)批钠,可以同時啟動多個串行化的線程并行運行,這種局部無鎖化的串行線程設計相比一個隊列-多個工作線程模型性能更優(yōu)得封。

  • 可靠性埋心,鏈路有效性檢測:鏈路空閑檢測機制,讀/寫空閑超時機制忙上;內(nèi)存保護機制:通過內(nèi)存池重用ByteBuf;ByteBuf的解碼保護拷呆;優(yōu)雅停機:不再接收新消息、退出前的預處理操作疫粥、資源的釋放操作茬斧。

  • Netty安全性:支持的安全協(xié)議:SSL V2和V3,TLS梗逮,SSL單向認證项秉、雙向認證和第三方CA認證。

  • 高效并發(fā)編程的體現(xiàn):volatile的大量库糠、正確使用伙狐;CAS和原子類的廣泛使用涮毫;線程安全容器的使用;通過讀寫鎖提升并發(fā)性能贷屎。IO通信性能三原則:傳輸(AIO)罢防、協(xié)議(Http)、線程(主從多線程)

  • 流量整型的作用(變壓器):防止由于上下游網(wǎng)元性能不均衡導致下游網(wǎng)元被壓垮唉侄,業(yè)務流中斷咒吐;防止由于通信模塊接受消息過快,后端業(yè)務線程處理不及時導致?lián)嗡绬栴}属划。

  • TCP參數(shù)配置:SO_RCVBUF和SO_SNDBUF:通常建議值為128K或者256K恬叹;SO_TCPNODELAY:NAGLE算法通過將緩沖區(qū)內(nèi)的小封包自動相連,組成較大的封包同眯,阻止大量小封包的發(fā)送阻塞網(wǎng)絡绽昼,從而提高網(wǎng)絡應用效率。但是對于時延敏感的應用場景需要關閉該優(yōu)化算法须蜗;

10.NIOEventLoopGroup源碼硅确?

image
  • NioEventLoopGroup(其實是MultithreadEventExecutorGroup) 內(nèi)部維護一個類型為 EventExecutor children [], 默認大小是處理器核數(shù) * 2, 這樣就構成了一個線程池,初始化EventExecutor時NioEventLoopGroup重載newChild方法明肮,所以children元素的實際類型為NioEventLoop菱农。

  • 線程啟動時調(diào)用SingleThreadEventExecutor的構造方法,執(zhí)行NioEventLoop類的run方法柿估,首先會調(diào)用hasTasks()方法判斷當前taskQueue是否有元素循未。如果taskQueue中有元素,執(zhí)行 selectNow() 方法秫舌,最終執(zhí)行selector.selectNow()的妖,該方法會立即返回。如果taskQueue沒有元素足陨,執(zhí)行 select(oldWakenUp) 方法

  • select ( oldWakenUp) 方法解決了 Nio 中的 bug羔味,selectCnt 用來記錄selector.select方法的執(zhí)行次數(shù)和標識是否執(zhí)行過selector.selectNow(),若觸發(fā)了epoll的空輪詢bug钠右,則會反復執(zhí)行selector.select(timeoutMillis),變量selectCnt 會逐漸變大忘蟹,當selectCnt 達到閾值(默認512)飒房,則執(zhí)行rebuildSelector方法,進行selector重建媚值,解決cpu占用100%的bug狠毯。

  • rebuildSelector方法先通過openSelector方法創(chuàng)建一個新的selector。然后將old selector的selectionKey執(zhí)行cancel褥芒。最后將old selector的channel重新注冊到新的selector中嚼松。rebuild后嫡良,需要重新執(zhí)行方法selectNow,檢查是否有已ready的selectionKey献酗。

  • 接下來調(diào)用processSelectedKeys 方法(處理I/O任務)寝受,當selectedKeys != null時,調(diào)用processSelectedKeysOptimized方法罕偎,迭代 selectedKeys 獲取就緒的 IO 事件的selectkey存放在數(shù)組selectedKeys中, 然后為每個事件都調(diào)用 processSelectedKey 來處理它很澄,processSelectedKey 中分別處理OP_READ;OP_WRITE颜及;OP_CONNECT事件甩苛。

  • 最后調(diào)用runAllTasks方法(非IO任務),該方法首先會調(diào)用fetchFromScheduledTaskQueue方法俏站,把scheduledTaskQueue中已經(jīng)超過延遲執(zhí)行時間的任務移到taskQueue中等待被執(zhí)行讯蒲,然后依次從taskQueue中取任務執(zhí)行,每執(zhí)行64個任務肄扎,進行耗時檢查墨林,如果已執(zhí)行時間超過預先設定的執(zhí)行時間,則停止執(zhí)行非IO任務反浓,避免非IO任務太多萌丈,影響IO任務的執(zhí)行。

  • 每個NioEventLoop對應一個線程和一個Selector雷则,NioServerSocketChannel會主動注冊到某一個NioEventLoop的Selector上辆雾,NioEventLoop負責事件輪詢。

  • Outbound 事件都是請求事件, 發(fā)起者是 Channel月劈,處理者是 unsafe度迂,通過 Outbound 事件進行通知,傳播方向是 tail到head猜揪。Inbound 事件發(fā)起者是 unsafe惭墓,事件的處理者是 Channel, 是通知事件,傳播方向是從頭到尾而姐。

  • 內(nèi)存管理機制腊凶,首先會預申請一大塊內(nèi)存Arena,Arena由許多Chunk組成拴念,而每個Chunk默認由2048個page組成钧萍。Chunk通過AVL樹的形式組織Page,每個葉子節(jié)點表示一個Page政鼠,而中間節(jié)點表示內(nèi)存區(qū)域风瘦,節(jié)點自己記錄它在整個Arena中的偏移地址。當區(qū)域被分配出去后公般,中間節(jié)點上的標記位會被標記万搔,這樣就表示這個中間節(jié)點以下的所有節(jié)點都已被分配了胡桨。大于8k的內(nèi)存分配在poolChunkList中,而PoolSubpage用于分配小于8k的內(nèi)存瞬雹,它會把一個page分割成多段昧谊,進行內(nèi)存分配。

  • ByteBuf的特點:支持自動擴容(4M)挖炬,保證put方法不會拋出異常揽浙、通過內(nèi)置的復合緩沖類型,實現(xiàn)零拷貝(zero-copy)意敛;不需要調(diào)用flip()來切換讀/寫模式馅巷,讀取和寫入索引分開;方法鏈草姻;引用計數(shù)基于AtomicIntegerFieldUpdater用于內(nèi)存回收钓猬;PooledByteBuf采用二叉樹來實現(xiàn)一個內(nèi)存池,集中管理內(nèi)存的分配和釋放撩独,不用每次使用都新建一個緩沖區(qū)對象敞曹。UnpooledHeapByteBuf每次都會新建一個緩沖區(qū)對象。

文章轉(zhuǎn)載自: https://www.cnblogs.com/duan2/p/8819910.html

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末综膀,一起剝皮案震驚了整個濱河市澳迫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剧劝,老刑警劉巖橄登,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異讥此,居然都是意外死亡拢锹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門萄喳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卒稳,“玉大人,你說我怎么就攤上這事他巨〕淇樱” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵染突,是天一觀的道長匪傍。 經(jīng)常有香客問我,道長觉痛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任茵休,我火速辦了婚禮薪棒,結果婚禮上手蝎,老公的妹妹穿的比我還像新娘。我一直安慰自己俐芯,他們只是感情好棵介,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吧史,像睡著了一般邮辽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贸营,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天吨述,我揣著相機與錄音,去河邊找鬼钞脂。 笑死揣云,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的冰啃。 我是一名探鬼主播邓夕,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阎毅!你這毒婦竟也來了焚刚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤扇调,失蹤者是張志新(化名)和其女友劉穎矿咕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肃拜,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡痴腌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了燃领。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片士聪。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖猛蔽,靈堂內(nèi)的尸體忽然破棺而出剥悟,到底是詐尸還是另有隱情,我是刑警寧澤曼库,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布区岗,位于F島的核電站,受9級特大地震影響毁枯,放射性物質(zhì)發(fā)生泄漏慈缔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一种玛、第九天 我趴在偏房一處隱蔽的房頂上張望藐鹤。 院中可真熱鬧瓤檐,春花似錦、人聲如沸娱节。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肄满。三九已至谴古,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間稠歉,已是汗流浹背掰担。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留轧抗,地道東北人恩敌。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像横媚,于是被迫代替她去往敵國和親纠炮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容