使用Netty,咱們到底在開發些什麼?

在java界,netty無疑是開發網絡應用的拿手菜。你不須要太多關注複雜的nio模型和底層網絡的細節,使用其豐富的接口,能夠很容易的實現複雜的通信功能。java

和golang的網絡模塊相比,netty仍是太過臃腫。不過java類框架就是這樣,屬於那種離了IDE就沒法存活的編碼語言。mysql

最新的netty版本將模塊分的很是細,若是不清楚每一個模塊都有什麼內容,直接使用netty-all便可。linux

單純從使用方面來講,netty是很是簡單的,掌握ByteBuf、Channel、Pipeline、Event模型等,就能夠進行開發了。你會發現面試netty相關知識,沒得聊。但Netty與其餘開發模式很大不一樣,最主要的就是其異步化。異步化形成的後果就是編程模型的不一樣,同時有調試上的困難,對編碼的要求比較高,由於bug的代價與業務代碼的bug代價不可同日而語。golang

但從項目來講,麻雀雖小五臟俱全,從業務層到服務網關,以及各類技術保障,包括監控和配置,都是須要考慮的因素。netty自己佔比很小。

本文將說明使用netty開發,都關注哪些通用的內容,而後附上單機支持100w鏈接的linux配置。本文並不關注netty的基礎知識。面試

協議開發

網絡開發中最重要的就是其通信格式,協議。咱們常見的protobuf、json、avro、mqtt等,都屬於此列。協議有語法、語義、時序三個要素。
redis

我見過不少中間件應用,採用的是redis協議,然後端落地的倒是mysql;也見過更多的採用mysql協議實現的各類自定義存儲系統,好比proxy端的分庫分表中間件、tidb等。sql

咱們經常使用的redis,使用的是文本協議;mysql等實現的是二進制協議。放在netty中也是同樣,實現一套codec便可(繼承Decoder或Encoder系列)。netty默認實現了dns、haproxy、http、http二、memcache、mqtt、redis、smtp、socks、stomp、xml等協議,能夠說是很全了,直接拿來用很爽。編程

一個可能的產品結構會是這樣的,對外提供一致的外觀,核心存儲卻不一樣:

文本協議在調試起來是比較直觀和容易的,但安全性欠佳;而二進制協議就須要依賴日誌、wireshark等其餘方式進行分析,增長了開發難度。傳說中的粘包拆包,就在這裏處理。而形成粘包的緣由,主要是因爲緩衝區的介入,因此須要約定雙方的傳輸概要等信息,netty在必定程度上解決了這個問題。json

每個想要開發網絡應用的同窗,內心都埋了一顆從新設計協議的夢想種子。但協議的設計能夠說是很是困難了,要深耕相應業務,還要考慮其擴展性。如沒有特別的必要,建議使用現有的協議。後端

鏈接管理功能

作Netty開發,鏈接管理功能是很是重要的。通訊質量、系統狀態,以及一些黑科技功能,都是依賴鏈接管理功能。
不管是做爲服務端仍是客戶端,netty在建立鏈接以後,都會獲得一個叫作Channel的對象。咱們所要作的,就是對它的管理,我習慣給它起名叫作ConnectionManager

管理類會經過緩存一些內存對象,用來統計運行中的數據。好比面向鏈接的功能:包發送、接收數量;包發送、接收速率;錯誤計數;鏈接重連次數;調用延遲;鏈接狀態等。這會頻繁用到java中concurrent包的相關類,每每也是bug集中地。

但咱們還須要更多,管理類會給予每一個鏈接更多的功能。好比,鏈接建立後,想要預熱一些功能,那這些狀態就能夠參與路由的決策。一般狀況下,將用戶或其餘元信息也attach到鏈接上,可以多維度的根據條件篩選一些鏈接,進行批量操做,好比灰度、過載保護等,是一個很是重要的功能。

管理後臺能夠看到每一個鏈接的信息,篩選到一個或多個鏈接後,可以開啓對這些鏈接的流量錄製、信息監控、斷點調試,你能體驗到掌控一切的感受。

管理功能還可以看到系統的整個運行狀態,及時調整負載均衡策略;同時對擴容、縮容提供數據依據。

心跳檢測

應用協議層的心跳是必須的,它和tcp keepalive是徹底不一樣的概念。

應用層協議層的心跳檢測的是鏈接雙方的存活性,兼而鏈接質量,而keepalive檢測的是鏈接自己的存活性。並且後者的超時時間默認過長,徹底不能適應現代的網絡環境。

心跳就是靠輪訓,不管是服務端,仍是客戶端好比GCM等。保活機制會在不一樣的應用場景進行動態的切換,好比程序喚起和在後臺,輪訓的策略是不同的。

Netty內置經過增長IdleStateHandler產生IDLE事件進行便捷的心跳控制。你要處理的,就是心跳超時的邏輯,好比延遲重連。但它的輪訓時間是固定的,沒法動態修改,高級功能須要本身定製。

在一些客戶端好比Android,頻繁心跳的喚起會浪費大量的網絡和電量,它的心跳策略會更加複雜一些。

邊界

優雅退出機制

Java的優雅停機一般經過註冊JDK ShutdownHook來實現。

Runtime.getRuntime().addShutdownHook();

通常經過kill -15進行java進程的關閉,以便在進程死亡以前進行一些清理工做。

注意:kill -9 會立馬殺死進程,不給遺言的機會,比較危險。

雖然netty作了不少優雅退出的工做,經過EventLoopGroupshutdownGracefully方法對nio進行了一些狀態設置,但在不少狀況下,這還不夠多。它只負責單機環境的優雅關閉。

流量可能還會經過外層的路由持續進入,形成無效請求。個人一般作法是首先在外層路由進行一次本地實例的摘除,把流量截斷,而後再進行netty自己的優雅關閉。這種設計很是簡單,即便沒有重試機制也會運行的很好,前提是在路由層須要提早暴露相關接口。

異常處理功能

netty因爲其異步化的開發方式,以及其事件機制,在異常處理方面就顯得異常重要。爲了保證鏈接的高可靠性,許多異常須要靜悄悄的忽略,或者在用戶態沒有感知。

netty的異常會經過pipeline進行傳播,因此在任何一層進行處理都是可行的,但編程習慣上,習慣性拋到最外層集中處理。

爲了最大限度的區別異常信息,一般會定義大量的異常類,不一樣的錯誤會拋出不一樣的異常。發生異常後,能夠根據不一樣的類型選擇斷線重連(好比一些二進制協議的編解碼紊亂問題),或者調度到其餘節點。

功能限制

指令模式

網絡應用就該幹網絡應用的事,任何通信都是昂貴的。在《Linux之《荒島餘生》(五)網絡篇》中,咱們談到百萬鏈接的服務器,廣播一個1kb消息,就須要1000M的帶寬,因此並非什麼均可以放在網絡應用裏的。

一個大型網絡應用的合理的思路就是值發送相關指令。客戶端在收到指令之後,經過其餘方式,好比http,進行大型文件到獲取。不少IM的設計思路就是如此。

指令模式還會讓通信系統的擴展性和穩定性獲得保證。增長指令能夠是配置式的,當即生效,服務端不須要編碼重啓。

穩定性保證

網絡應用的流量通常都是很是大的,並不適合全量日誌的開啓。應用應該只關注主要事件的日誌,關注異常狀況下的處理流程,日誌要打印有度。

網絡應用也不適合調用其餘緩慢的api,或者任何阻塞I/O的接口。一些實時的事件,也不該該經過調用接口吐出數據,能夠走高速mq等其餘異步通道。

緩存多是網絡應用裏用的最多的組件。jvm內緩存能夠存儲一些單機的統計數據,redis等存儲一些全局性的統計和中間態數據。

網絡應用中會大量使用redis、kv、高吞吐的mq,用來快速響應用戶請求。總之,儘可能保持通信層的清爽,你會省去不少憂慮。

單機支持100萬鏈接的Linux配置

單機支持100萬鏈接是可行的,但帶寬問題會成爲顯著的瓶頸。啓用壓縮的二進制協議會節省部分帶寬,但開發難度增長。

《LWP進程資源耗盡,Resource temporarily unavailable》中提到的ES配置同樣,優化都有相似的思路。這份配置,能夠節省你幾天的時間,請收下!

操做系統優化

更改進程最大文件句柄數

ulimit -n 1048576

修改單個進程可分配的最大文件數

echo 2097152 > /proc/sys/fs/nr_open

修改/etc/security/limits.conf文件

*   soft nofile  1048576
*   hard nofile 1048576
*   soft nproc unlimited
root soft nproc unlimited

記得清理掉/etc/security/limits.d/*下的配置

網絡優化

打開/etc/sysctl.conf,添加配置
而後執行,使用sysctl生效

#單個進程可分配的最大文件數
fs.nr_open=2097152

#系統最大文件句柄數
fs.file-max = 1048576

#backlog 設置
net.core.somaxconn=32768
net.ipv4.tcp_max_syn_backlog=16384
net.core.netdev_max_backlog=16384

#可用知名端口範圍配置
net.ipv4.ip_local_port_range='1000 65535'

#TCP Socket 讀寫 Buffer 設置
net.core.rmem_default=262144
net.core.wmem_default=262144
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.core.optmem_max=16777216
net.ipv4.tcp_rmem='1024 4096 16777216'
net.ipv4.tcp_wmem='1024 4096 16777216'

#TCP 鏈接追蹤設置
net.nf_conntrack_max=1000000
net.netfilter.nf_conntrack_max=1000000
net.netfilter.nf_conntrack_tcp_timeout_time_wait=30

#TIME-WAIT Socket 最大數量、回收與重用設置
net.ipv4.tcp_max_tw_buckets=1048576

# FIN-WAIT-2 Socket 超時設置
net.ipv4.tcp_fin_timeout = 15

總結

netty的開發工做並不集中在netty自己,更多體如今保證服務的高可靠性和穩定性上。同時有大量的工做集中在監控和調試,減小bug修復的成本。

深刻了解netty是在系統遇到疑難問題時可以深刻挖掘進行排查,或者對苛刻的性能進行提高。但對於廣大應用開發者來講,netty的上手成本小,死挖底層並不會產生太多收益。

它只是個工具,你還能讓它怎樣啊。
0.jpeg

相關文章
相關標籤/搜索