日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

在高性能的I/O設(shè)計(jì)中,有兩個(gè)著名的模型:Reactor模型和Proactor模型,其中Reactor模型用于同步I/O,而Proactor模型運(yùn)用于異步I/O操作。

想要了解兩種模型,需要了解一些IO、同步異步的基礎(chǔ)知識(shí),徹底搞懂JAVA的網(wǎng)絡(luò)IO

服務(wù)端的線程模型

無(wú)論是Reactor模型還是Proactor模型,對(duì)于支持多連接的服務(wù)器,一般可以總結(jié)為2種fd和3種事件,如下圖:

 

徹底搞懂Reactor模型和Proactor模型

 

 

2種fd

  1. listenfd:一般情況,只有一個(gè)。用來(lái)監(jiān)聽(tīng)一個(gè)特定的端口(如80)。
  2. connfd:每個(gè)連接都有一個(gè)connfd。用來(lái)收發(fā)數(shù)據(jù)。

3種事件

  1. listenfd進(jìn)行accept阻塞監(jiān)聽(tīng),創(chuàng)建一個(gè)connfd
  2. 用戶(hù)態(tài)/內(nèi)核態(tài)copy數(shù)據(jù)。每個(gè)connfd對(duì)應(yīng)著2個(gè)應(yīng)用緩沖區(qū):readbuf和writebuf。
  3. 處理connfd發(fā)來(lái)的數(shù)據(jù)。業(yè)務(wù)邏輯處理,準(zhǔn)備response到writebuf。

Reactor模型

無(wú)論是C++還是Java編寫(xiě)的網(wǎng)絡(luò)框架,大多數(shù)都是基于Reactor模型進(jìn)行設(shè)計(jì)和開(kāi)發(fā),Reactor模型基于事件驅(qū)動(dòng),特別適合處理海量的I/O事件。

Reactor模型中定義的三種角色:

  • Reactor:負(fù)責(zé)監(jiān)聽(tīng)和分配事件,將I/O事件分派給對(duì)應(yīng)的Handler。新的事件包含連接建立就緒、讀就緒、寫(xiě)就緒等。
  • Acceptor:處理客戶(hù)端新連接,并分派請(qǐng)求到處理器鏈中。
  • Handler:將自身與事件綁定,執(zhí)行非阻塞讀/寫(xiě)任務(wù),完成channel的讀入,完成處理業(yè)務(wù)邏輯后,負(fù)責(zé)將結(jié)果寫(xiě)出channel。可用資源池來(lái)管理。

Reactor處理請(qǐng)求的流程:

讀取操作:

  1. 應(yīng)用程序注冊(cè)讀就緒事件和相關(guān)聯(lián)的事件處理器
  2. 事件分離器等待事件的發(fā)生
  3. 當(dāng)發(fā)生讀就緒事件的時(shí)候,事件分離器調(diào)用第一步注冊(cè)的事件處理器

寫(xiě)入操作類(lèi)似于讀取操作,只不過(guò)第一步注冊(cè)的是寫(xiě)就緒事件。

1.單Reactor單線程模型

Reactor線程負(fù)責(zé)多路分離套接字,accept新連接,并分派請(qǐng)求到handler。redis使用單Reactor單進(jìn)程的模型。

 

徹底搞懂Reactor模型和Proactor模型

 

 

消息處理流程:

  1. Reactor對(duì)象通過(guò)select監(jiān)控連接事件,收到事件后通過(guò)dispatch進(jìn)行轉(zhuǎn)發(fā)。
  2. 如果是連接建立的事件,則由acceptor接受連接,并創(chuàng)建handler處理后續(xù)事件。
  3. 如果不是建立連接事件,則Reactor會(huì)分發(fā)調(diào)用Handler來(lái)響應(yīng)。
  4. handler會(huì)完成read->業(yè)務(wù)處理->send的完整業(yè)務(wù)流程。

單Reactor單線程模型只是在代碼上進(jìn)行了組件的區(qū)分,但是整體操作還是單線程,不能充分利用硬件資源。handler業(yè)務(wù)處理部分沒(méi)有異步。

對(duì)于一些小容量應(yīng)用場(chǎng)景,可以使用單Reactor單線程模型。但是對(duì)于高負(fù)載、大并發(fā)的應(yīng)用場(chǎng)景卻不合適,主要原因如下:

  1. 即便Reactor線程的CPU負(fù)荷達(dá)到100%,也無(wú)法滿足海量消息的編碼、解碼、讀取和發(fā)送。
  2. 當(dāng)Reactor線程負(fù)載過(guò)重之后,處理速度將變慢,這會(huì)導(dǎo)致大量客戶(hù)端連接超時(shí),超時(shí)之后往往會(huì)進(jìn)行重發(fā),這更加重Reactor線程的負(fù)載,最終會(huì)導(dǎo)致大量消息積壓和處理超時(shí),成為系統(tǒng)的性能瓶頸。
  3. 一旦Reactor線程意外中斷或者進(jìn)入死循環(huán),會(huì)導(dǎo)致整個(gè)系統(tǒng)通信模塊不可用,不能接收和處理外部消息,造成節(jié)點(diǎn)故障。

為了解決這些問(wèn)題,演進(jìn)出單Reactor多線程模型。

2.單Reactor多線程模型

該模型在事件處理器(Handler)部分采用了多線程(線程池)。

 

徹底搞懂Reactor模型和Proactor模型

 

 

消息處理流程:

  1. Reactor對(duì)象通過(guò)Select監(jiān)控客戶(hù)端請(qǐng)求事件,收到事件后通過(guò)dispatch進(jìn)行分發(fā)。
  2. 如果是建立連接請(qǐng)求事件,則由acceptor通過(guò)accept處理連接請(qǐng)求,然后創(chuàng)建一個(gè)Handler對(duì)象處理連接完成后續(xù)的各種事件。
  3. 如果不是建立連接事件,則Reactor會(huì)分發(fā)調(diào)用連接對(duì)應(yīng)的Handler來(lái)響應(yīng)。
  4. Handler只負(fù)責(zé)響應(yīng)事件,不做具體業(yè)務(wù)處理,通過(guò)Read讀取數(shù)據(jù)后,會(huì)分發(fā)給后面的Worker線程池進(jìn)行業(yè)務(wù)處理。
  5. Worker線程池會(huì)分配獨(dú)立的線程完成真正的業(yè)務(wù)處理,如何將響應(yīng)結(jié)果發(fā)給Handler進(jìn)行處理。
  6. Handler收到響應(yīng)結(jié)果后通過(guò)send將響應(yīng)結(jié)果返回給Client。

相對(duì)于第一種模型來(lái)說(shuō),在處理業(yè)務(wù)邏輯,也就是獲取到IO的讀寫(xiě)事件之后,交由線程池來(lái)處理,handler收到響應(yīng)后通過(guò)send將響應(yīng)結(jié)果返回給客戶(hù)端。這樣可以降低Reactor的性能開(kāi)銷(xiāo),從而更專(zhuān)注的做事件分發(fā)工作了,提升整個(gè)應(yīng)用的吞吐。

但是這個(gè)模型存在的問(wèn)題:

  1. 多線程數(shù)據(jù)共享和訪問(wèn)比較復(fù)雜。如果子線程完成業(yè)務(wù)處理后,把結(jié)果傳遞給主線程Reactor進(jìn)行發(fā)送,就會(huì)涉及共享數(shù)據(jù)的互斥和保護(hù)機(jī)制。
  2. Reactor承擔(dān)所有事件的監(jiān)聽(tīng)和響應(yīng),只在主線程中運(yùn)行,可能會(huì)存在性能問(wèn)題。例如并發(fā)百萬(wàn)客戶(hù)端連接,或者服務(wù)端需要對(duì)客戶(hù)端握手進(jìn)行安全認(rèn)證,但是認(rèn)證本身非常損耗性能。

為了解決性能問(wèn)題,產(chǎn)生了第三種主從Reactor多線程模型。

3.主從Reactor多線程模型

比起第二種模型,它是將Reactor分成兩部分:

  1. mainReactor負(fù)責(zé)監(jiān)聽(tīng)server socket,用來(lái)處理網(wǎng)絡(luò)IO連接建立操作,將建立的socketChannel指定注冊(cè)給subReactor。
  2. subReactor主要做和建立起來(lái)的socket做數(shù)據(jù)交互和事件業(yè)務(wù)處理操作。通常,subReactor個(gè)數(shù)上可與CPU個(gè)數(shù)等同。

Nginx、Swoole、Memcached和Netty都是采用這種實(shí)現(xiàn)。

 

徹底搞懂Reactor模型和Proactor模型

 

 

消息處理流程:

  1. 從主線程池中隨機(jī)選擇一個(gè)Reactor線程作為acceptor線程,用于綁定監(jiān)聽(tīng)端口,接收客戶(hù)端連接
  2. acceptor線程接收客戶(hù)端連接請(qǐng)求之后創(chuàng)建新的SocketChannel,將其注冊(cè)到主線程池的其它Reactor線程上,由其負(fù)責(zé)接入認(rèn)證、IP黑白名單過(guò)濾、握手等操作
  3. 步驟2完成之后,業(yè)務(wù)層的鏈路正式建立,將SocketChannel從主線程池的Reactor線程的多路復(fù)用器上摘除,重新注冊(cè)到Sub線程池的線程上,并創(chuàng)建一個(gè)Handler用于處理各種連接事件
  4. 當(dāng)有新的事件發(fā)生時(shí),SubReactor會(huì)調(diào)用連接對(duì)應(yīng)的Handler進(jìn)行響應(yīng)
  5. Handler通過(guò)Read讀取數(shù)據(jù)后,會(huì)分發(fā)給后面的Worker線程池進(jìn)行業(yè)務(wù)處理
  6. Worker線程池會(huì)分配獨(dú)立的線程完成真正的業(yè)務(wù)處理,如何將響應(yīng)結(jié)果發(fā)給Handler進(jìn)行處理
  7. Handler收到響應(yīng)結(jié)果后通過(guò)Send將響應(yīng)結(jié)果返回給Client

總結(jié)

Reactor模型具有如下的優(yōu)點(diǎn):

  1. 響應(yīng)快,不必為單個(gè)同步時(shí)間所阻塞,雖然Reactor本身依然是同步的;
  2. 編程相對(duì)簡(jiǎn)單,可以最大程度的避免復(fù)雜的多線程及同步問(wèn)題,并且避免了多線程/進(jìn)程的切換開(kāi)銷(xiāo);
  3. 可擴(kuò)展性,可以方便地通過(guò)增加Reactor實(shí)例個(gè)數(shù)來(lái)充分利用CPU資源;
  4. 可復(fù)用性,Reactor模型本身與具體事件處理邏輯無(wú)關(guān),具有很高的復(fù)用性。

Proactor模型

 

徹底搞懂Reactor模型和Proactor模型

 

 

模塊關(guān)系:

  1. Procator Initiator負(fù)責(zé)創(chuàng)建Procator和Handler,并將Procator和Handler都通過(guò)Asynchronous operation processor注冊(cè)到內(nèi)核。
  2. Asynchronous operation processor負(fù)責(zé)處理注冊(cè)請(qǐng)求,并完成IO操作。完成IO操作后會(huì)通知procator。
  3. procator根據(jù)不同的事件類(lèi)型回調(diào)不同的handler進(jìn)行業(yè)務(wù)處理。handler完成業(yè)務(wù)處理,handler也可以注冊(cè)新的handler到內(nèi)核進(jìn)程。

消息處理流程:

讀取操作:

  1. 應(yīng)用程序初始化一個(gè)異步讀取操作,然后注冊(cè)相應(yīng)的事件處理器,此時(shí)事件處理器不關(guān)注讀取就緒事件,而是關(guān)注讀取完成事件,這是區(qū)別于Reactor的關(guān)鍵。
  2. 事件分離器等待讀取操作完成事件
  3. 在事件分離器等待讀取操作完成的時(shí)候,操作系統(tǒng)調(diào)用內(nèi)核線程完成讀取操作,并將讀取的內(nèi)容放入用戶(hù)傳遞過(guò)來(lái)的緩存區(qū)中。這也是區(qū)別于Reactor的一點(diǎn),Proactor中,應(yīng)用程序需要傳遞緩存區(qū)。
  4. 事件分離器捕獲到讀取完成事件后,激活應(yīng)用程序注冊(cè)的事件處理器,事件處理器直接從緩存區(qū)讀取數(shù)據(jù),而不需要進(jìn)行實(shí)際的讀取操作。

異步IO都是操作系統(tǒng)負(fù)責(zé)將數(shù)據(jù)讀寫(xiě)到應(yīng)用傳遞進(jìn)來(lái)的緩沖區(qū)供應(yīng)用程序操作。

Proactor中寫(xiě)入操作和讀取操作,只不過(guò)感興趣的事件是寫(xiě)入完成事件。

Proactor有如下缺點(diǎn):

  1. 編程復(fù)雜性,由于異步操作流程的事件的初始化和事件完成在時(shí)間和空間上都是相互分離的,因此開(kāi)發(fā)異步應(yīng)用程序更加復(fù)雜。應(yīng)用程序還可能因?yàn)榉聪虻牧骺囟兊酶与y以Debug;
  2. 內(nèi)存使用,緩沖區(qū)在讀或?qū)懖僮鞯臅r(shí)間段內(nèi)必須保持住,可能造成持續(xù)的不確定性,并且每個(gè)并發(fā)操作都要求有獨(dú)立的緩存,相比Reactor模型,在Socket已經(jīng)準(zhǔn)備好讀或?qū)懬埃遣灰箝_(kāi)辟緩存的;
  3. 操作系統(tǒng)支持,windows下通過(guò)IOCP實(shí)現(xiàn)了真正的異步 I/O,而在linux系統(tǒng)下,Linux2.6才引入,并且異步I/O使用epoll實(shí)現(xiàn)的,所以還不完善。

因此在 Linux 下實(shí)現(xiàn)高并發(fā)網(wǎng)絡(luò)編程都是以Reactor模型為主。

常見(jiàn)架構(gòu)的進(jìn)程/線程模型

Netty的線程模型

Netty采用的是主從線程模型。下面是Netty使用中很常見(jiàn)的一段代碼。

public class Server {

public static void main(String[] args) throws Exception {

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

EventLoopGroup workerGroup = new NioEventLoopGroup();

try {

ServerBootstrap b = new ServerBootstrap();

b.group(bossGroup, workerGroup)

.channel(NIOServerSocketChannel.class)

.childOption(ChannelOption.TCP_NODELAY, true)

.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")

.handler(new ServerHandler())

.childHandler(new ChannelInitializer<SocketChannel>() {

@Override

public void initChannel(SocketChannel ch) {

}

});

ChannelFuture f = b.bind(8888).sync();

f.channel().closeFuture().sync();

} finally {

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

}

}

對(duì)Netty示例代碼進(jìn)行分析:

  1. 定義了兩個(gè)EventLoopGroup,其中bossGroup對(duì)應(yīng)的就是主線程池,只接收客戶(hù)端的連接(注冊(cè),初始化邏輯),具體的工作由workerGroup這個(gè)從線程池來(lái)完成。可以理解為老板負(fù)責(zé)招攬接待,員工負(fù)責(zé)任務(wù)完成。線程池和線程組是一個(gè)概念,所以名稱(chēng)里有g(shù)roup。之后就采用ServerBootstrap啟動(dòng)類(lèi),傳入這兩個(gè)主從線程組。
  2. 客戶(hù)端和服務(wù)器建立連接后,NIO會(huì)在兩者之間建立Channel,所以啟動(dòng)類(lèi)調(diào)用channel方法就是為了指定建立什么類(lèi)型的通道。這里指定的是NioServerSocketChannel這個(gè)通道類(lèi)。
  3. 啟動(dòng)類(lèi)還調(diào)用了handler()和childHandler()方法,這兩個(gè)方法中提及的handler是一個(gè)處理類(lèi)的概念,他負(fù)責(zé)處理連接后的一個(gè)個(gè)通道的相應(yīng)處理。handler()指定的處理類(lèi)是主線程池中對(duì)通道的處理類(lèi),childHandler()方法指定的是從線程池中對(duì)通道的處理類(lèi)。
  4. 執(zhí)行ServerBootstrap的bind方法進(jìn)行綁定端口的同時(shí)也執(zhí)行了sync()方法進(jìn)行同步阻塞調(diào)用。
  5. 關(guān)閉通道采用Channel的closeFuture()方法關(guān)閉。
  6. 最終優(yōu)雅地關(guān)閉兩個(gè)線程組,執(zhí)行shutdownGracefully()方法完成關(guān)閉線程組。

如果需要在客戶(hù)端連接前的請(qǐng)求進(jìn)行handler處理,則需要配置handler();如果是處理客戶(hù)端連接之后的handler,則需要配置在childHandler()。option和childOption也是一樣的道理。

boss線程池作用:

  1. 接收客戶(hù)端的連接,初始化Channel參數(shù)。
  2. 將鏈路狀態(tài)變更時(shí)間通知給ChannelPipeline。

worker線程池作用:

  1. 異步讀取通信對(duì)端的數(shù)據(jù)報(bào),發(fā)送讀事件到ChannelPipeline。
  2. 異步發(fā)送消息到通信對(duì)端,調(diào)用ChannelPipeline的消息發(fā)送接口。
  3. 執(zhí)行系統(tǒng)調(diào)用Task。
  4. 執(zhí)行定時(shí)任務(wù)Task。

通過(guò)配置boss和worker線程池的線程個(gè)數(shù)以及是否共享線程池等方式,Netty的線程模型可以在以上三種Reactor模型之間進(jìn)行切換。

Tomcat的線程模型

Tomcat支持四種接收請(qǐng)求的處理方式:BIO、NIO、APR和AIO

  • NIO
  • 同步非阻塞,比傳統(tǒng)BIO能更好的支持大并發(fā),tomcat 8.0 后默認(rèn)采用該模型。
  • 使用方法(配置server.xml):<Connector port="8080" protocol="HTTP/1.1"/> 改為 protocol="org.Apache.coyote.http11.Http11NioProtocol"
  • BIO
  • 阻塞式IO,tomcat7之前默認(rèn),采用傳統(tǒng)的java IO進(jìn)行操作,該模型下每個(gè)請(qǐng)求都會(huì)創(chuàng)建一個(gè)線程,適用于并發(fā)量小的場(chǎng)景。
  • 使用方法(配置server.xml):protocol =" org.apache.coyote.http11.Http11Protocol"
  • APR
  • tomcat 以JNI形式調(diào)用http服務(wù)器的核心動(dòng)態(tài)鏈接庫(kù)來(lái)處理文件讀取或網(wǎng)絡(luò)傳輸操作,需要編譯安裝APR庫(kù)。
  • 使用方法(配置server.xml):protocol ="org.apache.coyote.http11.Http11AprProtocol"
  • AIO
  • 異步非阻塞 (NIO2),tomcat8.0后支持。多用于連接數(shù)目多且連接比較長(zhǎng)(重操作)的架構(gòu),比如相冊(cè)服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開(kāi)始支持。
  • 使用方法(配置server.xml):protocol ="org.apache.coyote.http11.Http11Nio2Protocol"

Nginx的進(jìn)程模型

Nginx采用的是多進(jìn)程(單線程)&多路IO復(fù)用模型。

工作模型:

  1. Nginx在啟動(dòng)后,會(huì)有一個(gè)master進(jìn)程和多個(gè)相互獨(dú)立的worker進(jìn)程。
  2. 接收來(lái)自外界的信號(hào),向所有worker進(jìn)程發(fā)送信號(hào),每個(gè)進(jìn)程都有可能來(lái)處理這個(gè)連接。
  3. master進(jìn)程能監(jiān)控worker進(jìn)程的運(yùn)行狀態(tài),當(dāng)worker進(jìn)程退出后(異常情況下),會(huì)自動(dòng)啟動(dòng)新的worker進(jìn)程。

分享到:
標(biāo)簽:模型 Reactor
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定