摘要:主從多線程該模型將客戶端連接那一塊的線程也改為多線程,稱為主線程。同時也是多個子線程來處理事件響應,這樣無論是連接還是事件都是高性能的。多線程提高并發效率。
前言
在之前的 SpringBoot 整合長連接心跳機制 一文中認識了 Netty。
但其實只是能用,為什么要用 Netty?它有哪些優勢?這些其實都不清楚。
本文就來從歷史源頭說道說道。
傳統 IO在 Netty 以及 NIO 出現之前,我們寫 IO 應用其實用的都是用 java.io.* 下所提供的包。
比如下面的偽代碼:
ServeSocket serverSocket = new ServeSocket(8080); Socket socket = serverSocket.accept() ; BufferReader in = .... ; String request ; while((request = in.readLine()) != null){ new Thread(new Task()).start() }
大概是這樣,其實主要想表達的是:這樣一個線程只能處理一個連接。
如果是 100 個客戶端連接那就得開 100 個線程,1000 那就得 1000 個線程。
要知道線程資源非常寶貴,每次的創建都會帶來消耗,而且每個線程還得為它分配對應的棧內存。
即便是我們給 JVM 足夠的內存,大量線程所帶來的上下文切換也是受不了的。
并且傳統 IO 是阻塞模式,每一次的響應必須的是發起 IO 請求,處理請求完成再同時返回,直接的結果就是性能差,吞吐量低。Reactor 模型
因此業界常用的高性能 IO 模型是 Reactor。
它是一種異步、非阻塞的事件驅動模型。
通常也表現為以下三種方式:
單線程從圖中可以看出:
它是由一個線程來接收客戶端的連接,并將該請求分發到對應的事件處理 handler 中,整個過程完全是異步非阻塞的;并且完全不存在共享資源的問題。所以理論上來說吞吐量也還不錯。
但由于是一個線程,對多核 CPU 利用率不高,一旦有大量的客戶端連接上來性能必然下降,甚至會有大量請求無法響應。多線程
最壞的情況是一旦這個線程哪里沒有處理好進入了死循環那整個服務都將不可用!
因此產生了多線程模型。
其實最大的改進就是將原有的事件處理改為了多線程。
可以基于 Java 自身的線程池實現,這樣在大量請求的處理上性能提示是巨大的。
雖然如此,但理論上來說依然有一個地方是單點的;那就是處理客戶端連接的線程。
因為大多數服務端應用或多或少在連接時都會處理一些業務,如鑒權之類的,當連接的客戶端越來越多時這一個線程依然會存在性能問題。
于是又有了下面的線程模型。
主從多線程該模型將客戶端連接那一塊的線程也改為多線程,稱為主線程。
同時也是多個子線程來處理事件響應,這樣無論是連接還是事件都是高性能的。
Netty 實現以上談了這么多其實 Netty 的線程模型與之的類似。
我們回到之前 SpringBoot 整合長連接心跳機制TCP-Heartbeat/) 中的服務端代碼:
private EventLoopGroup boss = new NioEventLoopGroup(); private EventLoopGroup work = new NioEventLoopGroup(); /** * 啟動 Netty * * @return * @throws InterruptedException */ @PostConstruct public void start() throws InterruptedException { ServerBootstrap bootstrap = new ServerBootstrap() .group(boss, work) .channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(nettyPort)) //保持長連接 .childOption(ChannelOption.SO_KEEPALIVE, true) .childHandler(new HeartbeatInitializer()); ChannelFuture future = bootstrap.bind().sync(); if (future.isSuccess()) { LOGGER.info("啟動 Netty 成功"); } }
其實這里的 boss 就相當于 Reactor 模型中處理客戶端連接的線程池。
work 自然就是處理事件的線程池了。
那么如何來實現上文的三種模式呢?其實也很簡單:
單線程模型:
private EventLoopGroup group = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap() .group(group) .childHandler(new HeartbeatInitializer());
多線程模型:
private EventLoopGroup boss = new NioEventLoopGroup(1); private EventLoopGroup work = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap() .group(boss,work) .childHandler(new HeartbeatInitializer());
主從多線程:
private EventLoopGroup boss = new NioEventLoopGroup(); private EventLoopGroup work = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap() .group(boss,work) .childHandler(new HeartbeatInitializer());
相信大家一看也明白。
總結其實看過了 Netty 的線程模型之后能否對我們平時做高性能應用帶來點啟發呢?
我認為是可以的:
接口同步轉異步處理。
回調通知結果。
多線程提高并發效率。
無非也就是這些,只是做了這些之后就會帶來其他問題:
異步之后事務如何保證?
回調失敗的情況?
多線程所帶來的上下文切換、共享資源的問題。
這就是一個博弈的過程,想要做到一個盡量高效的應用是需要不斷磨合試錯的。
上文相關的代碼:
https://github.com/crossoverJie/netty-action
歡迎關注公眾號一起交流:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71483.html
摘要:的選擇器允許單個線程監視多個輸入通道。一旦執行的線程已經超過讀取代碼中的某個數據片段,該線程就不會在數據中向后移動通常不會。 1、引言 很多初涉網絡編程的程序員,在研究Java NIO(即異步IO)和經典IO(也就是常說的阻塞式IO)的API時,很快就會發現一個問題:我什么時候應該使用經典IO,什么時候應該使用NIO? 在本文中,將嘗試用簡明扼要的文字,闡明Java NIO和經典IO之...
摘要:接下來的兩篇文章,我將從源碼角度為大家深入淺出的剖析的線程模型工作機制。我們看一下的源碼通過的代碼發現,實現了接口,其內部會通過指定的默認線程工廠來創建線程,并執行相應的任務。至此,初始化完成了。下一篇我們將詳細介紹,敬請期待。 我們都知道Netty的線程模型是基于React的線程模型,并且我們都知道Netty是一個高性能的NIO框架,那么其線程模型必定是它的重要貢獻之一。 在使用ne...
摘要:如果什么事都沒得做,它也不會死循環,它會將線程休眠起來,直到下一個事件來了再繼續干活,這樣的一個線程稱之為線程。而請求處理邏輯既可以使用單獨的線程池進行處理,也可以跟放在讀寫線程一塊處理。 Netty到底是什么 從HTTP說起 有了Netty,你可以實現自己的HTTP服務器,FTP服務器,UDP服務器,RPC服務器,WebSocket服務器,Redis的Proxy服務器,MySQL的P...
摘要:搞懂了這部分后,我們將明白在世界中扮演的角色進擊的此圖展示的已經算是優化后的了用到了線程池。多線程將這種處理操作分隔出來,非型操作業務操作配備以線程池,進化成多線程模型這樣的架構,系統瓶頸轉移至部分。 Channel定位 注意:如無特別說明,文中的Channel都指的是Netty Channel(io.netty.channel) 一周時間的Channel家族學習,一度讓我懷疑人生——...
摘要:它使用了事件通知以確定在一組非阻塞套接字中有哪些已經就緒能夠進行相關的操作。目前,可以把看作是傳入入站或者傳出出站數據的載體。出站事件是未來將會觸發的某個動作的操作結果,這些動作包括打開或者關閉到遠程節點的連接將數據寫到或者沖刷到套接字。 netty的概念 定義 Netty 是一款異步的事件驅動的網絡應用程序框架,支持快速地開發可維護的高性能的面向協議的服務器和客戶端。我們可以很簡單的...
閱讀 1879·2021-09-27 13:35
閱讀 3432·2019-08-30 14:16
閱讀 2489·2019-08-30 10:52
閱讀 867·2019-08-29 16:35
閱讀 1420·2019-08-29 15:22
閱讀 3647·2019-08-23 18:21
閱讀 3138·2019-08-23 18:00
閱讀 3127·2019-08-23 16:50