作者:星巴刻
在 Netty NIO 編程中州叠,NioEventLoop 是一個(gè)核心類后众,發(fā)揮著極其重要的作用,要深入 Netty 的核心祟昭,必須深刻地對(duì)這個(gè)類進(jìn)行探究和理解缕坎。
服務(wù)端
在服務(wù)端程序中有兩類 NioEventLoop。一類稱為 parent (也稱 boss)篡悟,這一類 NioEventLoop 一般也就只有一個(gè)谜叹,專門負(fù)責(zé)發(fā)現(xiàn)客戶端連接。另一類是 child (也稱 worker)搬葬,這一類 NioEventLoop 要設(shè)置有限的若干個(gè)荷腊,默認(rèn)的個(gè)數(shù)只是為 CPU 核數(shù)的 2 倍,它負(fù)責(zé)處理客戶端連接的信息讀寫(xiě)急凰。使用 NIO 模式的服務(wù)端程序女仰,child 的個(gè)數(shù)可遠(yuǎn)遠(yuǎn)小于客戶端連接數(shù)。作為 parent 或者 child 的 NioEventLoop 都可以注冊(cè)不限制一個(gè)的 Channel 實(shí)例進(jìn)行服務(wù)抡锈。
parent 要負(fù)責(zé)的是表示服務(wù)端偵聽(tīng)端口的 NioServerSocketChannel 實(shí)例疾忍,NioServerSocketChannel 實(shí)例只有一個(gè)。把這個(gè) NioServerSocketChannel 注冊(cè)到 parent 后床三,parent 就開(kāi)始負(fù)責(zé)發(fā)現(xiàn)該 NioServerSocketChannel 上新的客戶端連接一罩,觸發(fā)對(duì)新來(lái)的客戶端連接進(jìn)行初始化工作,引導(dǎo)到后續(xù)的信息讀寫(xiě)等處理程序撇簿。
child 要負(fù)責(zé)的是表示客戶端連接的 NioSocketChannel 實(shí)例擒抛。NioSocketChannel 實(shí)例和客戶端連接數(shù)一一對(duì)應(yīng),因此程序中同時(shí)會(huì)有很多 NioSocketChannel 實(shí)例补疑。由于 child 數(shù)量有限(8 核 CPU 下默認(rèn)是 16 個(gè) child)歧沪,因此一個(gè) child 要同時(shí)負(fù)責(zé)多個(gè) NioSocketChannel,發(fā)現(xiàn)這些連接的可讀可寫(xiě)事件莲组,觸發(fā)應(yīng)用程序從系統(tǒng)緩沖區(qū)讀取字節(jié)流诊胞、對(duì)消息進(jìn)行編解碼、調(diào)用邏輯程序處理、繼續(xù)對(duì)先前中斷的系統(tǒng)緩沖區(qū)的寫(xiě)入等撵孤。
最簡(jiǎn)單地說(shuō)迈着,NioEventLoop 的首要職責(zé)就是為注冊(cè)在它上的 channels 服務(wù),發(fā)現(xiàn)這些 channels 上發(fā)生的新連接事件邪码、讀寫(xiě)等 I/O 事件裕菠,然后將事件轉(zhuǎn)交 channel 流水線處理。
下表是一個(gè)服務(wù)端程序的一個(gè)簡(jiǎn)單快照闭专。每一行代表一個(gè) NioEventLoop奴潘,第一行是 parent,負(fù)責(zé)處理NioServerSocketChannel影钉。隨后是16行的 child画髓,每一個(gè) child 負(fù)責(zé)多個(gè)NioSocketChannel。
隨著程序的進(jìn)行平委,表格的行數(shù)并不會(huì)變化奈虾,但是每行的 channels 會(huì)隨著連接的建立和斷開(kāi)不斷地變化著。Netty 并不保證每個(gè) NioEventLoop 負(fù)責(zé)的 channels 個(gè)數(shù)要進(jìn)行均衡廉赔, Netty 對(duì)新建立的連接采用簡(jiǎn)單的尋找下一個(gè) NioEventLoop 的策略肉微,并且在連接斷開(kāi)后也不會(huì)進(jìn)行重新分布;或許某些極端情況下蜡塌,可能出現(xiàn)某些 NioEventLoop 負(fù)責(zé)的 channels 比其他 NioEventLoop 負(fù)責(zé)的要多很多浪册,但這似乎不是問(wèn)題。
說(shuō)完服務(wù)端說(shuō)客戶端
客戶端比服務(wù)端簡(jiǎn)單岗照,客戶端程序只有一類? NioEventLoop村象,直接就是 parent ,沒(méi)有 child攒至。一般地厚者,由于客戶端和服務(wù)端只保留一個(gè)連接,所以只有一個(gè) channel迫吐,即一個(gè) parent 只負(fù)責(zé) NioEventChannel 的 I/O 事件库菲。但對(duì)于需要同一個(gè)服務(wù)端保持多個(gè)連接的,或者需要和多個(gè)服務(wù)端保持連接的志膀,則程序里依然會(huì)存在多個(gè) NioEventChannel 實(shí)例熙宇,但在實(shí)踐上還是建議這些不同的的連接使用同一個(gè) NioEventLoop,即都統(tǒng)一歸到 parent 負(fù)責(zé):
下一個(gè)問(wèn)題:NioEventLoop 是怎么發(fā)現(xiàn)其所負(fù)責(zé)的 channels 發(fā)生了 I/O 事件烫止?
2017-11-18