《Netty官方文件》5.0中的變化和注意點
原文地址 譯者:葉揚V
這篇文件將引領你瞭解netty在4.1 release版本之後所做的一系列顯著升級和新特性,以便讓你能把應用升級到新版本。
不像netty在3.X和4.0之間的升級變化,5.0版本雖然在設計上做出了重大突破和簡化,但(在呼叫層面)並沒有改變很多。我們儘可能讓4.X版本可以平滑地升級到5.0版本,但是如果你在升級過程中遇到任何問題,請告知我們。
變化要點
精簡handler型別繼承關係
ChannelInboundHandler和ChannelOutboundHandler被合併成ChannelHandler。現在ChannelHandler中既有inbound handler函式也有outbound handler函式。
ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter和ChannelDuplexHandlerAdapter被棄用然後替換為
。
因為現在已經無法區分一個handler是inbound handler還是outbound handler,所以CombinedChannelDuplexHandler已經被替換為
。
channelRead0() → messageReceived()
我知道,這(譯者注:netty4中的channelRead0()
)是一個愚蠢的錯誤。如果你已經使用了,你就必須將channelRead0()函式重新命名為messageReceived()
更靈活的執行緒模型
在Netty 4.X中,每個都與一個固定的執行緒緊密耦合,這個執行緒會執行它註冊的的所有I/O事件,也會執行所有提交給它的任務。
從5.0版本開始,一個EventLoop(的構造)不再直接使用執行緒,取而代之的是使用
。也就是說,它使用Executor物件作為建構函式的入參。而且,以前的方式是在迴圈中拉取I/O事件,現在的方式是每次迭代得到一個task,再將task提交給Executor執行。
如果沒有特別指定的話,Executor預設是一個
。ForkJoinPool的特點是使用
thread-local佇列。也就是說,一個從執行緒A提交到ForkJoinPool的任務非常可能再次被執行緒A
而且,開發者可以使用自己的Executor(也叫做
thread pool)接管EventLoops的排程。當netty只作為一個大型軟體系統中作的部分時,這種設計就顯得非常有用。假設一個系統已經在使用高併發處理它的任務,
Netty 4.x加入時會簡單的開啟自己的執行緒,而絲毫不顧netty只是這個大型系統的一部分。從netty5.0開始,開發者可以將netty和系統中其它部分放入一個執行緒池中,通過使用更優的排程策略和較少的排程開支來潛在地提高效能。細節變化的討論可以參考GitHub issue 2250。
值得一提的是,這個變化並未改變的開發方式。從開發者的視角來看,唯一改變的是,一個ChannelHandler將不再一定會被同一個執行緒一直執行;仍然可保證的是,它不會被多個執行緒同時執行。Netty會負責記憶體可見性的問題,所以不用擔心執行緒安全和ChannelHandler的volatile變數。
更好的Channel.deregister(...)
Netty 4.0引進了Channel.deregister(...),它的行為在5.0版本中被更新用以更符合
Netty執行緒模型。
現在可以確保在一個ChannelHandler中提交到EventLoop的所有任務都會在Channel被登出之前被EventLoop執行。然而,Channel.deregister(…)仍然是一個非阻塞的操作,所以我們必須等到ChannelFuture成功返回資料,然後才能安全的把Channel重新註冊到另一個EventLoop上。
在已經呼叫了Channel.deregister(...)後,任何嘗試在ChannelHandler中提交新任務
到EventLoop的行為將會丟擲
異常。只有這個Channel重新註冊到另一個EventLoop後,一切才會恢復正常。
ChannelHandler通過EventLoop.schedule*(...)函式提交的任務會在Channel被登出後停止執行。當這個Channel重新註冊時,任務會自動轉移到新的EventLoop繼續執行。這個限制只會影響那些當Channel被登出時被排程的任務。那些delay或者定時執行的任務不會受到影響。
你可以繞過上面的限制,但我們不推薦這樣做。Netty 5.0引進了一個新函式EventLoop.unwrap(),這個函式可以返回一個原始的EventLoop,這個EventLoop並不執行任何健全性檢查。
更準確的講, 當提交任務或者排程任務到 “unwrapped” EventLoop時, 不會保證這些任務被併發執行,排程的任務也不保證被自動移到新的EventLoop.