【轉】netty-mina對比一

Netty-Mina深刻學習與對比(一)

分類:

目錄(?)[+]html

Netty-Mina深刻學習與對比(一)

分享到:6

感謝支付寶同事[易鴻偉]在本站發佈此文。java

這博文的系列主要是爲了更好的瞭解一個完整的nio框架的編程細節以及演進過程,我選了同父(Trustin Lee)的兩個框架netty與mina作對比。版本涉及了netty3.x、netty4.x、mina1.x、mina2.x、mina3.x。這裏 並無寫netty5.x的細節,看了netty5的修改文檔,彷佛有一些比較有意思的改動,準備單獨寫一篇netty4.x與netty5.x的不一樣。
react

netty從twitter發佈的這篇《Netty 4 at Twitter: Reduced GC Overhead》 文章讓國內Java界爲之一振,也小火了一把,同時netty的社區發展也不錯,版本迭代很是快,半年不關注大、小版本就發了好幾輪了。可是mina就有 點淡了,github上面它最後大多數代碼最後的修改日期均在2013年,不過我從我的情感上仍是挺喜歡mina3的代碼,沒有太多的用不上的功能(支持 各類協議啥的),跑自帶的benchmark性能也比netty4好一些。可是若是是生產用的話,就偏向netty多一些了,畢竟社區活躍,版本迭代也 快。git

1. mina、netty的線程模型

mina與netty都是Trustin Lee的做品,因此在不少方面都十分類似,他們線程模型也是基本一致,採用了Reactors in threads模型,即Main Reactor + Sub Reactors的模式。由main reactor處理鏈接相關的任務:accept、connect等,當鏈接處理完畢並創建一個socket鏈接(稱之爲session)後,給每一個 session分配一個sub reactor,以後該session的全部IO、業務邏輯處理均交給了該sub reactor。每一個reactor均是一個線程,sub reactor中只靠內核調度,沒有任何通訊且互不打擾。github

在我本身的博客裏面[Netty 4.x學習筆記 – 線程模型]也對netty的線程模型有必定的介紹。如今來說講我對線程模型演進的一些理解:編程

  • Thread per Connection: 在 沒有nio以前,這是傳統的java網絡編程方案所採用的線程模型。即有一個主循環,socket.accept阻塞等待,當創建鏈接後,建立新的線程/ 從線程池中取一個,把該socket鏈接交由新線程全權處理。這種方案優缺點都很明顯,優勢即實現簡單,缺點則是方案的伸縮性受到線程數的限制。
  • Reactor in Single Thread: 有 了nio後,能夠採用IO多路複用機制了。咱們抽取出一個單線程版的reactor模型,時序圖見下文,該方案只有一個線程,全部的socket鏈接均注 冊在了該reactor上,由一個線程全權負責全部的任務。它實現簡單,且不受線程數的限制。這種方案受限於使用場景,僅適合於IO密集的應用,不太適合 CPU密集的應用,且適合於CPU資源緊張的應用上。

reactor-single-thread

  • Reactor + Thread Pool: 方案2因爲受限於使用場景,但爲了能夠更充分的使用CPU資源,抽取出一個邏輯處理線程池。reactor僅負責IO任務,線程池負責全部其它邏輯的處理。雖然該方案能夠充分利用CPU資源,可是這個方案多了進出thread pool的兩次上下文切換。

reactor-thread-pool

  • Reactors in threads: 基 於方案3缺點的考慮,將reactor分紅兩個部分。main reactor負責鏈接任務(accept、connect等),sub reactor負責IO、邏輯任務,即mina與netty的線程模型。該方案適應性十分強,能夠調整sub reactor的數量適應CPU資源緊張的應用;同時CPU密集型任務時,又能夠在業務處理邏輯中將任務交由線程池處理,如方案5。該方案有一個不太明顯 的缺點,即session沒有分優先級,全部session平等對待均分到全部的線程中,這樣可能會致使優先級低耗資源的session堵塞高優先級的 session,但彷佛netty與mina並無針對這個作優化。

reactors in threads

  • Reactors in threads + Threads pool: 這也是我所在公司應用框架採用的模型,能夠更爲靈活的適應全部的應用場景:調整reactor數量、調整thread pool大小等。

reactors-in-threads-thread-pool

以上圖片及總結參考:《Linux多線程服務端編程》網絡

 

2. mina、netty的任務調度粒度

mina、netty在線程模型上並無太大的差別性,主要的差別仍是在任務調度的粒度的不一樣。任務從邏輯上我給它分爲成三種類型:鏈接相關的任務 (bind、connect等)、寫任務(write、flush)、調度任務(延遲、定時等),讀任務則由selector加循環時間控制了。 mina、netty任務調度的趨勢是逐漸變小,從session級別的調度 -> 類型級別任務的調度 -> 任務的調度。session

代碼

  • mina-1.1.7: SocketIoProcessor$Worker.run
  • mina-2.0.4: AbstractPollingIoProcessor$Processor.run
  • mina-3.0.0.M3-SNAPSHOT: AbstractNioSession.processWrite
  • netty-3.5.8.Final: AbstractNioSelector.run
  • netty-4.0.6.Final: NioEventLoop.run

分析

mina一、2的任務調度粒度爲session。mina會將有IO任務的的session寫入隊列中,當循環執行任務時,則會輪詢全部的session,並依次把session中的全部任務取出來運行。這樣粗粒度的調度是不公平調度,會致使某些請求的延遲很高。多線程

mina3的模型改動比較大,代碼相對就比較難看了,我僅是隨便掃了一下,它僅提煉出了writeQueue。框架

而netty3的調度粒度則是按照IO操做,分紅了registerTaskQueue、writeTaskQueue、eventQueue三個隊列, 當有IO任務時,依次processRegisterTaskQueue、processEventQueue、 processWriteTaskQueue、processSelectedKeys(selector.selectedKeys)。

netty4可能以爲netty3的粒度仍是比較粗,將隊列細分紅了taskQueue和delayedTaskQueue,全部的任務均放在 taskQueue中,delayedTaskQueue則是定時調度任務,且netty4能夠靈活配置task與selectedKey處理的時間比 例。

BTW: netty3.6.0以後,全部的隊列均合併成了一個taskQueue

有意思的是,netty4會優先處理selectedKeys,而後再處理任務,netty3則相反。mina一、2則是先處理新建的session,再處理selectedKeys,再處理任務。

難道selectedKeys處理順序有講究麼?

(全文完)若是您喜歡此文請點贊,分享,評論。

相關文章
相關標籤/搜索