一文搞定Netty寫數(shù)據(jù)高性能原理
? 點擊上方“JavaEdge”,關(guān)注公眾號

1 寫數(shù)據(jù)的核心問題

| 快遞場景(包裹) | Netty寫數(shù)據(jù)(數(shù)據(jù)) |
|---|---|
| 攬收到倉庫 | write:寫到一個buffer |
| 從倉庫發(fā)貨 | flush:把buffer里的數(shù)據(jù)發(fā)送出去 |
| 攬收到倉庫并立馬發(fā)貨( 加急件) | writeAndFlush: 寫到buffer, 立馬發(fā)送 |
| 攬收與發(fā)貨之間有個緩沖的倉庫 | Write和Flush之間有個ChannelOutboundBuffer |
1.1 寫炸了

對方倉庫爆倉時,送不了的時候,會停止送,協(xié)商等電話通知什么時候好了,再送。
Netty寫數(shù)據(jù),寫不進去時,會停止寫,然后注冊一個 OP_WRITE事件,來通知什么時候可以寫進去了再寫。
1.2 挺能寫的

發(fā)送快遞時,對方倉庫都直接收下,這個時候再發(fā)送快遞時,可以嘗試發(fā)送更多的快遞試試,這樣效果更好。
Netty批量寫數(shù)據(jù)時,如果嘗試寫的都寫進去了,接下來會嘗試寫更多(調(diào)整maxBytesPerGatheringWrite)
1.3 我還能寫

發(fā)送快遞時,發(fā)到某個地方的快遞特別多,我們會連續(xù)發(fā),但是快遞車畢竟有限,也會考慮下其他地方
Netty只要有數(shù)據(jù)要寫,且能寫的出去,則一直嘗試,直到寫不出去或滿16次(writeSpinCount)
寫16次還沒有寫完,就直接 schedule 一個 task 來繼續(xù)寫,而不是用注冊寫事件來觸發(fā),更簡潔有力。
1.4 寫不過來了

攬收太多,發(fā)送來不及時,爆倉,這個時候會出個告示牌:收不下了,最好過2天再來郵寄吧。
Netty待寫數(shù)據(jù)太多,超過一定的水位線(writeBufferWaterMark.high()) ,會將可寫的標志位改成 false,讓應用端自己做決定要不要發(fā)送數(shù)據(jù)(寫)了(很真實,將責任推給用戶)。

2 核心流程


Write - 寫數(shù)據(jù)到buffer :
ChannelOutboundBuffer#addMessage
Flush -發(fā)送buffer里面的數(shù)據(jù):
AbstractChannel.AbstractUnsafe#flush
準備數(shù)據(jù): ChannelOutboundBuffer#addFlush
寫完了更新狀態(tài)
發(fā)送: NioSocketChannel#doWrite

3 寫數(shù)據(jù)的根本

Single write
sun.nio.ch.SocketChannelmpl#write(java.nio.ByteBuffer)
gathering write(批量寫)
sun.nio.ch.SocketChannelmpl#write(java.nio.ByteBuffer[], int, int)
寫數(shù)據(jù)寫不進去時,會停止寫,注冊一個?OP_WRITE?事件,來通知什么時候可以寫進去了。
OP_WRITE不代表有數(shù)據(jù)可寫,而是可以寫進去,所以正常情況下不要注冊它,否則會一直觸發(fā)。
channelHandlerContext.channel().write()
從TailContext開始執(zhí)行
channelHandlerContext.write()
從當前的Context開始
往期推薦

目前交流群已有?800+人,旨在促進技術(shù)交流,可關(guān)注公眾號添加筆者微信邀請進群
喜歡文章,點個“在看、點贊、分享”素質(zhì)三連支持一下~
