-
Netty 核心的幾個(gè)概念
1. 一個(gè)EventLoopGroup當(dāng)中包含一個(gè)或多個(gè)EventLoop
2. 一個(gè)EventLoop在它的整個(gè)生命周期當(dāng)中都只會(huì)與唯一一個(gè)Thread進(jìn)行綁定
3. 所有由EventLoop所處理的各種I/O事件都將在它所關(guān)聯(lián)的那個(gè)Thread上進(jìn)行處理
4. 一個(gè)Channel在它的整個(gè)生命周期中只會(huì)注冊(cè)在一個(gè)EventLoop上
5. 一個(gè)EventLoop在運(yùn)行過程當(dāng)中,會(huì)被分配到多個(gè)Channel
- 結(jié)論:
1. 在Netty中,Channel的實(shí)現(xiàn)一定是線程安全的,基于此,我們可以存儲(chǔ)一個(gè)Channel的引用,并且在需要向遠(yuǎn)端發(fā)送數(shù)據(jù)時(shí),通過整個(gè)引用來調(diào)用Channel的相應(yīng)方法;即便當(dāng)時(shí)有很多線程都在使用它也不會(huì)出現(xiàn)線程問題;而且消息一定會(huì)按照順序發(fā)送出去。
2. 我們?cè)跇I(yè)務(wù)開發(fā)中,不要將長時(shí)間執(zhí)行的耗時(shí)任務(wù)放入到EventLoop的執(zhí)行隊(duì)列中,因?yàn)樗鼘?huì)一直阻塞該線程所對(duì)應(yīng)的所有Channel上的其他執(zhí)行任務(wù),如果我們需要進(jìn)行阻塞調(diào)用或是耗時(shí)的操作,那么我們就需要使用一個(gè)專門的EventExecutor(業(yè)務(wù)線程池)
3. JDK所提供的Future只能通過手工的方式檢查執(zhí)行結(jié)果,而這個(gè)操作是會(huì)阻塞的;Netty則對(duì)ChannelFuture進(jìn)行了增強(qiáng),通過ChannelFutureListener以回調(diào)的方式獲取結(jié)果,去除了手工檢查的操作(觀察者模式);值得注意的是:ChannelFutureListener的operationComplete方法是由I/O線程執(zhí)行的,因此要注意的是不要在這里執(zhí)行耗時(shí)的操作,否則需要通過另外的線程或線程池來執(zhí)行。
4. 在Netty中有兩種發(fā)送消息的方式,可以直接寫到Channel中,也可以寫到ChannelHandler所關(guān)聯(lián)的那個(gè)ChannelHandlerContext中。對(duì)于前一種方式來說,消息會(huì)從ChannelPipline的末尾開始流動(dòng);對(duì)于后一種方式來說,消息將從ChannelPipline中的下一個(gè)ChannelHandler開始流動(dòng)。
5. ChannelHandlerContext與ChannelHandler之間的關(guān)聯(lián)綁定關(guān)系是永遠(yuǎn)都不會(huì)發(fā)生改變的,因此對(duì)其進(jìn)行緩存是沒有任何問題的。
6. 對(duì)于Channel的同名方法來說,ChannelHandlerContext的方法將會(huì)產(chǎn)生更短的事件流,所以我們應(yīng)該在可能的情況下利用這個(gè)特性來提升應(yīng)用的性能。
7. 在實(shí)際的開發(fā)中我們經(jīng)常會(huì)遇到一個(gè)服務(wù)端可能會(huì)去要調(diào)用另外一個(gè)客戶端,這時(shí)這個(gè)服務(wù)端的角色就相當(dāng)于即作為服務(wù)端也作為客戶端。這時(shí)我們需要注意在我們作為客戶端時(shí)我們應(yīng)該將對(duì)服務(wù)端和客戶端的channel綁定在同一個(gè)eventLoop上;
- Netty 提供的三種緩沖區(qū)類型
1. heap buffer 堆緩沖區(qū)
- 優(yōu)點(diǎn):由于數(shù)據(jù)是存儲(chǔ)在JVM的堆中,因此可以快速的創(chuàng)建于快速的釋放,并且他提供了直接訪問內(nèi)部字節(jié)數(shù)組的方法
- 缺點(diǎn):每次的讀寫操作,都需要先將數(shù)據(jù)復(fù)制到直接緩沖區(qū)中在進(jìn)行網(wǎng)絡(luò)傳輸
2. direct buffer 直接緩沖區(qū)(在堆之外直接分配內(nèi)存空間,直接緩沖區(qū)不會(huì)占用堆的容量空間,因?yàn)樗怯刹僮飨到y(tǒng)在本地內(nèi)存進(jìn)行的數(shù)據(jù)分配)
- 優(yōu)點(diǎn):在使用Sockte進(jìn)行數(shù)據(jù)傳遞時(shí),性能非常好,因?yàn)閿?shù)據(jù)直接位于操作系統(tǒng)的本地內(nèi)存中,所以不需要從JVM將數(shù)據(jù)復(fù)制到直接緩沖區(qū),性能很好。
- 缺點(diǎn):因?yàn)镈irect Buffer是直接在操作系統(tǒng)內(nèi)存中,所以內(nèi)存空間的分配與釋放要比堆空間更加復(fù)雜,而且速度慢一些。(Netty通過提供內(nèi)存池來解決這個(gè)問題)
- 注意:直接緩沖區(qū)不支持通過字節(jié)數(shù)組的方式來直接訪問數(shù)據(jù)(對(duì)于后端的業(yè)務(wù)消息的編解碼來說,推薦使用HeapByteBuf;對(duì)于I/O通信線程在讀寫緩沖區(qū)時(shí),推薦使用DirectByteBuf)
3. composite buffer 復(fù)合緩沖區(qū)
- JDK的ByteBuffer和Netty的ByteBuf的差異比對(duì)
1. Netty的ByteBuf采用讀寫索引分離的策略(readerIndex與writerIndex),一個(gè)初始化(里面尚未有任何數(shù)據(jù))的ByteBuf的readerIndex與witerIndex值都為0
2. 當(dāng)讀索引和寫索引處于同一個(gè)位置時(shí),如果我們繼續(xù)讀取,那么就會(huì)拋出IndexOutofBoundsException
3. 對(duì)于ByteBuf的任何讀寫操作都會(huì)分別單獨(dú)維護(hù)讀索引與寫索引。maxCapacity最大的容量默認(rèn)是 Integer.MAX_VALUE。- JDK的ByteBuffer的缺點(diǎn) 1. final byte[] hb;這是JDK的ByteBuffer對(duì)象中用于存儲(chǔ)數(shù)據(jù)的對(duì)象聲明;可以看到,其字節(jié)數(shù)組是被聲明為final的,也就是長度是固定不變的。一旦分配好就不能動(dòng)態(tài)擴(kuò)容與收縮。而且當(dāng)待存儲(chǔ)的數(shù)據(jù)字節(jié)很大時(shí)就很有可能出現(xiàn) IndexOutofBoundsException 。如果需要預(yù)防這個(gè)異常,那就需要在存儲(chǔ)之前完全確定好待存儲(chǔ)的字節(jié)大小。如果ByteBuffer的空間不足,我們只有一種解決方案;創(chuàng)建一個(gè)全新的ByteBuffer對(duì)象,然后將之間的ByteBuffer中的數(shù)據(jù)復(fù)制過去,這一切的操作都需要開發(fā)者自己手動(dòng)完成。 2. ByteBuffer只使用一個(gè)position指針來標(biāo)識(shí)位置信息,在進(jìn)行讀寫切換時(shí)就需要調(diào)用flip方法或是rewind方法,使用起來不方便。 - Netty的ByteBuf的優(yōu)點(diǎn) 1. 存儲(chǔ)的字節(jié)數(shù)組是動(dòng)態(tài)的,其最大值的默認(rèn)是Integer.MAX_VALUE。這里的動(dòng)態(tài)性體現(xiàn)在write方法中的。write方法在執(zhí)行時(shí)會(huì)判斷buffer的容量,如果不足則自動(dòng)擴(kuò)容。 2. ByteBuf的讀寫索引是完全分開的,使用起來就很方便。 - 引用計(jì)數(shù) 1. netty采用自旋鎖的方式來進(jìn)行操作(io.netty.util.AbstractReferenceCounted) ```java // 更新特定的字段 private static final AtomicIntegerFieldUpdater<AbstractReferenceCounted> refCntUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCounted.class, "refCnt"); private volatile int refCnt = 1; ... private ReferenceCounted retain0(int increment) { for (;;) { int refCnt = this.refCnt; final int nextCnt = refCnt + increment; // Ensure we not resurrect (which means the refCnt was 0) and also that we encountered an overflow. // 這里的判斷有兩個(gè)意義 // nextCnt==increment 表示refCnt=0 這在netty中對(duì)于引用計(jì)數(shù)的定義是:如果一個(gè)對(duì)象的引用計(jì)數(shù)為0則這個(gè)引用對(duì)象不能使用 // nextCnt < increment 成立則表示 nextCnt是負(fù)數(shù) 說明已經(jīng)超過最大的整數(shù)值了 if (nextCnt <= increment) { throw new IllegalReferenceCountException(refCnt, increment); } if (refCntUpdater.compareAndSet(this, refCnt, nextCnt)) { break; } } return this; } ```- AtomicIntegerFieldUpdater 要點(diǎn)總結(jié)
1. 更新器更新的必須是int類型變量,不能是其包裝類型
2. 更新器更新的必須是 volatile類型變量,確保線程之間共享變量時(shí)的立即可見性。
3. 變量不能是static的,必須是實(shí)例變量。因?yàn)閁nsafe.objectFiledOffset()方法不支持靜態(tài)變量(CAS操作本質(zhì)上是通過對(duì)象實(shí)例的偏移量來直接進(jìn)行賦值)
4. 更新器只能修改它可見范圍的變量,因?yàn)楦缕魇峭ㄟ^反射來得到這個(gè)變量,如果變量不可見就會(huì)報(bào)錯(cuò)。
5. 如果需要更新的變量時(shí)包裝類型或者是其他類型,可以使用 AtomicReferenceFieldUpdater來進(jìn)行更新
3. Netty內(nèi)存泄漏檢測
4. Netty的處理器和編解碼器
1. Netty的處理器分為兩類 入站處理器、出站處理器
2. 入站處理器的頂層是 ChannelInboundHandler,出站處理器的頂層是ChannelOutboundHandler
3. 數(shù)據(jù)處理時(shí)常用的各種編解碼器本質(zhì)上都是處理器。
4. 編解碼器:編碼器,解碼器。無論我們想網(wǎng)絡(luò)中寫入的數(shù)據(jù)是什么類型(int,char,String,二進(jìn)制等),數(shù)據(jù)在網(wǎng)絡(luò)中傳遞時(shí),其都是以字節(jié)流的形式呈現(xiàn)的;將數(shù)據(jù)由原來的形式轉(zhuǎn)換為字節(jié)流的操作稱為編碼(encode),將數(shù)據(jù)由字節(jié)轉(zhuǎn)換成它原本的格式或是其他格式的操作稱為解碼(decode),編解碼統(tǒng)一稱為codec。
5. 編碼:本質(zhì)上是一種出站處理器。因此,編碼一定是 ChannelOutboundHandler。
6. 解碼:本質(zhì)上是一種入站處理器,因此解碼一定是 ChannelInboundHandler。
7. 在Netty中,編碼器通常以 XXXEncoder命名,解碼器通常以XXXDecoder命名。
8. TCP粘包與拆包
5. 結(jié)論:
1. 無論是編碼器還是解碼器,其所接收的消息類型必須要與待處理的參數(shù)類型一致,否則該編碼器或解碼器并不會(huì)被執(zhí)行。
2. 在解碼器進(jìn)行數(shù)據(jù)解碼時(shí),一定要記得判斷緩沖(ByteBuf)中的數(shù)據(jù)是否足夠,否則將會(huì)產(chǎn)生一些問題。
- AtomicIntegerFieldUpdater 要點(diǎn)總結(jié)
Netty-2
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 原文地址:http://netty.io/wiki/reference-counted-objects.html ...
- 前言 本篇文章主要分析Netty的系統(tǒng)結(jié)構(gòu)以及其如何實(shí)現(xiàn)其對(duì)外宣稱的特色,如果還未了解Netty的基礎(chǔ)知識(shí),最好先...
- 10月26號(hào)星期六今天是上中周末的第二天,我們集體被下課。剛還沉浸在今天練習(xí)的收獲中,全體下課來的這么突然,先是有...
- 妻發(fā)現(xiàn)夫有段時(shí)間里不對(duì)勁,有時(shí)在下班點(diǎn)接她電話不慌不忙,沒多久便回到家。有時(shí)卻隨便應(yīng)付一句半句掛斷電話,讓她一頭霧...