一、什么是Netty
網站建設哪家好,找創新互聯公司!專注于網頁設計、網站建設、微信開發、成都小程序開發、集團企業網站建設等服務項目。為回饋新老客戶創新互聯還提供了淮濱免費建站歡迎大家使用!
Netty是一個高性能 事件驅動、異步非堵塞的IO(NIO)Java開源框架,Jboss提供,用于建立TCP等底層的連接,基于Netty可以建立高性能的Http服務器,快速開發高性能、高可靠性的網絡服務器和客戶端程序。支持HTTP、 WebSocket 、Protobuf、 Binary TCP |和UDP,Netty已經被很多高性能項目作為其Socket底層基礎,如HornetQ Infinispan Vert.x Play Framework Finangle和 Cassandra。其競爭對手是:Apache MINA和 Grizzly。
也就是說,Netty 是一個基于NIO的客戶,服務器端編程框架,使用Netty 可以確保你快速和簡單的開發出一個網絡應用,例如實現了某種協議的客戶,服務端應用。Netty相當簡化和流線化了網絡應用的編程開發過程,例如,TCP和UDP的socket服務開發。
“快速”和“簡單”并不意味著會讓你的最終應用產生維護性或性能上的問題。Netty 是一個吸收了多種協議的實現經驗,這些協議包括FTP,SMTP,HTTP,各種二進制,文本協議,并經過相當精心設計的項目,最終,Netty 成功的找到了一種方式,在保證易于開發的同時還保證了其應用的性能,穩定性和伸縮性。
二、不選擇Java原生NIO編程的原因
首先開發出高質量的NIO程序并不是一件簡單的事情,除去NIO固有的復雜性和BUG不談,作為一個NIO服務端,還需要能夠處理網絡的閃斷、客戶端的重復接入、客戶端的安全認證、消息的編解碼、半包讀寫等情況,如果你沒有足夠的NIO編程經驗積累,一個NIO框架的穩定往往需要半年甚至更長的時間。更為糟糕的是,一旦在生產環境中發生問題,往往會導致跨節點的服務調用中斷,嚴重的可能會導致整個集群環境都不可用,需要重啟服務器,這種非正常停機會帶來巨大的損失。
從可維護性角度看,由于NIO采用了異步非阻塞編程模型,而且是一個I/O線程處理多條鏈路,它的調試和跟蹤非常麻煩,特別是生產環境中的問題,我們無法進行有效的調試和跟蹤,往往只能靠一些日志來輔助分析,定位難度很大。
現在我們總結一下為什么不建議開發者直接使用JDK的NIO類庫進行開發,具體原因如下。
1)跨平臺與兼容性:NIO算是底層的APIs需依賴系統的IO APIs。但Java NIO發現在不同系統平臺會出現問題。大量測試也耗不少時間;NIO2只支持JDK1.7+,而且沒提供DatagramSocket,故NIO2不支持UDP協議。而Netty提供統一接口,同一語句無論在JDK6.X 還是JDK7.X 都可運行,無需關心底層架構功能!
2)JAVA NIO的ByteBuffer構造函數私有,無法擴展。Netty提供了自己的ByteBuffer實現,通過簡單APIs對其進行構造、使用和操作,一此解決NIO的一些限制。
3)NIO對緩沖區的聚合與分散操作可能會導致內存泄漏。直到JDK1.7才解決此問題。
4)NIO的類庫和API繁雜,使用麻煩,你需要熟練掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。
5)使用JAVA NIO需要具備其他的額外技能做鋪墊,例如熟悉Java多線程編程。這是因為NIO編程涉及到Reactor模式,你必須對多線程和網路編程非常熟悉,才能編寫出高質量的NIO程序。
6)可靠性能力補齊,工作量和難度都非常大。例如客戶端面臨斷連重連、網絡閃斷、半包讀寫、失敗緩存、網絡擁塞和異常碼流的處理等問題。
7)JDK NIO的BUG,例如臭名昭著的epoll bug,它會導致Selector空輪詢,最終導致CPU 100%。官方聲稱在JDK 1.6版本的update18修復了該問題,但是直到JDK 1.7版本該問題仍舊存在,只不過該BUG發生概率降低了一些而已,它并沒有得到根本性解決。該BUG以及與該BUG相關的問題單可以參見以下鏈接內容。
異常堆棧如下。
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
- locked 0x0000000750928190 (a sun.nio.ch.Util$2)
- locked 0x00000007509281a8 (a java.util.Collections$ UnmodifiableSet)
- locked 0x0000000750946098 (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
at net.spy.memcached.MemcachedConnection.handleIO(Memcached Connection.java:217)
at net.spy.memcached.MemcachedConnection.run(MemcachedConnection. java:836)
由于上述原因,在大多數場景下,不建議大家直接使用JDK的NIO類庫,除非你精通NIO編程或者有特殊的需求。在絕大多數的業務場景中,我們可以使用NIO框架Netty來進行NIO編程,它既可以作為客戶端也可以作為服務端,同時支持UDP和異步文件傳輸,功能非常強大。
Executor workerExecutor = Executors.newCachedThreadPool();
Executor bossExecutor = Executors.newCachedThreadPool();
ServerBootstrap server = new ServerBootstrap(new NioServerSocketChannelFactory(bossExecutor, workerExecutor));
server.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline p = Channels.pipeline();
p.addLast("logging", new LoggingHandler(InternalLogLevel.INFO));
p.addLast("decoder", new Decoder());
p.addLast("handler", new Netty3Handler());
return p;
}
});
server.bind(new InetSocketAddress("127.0.0.1", 9999));
根據我們前面分析的,接收到消息后,為了避免在I/O線程里執行耗時的操作,一般都會使用線程池來執行業務處理邏輯.
那是使用Netty提供給我們的方法,傳入一個線程池還是使用我們自己定義的線程池好呢?
先來看Netty給我們提供的
即我們添加handler的時候可以傳入一個線程池進去
DefaultEventExecutorGroup
它與NioEventLoop之間的區別又是什么?
其次
也就是說使用netty提供默認的,是綁定的.如下圖
如果采用自定義線程池時,優化方向就是鎖消除.
可以使用Disruptor或者使用ChannelId與業務線程池中的某個業務進行綁定
鏈接:
用while語句求 。
用傳統流程圖和N-S結構流程圖表示算法,見圖:
main()
{
int i,sum=0;
i=1;
while(i=100)
{
sum=sum+i;
i++;
}
printf("%d\n",sum);
}
NioEventLoop的事件循環處理,就是在一個死循環中處理IO事件和隊列里的任務,并且可以根據策略來平衡這兩者之間的執行比例。
首先,先來看下selectStrategy,netty中只有一個默認實現
這個策略,若是當前有任務,那么返回selectNow()方法的返回值,若是沒有任務,則返回SelectStrategy.SELECT(-1)。
因此接下來的swtich語句塊中只會有一種情況,就是值為-1時,表示沒有任務。但是并不是就進入無限的阻塞狀態select()方法中,還會判斷隊列是否有定時任務要執行,若有,則計算到下一次定時任務的時間間隔,并傳給select()方法中,表示超時時間,這個是為了防止一直在select等待,而沒有及時的執行定時任務。
這個超時時間還會設置到原子變量nextWakeupNanos中,這樣應用程序就可以通過nextWakeupNanos獲取到下一次線程喚醒的時間。當線程喚醒后,程序finally會執行nextWakeupNanos.lazySet(AWAKE),表示線程目前是喚醒狀態。這個變量的主要作用是當線程阻塞在select方法時,而此時又有任務提交給這個NioEventLoop執行時
喚醒selector時,會先判斷inEventLoop,因為若是inEventLoop,就是目前的任務正在被NioEventLoop的線程執行,并沒有阻塞在selector的select方法,還有會對nextWakeupNanos的值設置為AWAKE喚醒狀態,若該變量值之前就是喚醒的,那么也不會喚醒selector。
現在,把流程又回到剛剛的事件循環run方法中,當select方法返回后,要執行selectKeys和任務時,會先判斷ioRatio這個參數,這個表示的是在當前循環中處理IO事件的時間與任務的比例
在每次的循環最后,會判斷NioEventLoop是否shutdown了,若關閉了,則將Selector上的key都cancel,并關閉channel。
鏈接:
實現單機的百萬連接,瓶頸有以下幾點:
1、如何模擬百萬連接
2、突破局部文件句柄的限制
3、突破全局文件句柄的限制
在linux系統里面,單個進程打開的句柄數是非常有限的,一條TCP連接就對應一個文件句柄,而對于我們應用程序來說,一個服務端默認建立的連接數是有限制的。
下面通過優化要突破這個連接數。
優化
1、局部文件句柄限制
一個jvm進程最大能夠打開的文件數.png
修改65535的這個限制
vi /etc/security/limits.conf
在文件末尾添加兩行
*hard nofile 1000000
soft nofile? 1000000
soft和hard為兩種限制方式,其中soft表示警告的限制,hard表示真正限制,nofile表示打開的最大文件數。整體表示任何用戶一個進程能夠打開1000000個文件。注意語句簽名有
號 表示任何用戶
shutdown -r now? 重啟linux
再次查看
已經修改生效了。
測試
最大連接數10萬多.png
2、突破全局文件句柄的限制
cat /proc/sys/fs/file-max
file-max 表示在linux 中最終所有x線程能夠打開的最大文件數
修改這個最大值:
sudo vi? /etc/sysctl.conf
在文件的末尾添加 fs.file-max=1000000
然后讓文件生效 sudo sysctl -p
這個時候再查看一下全局最大文件句柄的數已經變成1000000了
測試
最大連接數36萬多.png
注: 測試的服務器型號
cpu 相關配置
網頁題目:vb.nettyp語句,vbnet property
文章網址:http://vcdvsql.cn/article16/hedpdg.html
成都網站建設公司_創新互聯,為您提供靜態網站、面包屑導航、云服務器、網站導航、定制開發、建站公司
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯