閃電俠 Netty 小冊裏的騷操做

前言

即便這是一本小冊,但基於「不提筆不讀書」的理念,仍然有必要總結一下。此小冊對於那些「硬槓 Netty 源碼 卻未曾在千萬級生產環境上使用實操」的用戶很是有用。固然,對那些沒有 Netty 編程經驗的人來講,更爲有用。git

放個小冊地址:[Netty 入門與實戰:仿寫微信 IM 即時通信系統](https://juejin.im/book/5b4bc28bf265da0f60130116)github

再次強烈推薦,一碗黃燜雞/半杯 Luckin coffee/一包炫赫門 的價錢,可讓你學會使用 Java 界的 epoll 進行多路複用網絡編程,不能說是不划算的 :)面試

本文標題含有「騷操做」,爲何這麼說呢?算法

做者是某團某評基礎架構部技術專家,長期負責後臺千萬級別的推送系統,而這些推送系統天然是長鏈接實現的。能夠想象,做者的這些實踐經驗不可謂很差用,縱然看過源碼,提過 issue,本人也以爲這些操做很是好用,很是騷氣。編程

開始

咱們挑重點講,雖然對於強迫症來說,每一節都有筆記纔是最吼的!bootstrap

1 服務端啓動流程安全

1. 經過給 bind 方法添加監聽器,用以自動綁定遞增端口。算騷操做吧?
2. attr 方法,爲每條鏈接增長屬性,可以實現全單例模式喲
3. childOption 方法,關於 TCP鏈接的優化,SO_KEEPALIVE 底層心跳,TCP_NODELAY 延遲發送,SO_BACKLOG 等待隊列

2 客戶端啓動流程性能優化

1. 仍是經過監聽器實現重試,可是是 connect 返回的 future,且重實間隔時間左移 1 位增長(性能優化,不使用乘二 ,優秀)。
2. 重試不在主線程,而是使用 bootstrap.config().group().schedule 搞定時任務,和我想的不同。優秀
3. 客戶端須要 CONNECT_TIMEOUT_MILLIS 屬性

3 客戶端與服務端雙向通訊微信

1.客戶端在 channelActive 馬上搞事情,嗯,rpc 通訊一般也會作一些處理,例如打印客戶端ip之類的。

4 客戶端與服務端通訊協議編解碼(擴展較多)網絡

emm,這個其實就是自定義應用層協議。
1. 4 字節魔數校驗,例如 dubbo 就使用0xdabb進行校驗,Java 字節碼也使用 0xcafebabe 校驗字節碼。
2.  版本號確定須要的
3. 序列化算法,確定也須要的
4. 指令,確定也是須要的,不過,也可使用別的方式。
5. 後面的數據長度,也是須要的,方便拆包。

其實這裏能夠參照 RPC 協議來看,這裏更像一個簡化的 RPC 協議。
通常 RPC 框架首先獲取協議類型,根據這個協議類型獲得協議處理器,而後再處理(一個端口處理多個協議的場景)。
生產級別的 RPC 一般較爲複雜,以 SOFABolt 爲例,須要如下字段:
1. 協議版本
2. 請求類型,即指令(Request,Response, oneway)
3. 指令版本
4. RequestID 負責數據對應
5. 序列號器
6. 協議開關(例如 CRC 校驗,安全校驗)
7. 響應碼,約定異常,簡化異常
8. 類名長度,Java rpc 框架必備
9. 請求頭長度(參照 http header)
10. 請求體長度(參照http body)
11. 類名
12. 業務請求頭內容(通常是 Map,SOFABolt 支持自定義,SOFARPC 裏面藏着是否泛化調用等信息)
13. 業務請求體內容(通常就是個Request對象或 Response對象,裏面包含約定的屬性,例如參數,返回值,超級多,SOFARPC 有個屬性類 RemotingConstants,這裏都有)
14. CRC 校驗碼(金融場景必備)

5 實現客戶端與服務端收發消息

1. 使用 hannel.attr(Attributes.LOGIN).set(true) 綁定登陸標識方便喲

6 構建客戶端與服務端 pipeline

1. 經常使用的 ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter 可是須要強轉哦,麻煩,
   建議使用 SimpleChannelInboundHandler (還幫你釋放內存喲)。
2. 不使用 MessageToByteEncoder ,能夠本身編解碼哦,雖然麻煩點

7 拆包粘包理論與解決方案

1. 經常使用拆包:固定長度,行拆包(有bug,我寫過文章分析),分隔符,基於長度
2. 最通用的就是基於長度,只要你的自定義協議中包含長度域字段,就可使用
3. LengthFieldBasedFrameDecoder 代替本身繼承 ByteToMessageDecoder 喲。
4. 對 LengthFieldBasedFrameDecoder 擴展一下,校驗魔數關閉錯誤鏈接美滋滋。

8 channelHandler 的生命週期

1. 在 channelReadComplete 方法裏執行 flush,批量刷新,性能提高美滋滋。
2. channelActive 和 channelInActive 增減鏈接,RPC 都這麼幹

9 使用 channelHandler 的熱插拔實現客戶端身份校驗

1. ctx.pipeline().remove(this) 刪除沒有必要的 handler 美滋滋
2. handlerRemoved 回調美滋滋

10 客戶端互聊原理與實現

1. Session 經過 channel.attr(Attributes.SESSION).set(session) 綁定鏈接美滋滋。
2. channel.attr(Attributes.SESSION).set(null) 刪除 session 美滋滋
3. channel.attr(Attributes.SESSION).get() 美滋滋

11 羣聊的發起與通知

1. ChannelGroup c = ChannelGroup channelGroup = new DefaultChannelGroup(ctx.executor()) 批量處理鏈接美滋滋
2. channelGroup.writeAndFlush 批量寫鏈接美滋滋

高能預警!!!!

12 牛逼的性能優化

1. 共享 handler
2. 壓縮 handler - 合併編解碼器 —— MessageToMessageCodec
3. 雖然有狀態的 handler 不能搞單例,可是你能夠綁定到 channel 屬性上,強行單例
4. 縮短事件傳播路徑—— 放 Map 裏,在第一個 handler 里根據指令來找具體 handler。
5. 更改事件傳播源—— 用 ctx.writeAndFlush() 不要用 ctx.channel().writeAndFlush()
6. 減小阻塞主線程的操做—— 使用業務線程池,RPC 優化重點
7. 計算耗時,使用回調 Future

13 心跳和空閒檢測

1. 空閒檢測 IdleStateHandler 用起來很爽, channelIdle 和 userEventTriggered 均可以處理
2. 定時心跳 ctx.executor().scheduleAtFixedRate 很優秀
3. 一般空閒檢測時間要比發送心跳的時間的兩倍要長一些(3倍),這也是爲了排除偶發的公網抖動,防止誤判。美滋滋

總結

小小短文,沒法盡數 Netty 精華,但對於新手來講,已經足夠使用了。而我這裏僅僅是作簡單的閱讀總結,更多的內容,還須要讀者本身去研究小冊,研究源碼,研究 Netty 在 RPC 裏的運用,方能成爲 Netty 多路複用網絡編程高手。

關於 RPC 裏使用 Netty 的最佳範例,推薦螞蟻金服開源框架 SOFABolt,能夠說是對 Netty 編程最佳實踐的提煉,和此文相輔相成進行學習,可助汝縱橫 Java 各類面試。

good luck!!!

相關文章
相關標籤/搜索