图灵学院Java架构师五期笔记
緣起
日前在看netty的工作原理,對netty的線程模型很是不能理解,查閱了諸多資料,終于有了一些眉目。特此記錄,以備查閱。
閱讀對象
netty中的NIO編程模型是基于java Nio的封裝,所以需要讀者對java NIO有一定的了解,篇幅所限,本文不會對NIO再做詳述,有需要的讀者可以查看??JAVA BIO,NIO,AIO詳解(附代碼實現(xiàn))以及Netty的簡介??
Netty的NIO線程模型
說netty的線程模型之前,先說傳統(tǒng)NIO的使用方式中的關(guān)鍵代碼
可以看到是當(dāng)前線程獲得了客戶端的連接之后再重新把channel注冊到selector上,同時把事件注冊為讀,這樣就可以開始讀消息了。也就是說獲取tcp連接和讀取消息都是在同一個線程里面處理的。那么這種方式有什么問題呢?對于一些小流量應(yīng)用場景,可以使用單線程模型。但是對于高負載、大并發(fā)的應(yīng)用場景卻不合適,主要原因如下:
一個 NIO 線程同時處理成百上千的鏈路,性能上無法支撐,即便 NIO 線程的 CPU 負荷達到 100%,也無法滿足海量消息的編碼、解碼、讀取和發(fā)送;
當(dāng) NIO 線程負載過重之后,處理速度將變慢,這會導(dǎo)致大量客戶端連接超時,超時之后往往會進行重發(fā),這更加重了 NIO 線程的負載,最終會導(dǎo)致大量消息積壓和處理超時,成為系統(tǒng)的性能瓶頸;
可靠性問題:一旦 NIO 線程意外跑飛,或者進入死循環(huán),會導(dǎo)致整個系統(tǒng)通信模塊不可用,不能接收和處理外部消息,造成節(jié)點故障。
那么你可能會想,既然一個線程不行,那我在讀取消息的時候采用線程池不就可以了嗎?的確是可行的,事實上,在Netty中也確實是這么做的。
netty的一個啟動程序如下
可以看到開頭new了兩個EventLoopGroup,EventLoopGroup可以暫時理解為一個線程組。其中bossGroup負責(zé)處理客戶端的 TCP 連接請求,如果系統(tǒng)只有一個服務(wù)端端口需要監(jiān)聽,則建議 bossGroup 線程組線程數(shù)設(shè)置為 1,workerGroup 是真正負責(zé) I/O 讀寫操作的線程組
先看一張netty的執(zhí)行流程圖
圖中可以看到boosGroup在接收到請求后會重新注冊到workerGroup上,也就是對應(yīng)了前面說的bossGroup負責(zé)處理客戶端的 TCP 連接請求,而workerGroup是真正負責(zé) I/O 讀寫操作的線程組。就像軟件開發(fā)里面的boss負責(zé)分配任務(wù),而worker即程序員負責(zé)寫代碼。那么bossGroup是如何處理tcp的連接請求同時把他注冊到workerGroup上的呢?
bossGroup是如何分配任務(wù)的
workerGroup中的每一個線程,都有一個多路復(fù)用器 Selector,bossGroup每接收到一個客戶端連接,就會從workerGroup選擇一個線程然后把channel注冊到它的Selector上。
偽代碼實現(xiàn)
boss中的代碼
可以看到,bossGroup接收到了新客戶端的請求后,就會調(diào)用一個算法,從多個worker中選取一個worker,然后調(diào)用worker的注冊方法,把這個新客戶端的channel注冊上去。我們再看workerGroup中的注冊方法實現(xiàn)
可以看到,就是把新的channel注冊到自己的Selector上,注冊好后就會觸發(fā)workerGroup的堵塞代碼塊,這樣這個workerGroup中的這個線程就會開始讀取數(shù)據(jù),下面看看worker線程讀取數(shù)據(jù)的偽代碼實現(xiàn)(其實就是普通的NIO中讀取數(shù)據(jù)的方式)
總結(jié):bossGroup負責(zé)處理客戶端的 TCP 連接請求,bossGroup每接收到一個客戶端連接,就會從workerGroup選擇一個線程然后把channel注冊到它的Selector上,這樣的話請求接收和請求處理就通過不同的線程分開了,這也是netty高效的原因之一。當(dāng)然Netty高效的原因絕不僅僅是由于優(yōu)秀的線程模型的設(shè)計,與Netty的編碼協(xié)議,virtual buffer,以及Zero-Copy(零拷貝)也息息相關(guān) 。
總結(jié)
以上是生活随笔為你收集整理的图灵学院Java架构师五期笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows的进程创建和映像装入
- 下一篇: 记一次CentOS7因Redis配置不当