Netty和RPC框架线程模型分析
《Netty 進(jìn)階之路》、《分布式服務(wù)框架原理與實(shí)踐》作者李林鋒深入剖析Netty和RPC框架線程模型。李林鋒已在 InfoQ 上開設(shè) Netty 專題持續(xù)出稿,感興趣的同學(xué)可以持續(xù)關(guān)注。
1. 背景
1.1 線程模型的重要性
對(duì)于RPC框架而言,影響其性能指標(biāo)的主要有三個(gè)要素:
I/O模型:采用的是同步BIO、還是非阻塞的NIO、以及全異步的事件驅(qū)動(dòng)I/O(AIO)。
協(xié)議和序列化方式:它主要影響消息的序列化、反序列化性能,以及消息的通信效率。
線程模型:主要影響消息的讀取和發(fā)送效率、以及調(diào)度的性能。
除了對(duì)性能有影響,在一些場(chǎng)景下,線程模型的變化也會(huì)影響到功能的正確性,例如Netty從3.X版本升級(jí)到4.X版本之后,重構(gòu)和優(yōu)化了線程模型。當(dāng)業(yè)務(wù)沒有意識(shí)到線程模型發(fā)生變化時(shí),就會(huì)踩到一些性能和功能方面的坑。
1.2 Netty和RPC框架的線程模型關(guān)系
作為一個(gè)高性能的NIO通信框架,Netty主要關(guān)注的是I/O通信相關(guān)的線程工作策略,以及提供的用戶擴(kuò)展點(diǎn)ChannelHandler的執(zhí)行策略,示例如下:
圖1 Netty 多線程模型該線程模型的工作特點(diǎn)如下:
有專門一個(gè)(一組)NIO線程-Acceptor線程用于監(jiān)聽服務(wù)端,接收客戶端的TCP連接請(qǐng)求。
網(wǎng)絡(luò)I/O操作-讀、寫等由一個(gè)NIO線程池負(fù)責(zé),線程池可以采用標(biāo)準(zhǔn)的JDK線程池實(shí)現(xiàn),它包含一個(gè)任務(wù)隊(duì)列和N個(gè)可用的線程,由這些NIO線程負(fù)責(zé)消息的讀取、解碼、編碼和發(fā)送。
1個(gè)NIO線程可以同時(shí)處理N條鏈路,但是1個(gè)鏈路只對(duì)應(yīng)1個(gè)NIO線程,防止發(fā)生并發(fā)操作問題。
對(duì)于RPC框架,它的線程模型會(huì)更復(fù)雜一些,除了通信相關(guān)的I/O線程模型,還包括服務(wù)接口調(diào)用、服務(wù)訂閱/發(fā)布等相關(guān)的業(yè)務(wù)側(cè)線程模型。對(duì)于基于Netty構(gòu)建的RPC框架,例如gRPC、Apache ServiceComb等,它在重用Netty線程模型的基礎(chǔ)之上,也擴(kuò)展實(shí)現(xiàn)了自己的線程模型。
2. Netty線程模型
2.1 線程模型的變更
2.1.1 Netty 3.X 版本線程模型
Netty 3.X的I/O操作線程模型比較復(fù)雜,它的處理模型包括兩部分:
Inbound:主要包括鏈路建立事件、鏈路激活事件、讀事件、I/O異常事件、鏈路關(guān)閉事件等。
Outbound:主要包括寫事件、連接事件、監(jiān)聽綁定事件、刷新事件等。
我們首先分析下Inbound操作的線程模型:
圖2 Netty 3 Inbound操作線程模型從上圖可以看出,Inbound操作的主要處理流程如下:
I/O線程(Work線程)將消息從TCP緩沖區(qū)讀取到SocketChannel的接收緩沖區(qū)中。
由I/O線程負(fù)責(zé)生成相應(yīng)的事件,觸發(fā)事件向上執(zhí)行,調(diào)度到ChannelPipeline中。
I/O線程調(diào)度執(zhí)行ChannelPipeline中Handler鏈的對(duì)應(yīng)方法,直到業(yè)務(wù)實(shí)現(xiàn)的Last Handler。
Last Handler將消息封裝成Runnable,放入到業(yè)務(wù)線程池中執(zhí)行,I/O線程返回,繼續(xù)讀/寫等I/O操作。
業(yè)務(wù)線程池從任務(wù)隊(duì)列中彈出消息,并發(fā)執(zhí)行業(yè)務(wù)邏輯。
通過對(duì)Netty 3的Inbound操作進(jìn)行分析我們可以看出,Inbound的Handler都是由Netty的I/O Work線程負(fù)責(zé)執(zhí)行。
下面我們繼續(xù)分析Outbound操作的線程模型:
圖3 Netty 3 Outbound操作線程模型從上圖可以看出,Outbound操作的主要處理流程如下:
業(yè)務(wù)線程發(fā)起Channel Write操作,發(fā)送消息。
Netty將寫操作封裝成寫事件,觸發(fā)事件向下傳播。
寫事件被調(diào)度到ChannelPipeline中,由業(yè)務(wù)線程按照Handler Chain串行調(diào)用支持Downstream事件的Channel Handler。
執(zhí)行到系統(tǒng)最后一個(gè)ChannelHandler,將編碼后的消息Push到發(fā)送隊(duì)列中,業(yè)務(wù)線程返回。
Netty的I/O線程從發(fā)送消息隊(duì)列中取出消息,調(diào)用SocketChannel的write方法進(jìn)行消息發(fā)送。
2.1.2 Netty 4.X 版本線程模型
相比于Netty 3.X系列版本,Netty 4.X的I/O操作線程模型比較簡(jiǎn)答,它的原理圖如下所示:
圖4 Netty 4 Inbound和Outbound操作線程模型從上圖可以看出,Outbound操作的主要處理流程如下:
I/O線程N(yùn)ioEventLoop從SocketChannel中讀取數(shù)據(jù)報(bào),將ByteBuf投遞到ChannelPipeline,觸發(fā)ChannelRead事件。
I/O線程N(yùn)ioEventLoop調(diào)用ChannelHandler鏈,直到將消息投遞到業(yè)務(wù)線程,然后I/O線程返回,繼續(xù)后續(xù)的讀寫操作。
業(yè)務(wù)線程調(diào)用ChannelHandlerContext.write(Object msg)方法進(jìn)行消息發(fā)送。
如果是由業(yè)務(wù)線程發(fā)起的寫操作,ChannelHandlerInvoker將發(fā)送消息封裝成Task,放入到I/O線程N(yùn)ioEventLoop的任務(wù)隊(duì)列中,由NioEventLoop在循環(huán)中統(tǒng)一調(diào)度和執(zhí)行。放入任務(wù)隊(duì)列之后,業(yè)務(wù)線程返回。
I/O線程N(yùn)ioEventLoop調(diào)用ChannelHandler鏈,進(jìn)行消息發(fā)送,處理Outbound事件,直到將消息放入發(fā)送隊(duì)列,然后喚醒Selector,進(jìn)而執(zhí)行寫操作。
通過流程分析,我們發(fā)現(xiàn)Netty 4修改了線程模型,無論是Inbound還是Outbound操作,統(tǒng)一由I/O線程N(yùn)ioEventLoop調(diào)度執(zhí)行。
2.1.3 新老線程模型對(duì)比
在進(jìn)行新老版本線程模型對(duì)比之前,首先還是要熟悉下串行化設(shè)計(jì)的理念:
我們知道當(dāng)系統(tǒng)在運(yùn)行過程中,如果頻繁的進(jìn)行線程上下文切換,會(huì)帶來額外的性能損耗。多線程并發(fā)執(zhí)行某個(gè)業(yè)務(wù)流程,業(yè)務(wù)開發(fā)者還需要時(shí)刻對(duì)線程安全保持警惕,哪些數(shù)據(jù)可能會(huì)被并發(fā)修改,如何保護(hù)?這不僅降低了開發(fā)效率,也會(huì)帶來額外的性能損耗。
為了解決上述問題,Netty 4采用了串行化設(shè)計(jì)理念,從消息的讀取、編碼以及后續(xù)Handler的執(zhí)行,始終都由I/O線程N(yùn)ioEventLoop負(fù)責(zé),這就意外著整個(gè)流程不會(huì)進(jìn)行線程上下文的切換,數(shù)據(jù)也不會(huì)面臨被并發(fā)修改的風(fēng)險(xiǎn),對(duì)于用戶而言,甚至不需要了解Netty的線程細(xì)節(jié),這確實(shí)是個(gè)非常好的設(shè)計(jì)理念,它的工作原理圖如下:
圖5 Netty 4的串行化設(shè)計(jì)理念一個(gè)NioEventLoop聚合了一個(gè)多路復(fù)用器Selector,因此可以處理成百上千的客戶端連接,Netty的處理策略是每當(dāng)有一個(gè)新的客戶端接入,則從NioEventLoop線程組中順序獲取一個(gè)可用的NioEventLoop,當(dāng)?shù)竭_(dá)數(shù)組上限之后,重新返回到0,通過這種方式,可以基本保證各個(gè)NioEventLoop的負(fù)載均衡。一個(gè)客戶端連接只注冊(cè)到一個(gè)NioEventLoop上,這樣就避免了多個(gè)I/O線程去并發(fā)操作它。
Netty通過串行化設(shè)計(jì)理念降低了用戶的開發(fā)難度,提升了處理性能。利用線程組實(shí)現(xiàn)了多個(gè)串行化線程水平并行執(zhí)行,線程之間并沒有交集,這樣既可以充分利用多核提升并行處理能力,同時(shí)避免了線程上下文的切換和并發(fā)保護(hù)帶來的額外性能損耗。
了解完了Netty 4的串行化設(shè)計(jì)理念之后,我們繼續(xù)看Netty 3線程模型存在的問題,總結(jié)起來,它的主要問題如下:
Inbound和Outbound實(shí)質(zhì)都是I/O相關(guān)的操作,它們的線程模型竟然不統(tǒng)一,這給用戶帶來了更多的學(xué)習(xí)和使用成本。
Outbound操作由業(yè)務(wù)線程執(zhí)行,通常業(yè)務(wù)會(huì)使用線程池并行處理業(yè)務(wù)消息,這就意味著在某一個(gè)時(shí)刻會(huì)有多個(gè)業(yè)務(wù)線程同時(shí)操作ChannelHandler,我們需要對(duì)ChannelHandler進(jìn)行并發(fā)保護(hù),通常需要加鎖。如果同步塊的范圍不當(dāng),可能會(huì)導(dǎo)致嚴(yán)重的性能瓶頸,這對(duì)開發(fā)者的技能要求非常高,降低了開發(fā)效率。
Outbound操作過程中,例如消息編碼異常,會(huì)產(chǎn)生Exception,它會(huì)被轉(zhuǎn)換成Inbound的Exception并通知到ChannelPipeline,這就意味著業(yè)務(wù)線程發(fā)起了Inbound操作!它打破了Inbound操作由I/O線程操作的模型,如果開發(fā)者按照Inbound操作只會(huì)由一個(gè)I/O線程執(zhí)行的約束進(jìn)行設(shè)計(jì),則會(huì)發(fā)生線程并發(fā)訪問安全問題。由于該場(chǎng)景只在特定異常時(shí)發(fā)生,因此錯(cuò)誤非常隱蔽!一旦在生產(chǎn)環(huán)境中發(fā)生此類線程并發(fā)問題,定位難度和成本都非常大。
講了這么多,似乎Netty 4 完勝 Netty 3的線程模型,其實(shí)并不盡然。在特定的場(chǎng)景下,Netty 3的性能可能更高,如果編碼和其它Outbound操作非常耗時(shí),由多個(gè)業(yè)務(wù)線程并發(fā)執(zhí)行,性能肯定高于單個(gè)NioEventLoop線程。
但是,這種性能優(yōu)勢(shì)不是不可逆轉(zhuǎn)的,如果我們修改業(yè)務(wù)代碼,將耗時(shí)的Handler操作前置,Outbound操作不做復(fù)雜業(yè)務(wù)邏輯處理,性能同樣不輸于Netty 3,但是考慮內(nèi)存池優(yōu)化、不會(huì)反復(fù)創(chuàng)建Event、不需要對(duì)Handler加鎖等Netty 4的優(yōu)化,整體性能Netty 4版本肯定會(huì)更高。
2.2 Netty 4.X版本線程模型實(shí)踐經(jīng)驗(yàn)
2.2.1 時(shí)間可控的簡(jiǎn)單業(yè)務(wù)直接在I/O線程上處理
如果業(yè)務(wù)非常簡(jiǎn)單,執(zhí)行時(shí)間非常短,不需要與外部網(wǎng)元交互、訪問數(shù)據(jù)庫(kù)和磁盤,不需要等待其它資源,則建議直接在業(yè)務(wù)ChannelHandler中執(zhí)行,不需要再啟業(yè)務(wù)的線程或者線程池。避免線程上下文切換,也不存在線程并發(fā)問題。
2.2.2 復(fù)雜和時(shí)間不可控業(yè)務(wù)建議投遞到后端業(yè)務(wù)線程池統(tǒng)一處理
對(duì)于此類業(yè)務(wù),不建議直接在業(yè)務(wù)ChannelHandler中啟動(dòng)線程或者線程池處理,建議將不同的業(yè)務(wù)統(tǒng)一封裝成Task,統(tǒng)一投遞到后端的業(yè)務(wù)線程池中進(jìn)行處理。
過多的業(yè)務(wù)ChannelHandler會(huì)帶來開發(fā)效率和可維護(hù)性問題,不要把Netty當(dāng)作業(yè)務(wù)容器,對(duì)于大多數(shù)復(fù)雜的業(yè)務(wù)產(chǎn)品,仍然需要集成或者開發(fā)自己的業(yè)務(wù)容器,做好和Netty的架構(gòu)分層。
2.2.3 業(yè)務(wù)線程避免直接操作ChannelHandler
對(duì)于ChannelHandler,I/O線程和業(yè)務(wù)線程都可能會(huì)操作,因?yàn)闃I(yè)務(wù)通常是多線程模型,這樣就會(huì)存在多線程操作ChannelHandler。為了盡量避免多線程并發(fā)問題,建議按照Netty自身的做法,通過將操作封裝成獨(dú)立的Task由NioEventLoop統(tǒng)一執(zhí)行,而不是業(yè)務(wù)線程直接操作。
3. gRPC線程模型
gRPC的線程模型主要包括服務(wù)端線程模型和客戶端線程模型,其中服務(wù)端線程模型主要包括:
服務(wù)端監(jiān)聽和客戶端接入線程(HTTP /2 Acceptor)。
網(wǎng)絡(luò)I/O讀寫線程。
服務(wù)接口調(diào)用線程。
客戶端線程模型主要包括:
客戶端連接線程(HTTP/2 Connector)。
網(wǎng)絡(luò)I/O讀寫線程。
接口調(diào)用線程。
響應(yīng)回調(diào)通知線程。
3.1 服務(wù)端線程模型
gRPC服務(wù)端線程模型整體上可以分為兩大類:
網(wǎng)絡(luò)通信相關(guān)的線程模型,基于Netty4.1的線程模型實(shí)現(xiàn)。
服務(wù)接口調(diào)用線程模型,基于JDK線程池實(shí)現(xiàn)。
3.1.1 服務(wù)端線程模型概述
gRPC服務(wù)端線程模型和交互圖如下所示:
圖6 gRPC服務(wù)端線程模型其中,HTTP/2服務(wù)端創(chuàng)建、HTTP/2請(qǐng)求消息的接入和響應(yīng)發(fā)送都由Netty負(fù)責(zé),gRPC消息的序列化和反序列化、以及應(yīng)用服務(wù)接口的調(diào)用由gRPC的SerializingExecutor線程池負(fù)責(zé)。
3.1.2 服務(wù)調(diào)度線程模型
gRPC服務(wù)調(diào)度線程主要職責(zé)如下:
請(qǐng)求消息的反序列化,主要包括:HTTP/2 Header的反序列化,以及將PB(Body)反序列化為請(qǐng)求對(duì)象。
服務(wù)接口的調(diào)用,method.invoke(非反射機(jī)制)。
將響應(yīng)消息封裝成WriteQueue.QueuedCommand,寫入到Netty Channel中,同時(shí),對(duì)響應(yīng)Header和Body對(duì)象做序列化。
服務(wù)端調(diào)度的核心是SerializingExecutor,它同時(shí)實(shí)現(xiàn)了JDK的Executor和Runnable接口,既是一個(gè)線程池,同時(shí)也是一個(gè)Task。
SerializingExecutor聚合了JDK的Executor,由Executor負(fù)責(zé)Runnable的執(zhí)行,代碼示例如下:
其中,Executor默認(rèn)使用的是JDK的CachedThreadPool,在構(gòu)建ServerImpl的時(shí)候進(jìn)行初始化,代碼如下:
當(dāng)服務(wù)端接收到客戶端HTTP/2請(qǐng)求消息時(shí),由Netty的NioEventLoop線程切換到gRPC的SerializingExecutor,進(jìn)行消息的反序列化、以及服務(wù)接口的調(diào)用,代碼示例如下:
相關(guān)的調(diào)用堆棧,示例如下:
響應(yīng)消息的發(fā)送,由SerializingExecutor發(fā)起,將響應(yīng)消息頭和消息體序列化,然后分別封裝成SendResponseHeadersCommand和SendGrpcFrameCommand,調(diào)用Netty NioSocketChannle的write方法,發(fā)送到Netty的ChannelPipeline中,由gRPC的NettyServerHandler攔截之后,真正寫入到SocketChannel中,代碼如下所示:
響應(yīng)消息體的發(fā)送堆棧如下所示:
Netty I/O線程和服務(wù)調(diào)度線程的運(yùn)行分工界面以及切換點(diǎn)如下所示:
圖7 網(wǎng)絡(luò)I/O線程和服務(wù)調(diào)度線程交互圖事實(shí)上,在實(shí)際服務(wù)接口調(diào)用過程中,NIO線程和服務(wù)調(diào)用線程切換次數(shù)遠(yuǎn)遠(yuǎn)超過4次,頻繁的線程切換對(duì)gRPC的性能帶來了一定的損耗。
3.2 客戶端線程模型
gRPC客戶端的線程主要分為三類:
業(yè)務(wù)調(diào)用線程。
客戶端連接和I/O讀寫線程。
請(qǐng)求消息業(yè)務(wù)處理和響應(yīng)回調(diào)線程。
3.2.1 客戶端線程模型概述
gRPC客戶端線程模型工作原理如下圖所示(同步阻塞調(diào)用為例):
圖8 客戶端調(diào)用線程模型客戶端調(diào)用主要涉及的線程包括:
應(yīng)用線程,負(fù)責(zé)調(diào)用gRPC服務(wù)端并獲取響應(yīng),其中請(qǐng)求消息的序列化由該線程負(fù)責(zé)。
客戶端負(fù)載均衡以及Netty Client創(chuàng)建,由grpc-default-executor線程池負(fù)責(zé)。
HTTP/2客戶端鏈路創(chuàng)建、網(wǎng)絡(luò)I/O數(shù)據(jù)的讀寫,由Netty NioEventLoop線程負(fù)責(zé)。
響應(yīng)消息的反序列化由SerializingExecutor負(fù)責(zé),與服務(wù)端不同的是,客戶端使用的是ThreadlessExecutor,并非JDK線程池。
SerializingExecutor通過調(diào)用responseFuture的set(value),喚醒阻塞的應(yīng)用線程,完成一次RPC調(diào)用。
3.2.2 客戶端調(diào)用線程模型
客戶端調(diào)用線程交互流程如下所示:
圖9 客戶端線程交互原理圖請(qǐng)求消息的發(fā)送由用戶線程發(fā)起,相關(guān)代碼示例如下:
HTTP/2 Header的創(chuàng)建、以及請(qǐng)求參數(shù)反序列化為Protobuf,均由用戶線程負(fù)責(zé)完成,相關(guān)代碼示例如下:
用戶線程將請(qǐng)求消息封裝成CreateStreamCommand和SendGrpcFrameCommand,發(fā)送到Netty的ChannelPipeline中,然后返回,完成線程切換。后續(xù)操作由Netty NIO線程負(fù)責(zé),相關(guān)代碼示例如下:
客戶端響應(yīng)消息的接收,由gRPC的NettyClientHandler負(fù)責(zé),相關(guān)代碼如下所示:
接收到HTTP/2響應(yīng)之后,Netty將消息投遞到SerializingExecutor,由SerializingExecutor的ThreadlessExecutor負(fù)責(zé)響應(yīng)的反序列化,以及responseFuture的設(shè)值,相關(guān)代碼示例如下:
3.3 線程模型總結(jié)
消息的序列化和反序列化均由gRPC線程負(fù)責(zé),而沒有在Netty的Handler中做CodeC,原因如下:Netty4優(yōu)化了線程模型,所有業(yè)務(wù)Handler都由Netty的I/O線程負(fù)責(zé),通過串行化的方式消除鎖競(jìng)爭(zhēng),原理如下所示:
圖10 Netty4串行執(zhí)行Handler如果大量的Handler都在Netty I/O線程中執(zhí)行,一旦某些Handler執(zhí)行比較耗時(shí),則可能會(huì)反向影響I/O操作的執(zhí)行,像序列化和反序列化操作,都是CPU密集型操作,更適合在業(yè)務(wù)應(yīng)用線程池中執(zhí)行,提升并發(fā)處理能力。因此,gRPC并沒有在I/O線程中做消息的序列化和反序列化。
4. Apache ServiceComb微服務(wù)框架線程模型
Apache ServiceComb底層通信框架基于Vert.X(Netty)構(gòu)建,它重用了Netty的EventLoop線程模型,考慮到目前同步RPC調(diào)用仍然是主流模式,因此,針對(duì)同步RPC調(diào)用,在Vert.X線程模型基礎(chǔ)之上,提供了額外的線程模型封裝。
下面我們分別對(duì)同步和異步模式的線程模型進(jìn)行分析。
4.1 同步模式
核心設(shè)計(jì)理念是I/O線程(協(xié)議棧)和微服務(wù)調(diào)用線程分離,線程調(diào)度模型如下所示:
圖11 ServiceComb內(nèi)置線程池同步模式下ServiceComb的線程模型特點(diǎn)如下:
線程池用于執(zhí)行同步模式的業(yè)務(wù)邏輯。
網(wǎng)絡(luò)收發(fā)及reactive模式的業(yè)務(wù)邏輯在Eventloop中執(zhí)行,與線程池?zé)o關(guān)。
默認(rèn)所有同步方法都在一個(gè)全局內(nèi)置線程池中執(zhí)行。
如果業(yè)務(wù)有特殊的需求,可以指定使用自定義的全局線程池,并且可以根據(jù)schemaId或operationId指定各自使用獨(dú)立的線程池,實(shí)現(xiàn)隔離倉(cāng)的效果。
基于ServiceComb定制線程池策略實(shí)現(xiàn)的微服務(wù)隔離倉(cāng)效果如下所示:
圖12 基于ServiceComb的微服務(wù)故障隔離倉(cāng)4.2 異步模式
ServiceComb的異步模式即純Reactive機(jī)制,它的代碼示例如下:
public interface Intf{ CompletableFuture\u0026lt;String\u0026gt; hello(String name);}@GetMapping(path = \u0026quot;/hello/{name}\u0026quot;)public CompletableFuture\u0026lt;String\u0026gt; hello(@PathVariable(name = \u0026quot;name\u0026quot;) String name){ CompletableFuture\u0026lt;String\u0026gt; future = new CompletableFuture\u0026lt;\u0026gt;(); intf.hello(name).whenComplete((result, exception) -\u0026gt; { if (exception == null) { future.complete(\u0026quot;from remote: \u0026quot; + result); return; } future.completeExceptionally(exception); }); return future;與之對(duì)應(yīng)的線程調(diào)度流程如下所示:
圖13 基于ServiceComb的Reactive線程模型它的特點(diǎn)總結(jié)如下:
所有功能都在eventloop中執(zhí)行,并不會(huì)進(jìn)行線程切換。
橙色箭頭走完后,對(duì)本線程的占用即完成了,不會(huì)阻塞等待應(yīng)答,該線程可以處理其他任務(wù)。
當(dāng)收到遠(yuǎn)端應(yīng)答后,由網(wǎng)絡(luò)數(shù)據(jù)驅(qū)動(dòng)開始走紅色箭頭的應(yīng)答流程。
只要有任務(wù),線程就不會(huì)停止,會(huì)一直執(zhí)行任務(wù),可以充分利用cpu資源,也不會(huì)產(chǎn)生多余的線程切換,去無謂地消耗cpu。
4.3.線程模型總結(jié)
ServiceComb的同步和異步RPC調(diào)用對(duì)應(yīng)的線程模型存在差異,對(duì)于純Reactive的異步,I/O讀寫與微服務(wù)業(yè)務(wù)邏輯執(zhí)行共用同一個(gè)EventLoop線程,在一次服務(wù)端RPC調(diào)用時(shí)不存在線程切換,性能最優(yōu)。但是,這種模式也存在一些約束,例如要求微服務(wù)業(yè)務(wù)邏輯執(zhí)行過程中不能有任何可能會(huì)導(dǎo)致同步阻塞的操作,包括但不限于數(shù)據(jù)庫(kù)操作、緩存讀寫、第三方HTTP服務(wù)調(diào)用、本地I/O讀寫等(本質(zhì)就是要求全棧異步)。
對(duì)于無法做到全棧異步的業(yè)務(wù),可以使用ServiceComb同步編程模型,同時(shí)根據(jù)不同微服務(wù)接口的重要性和優(yōu)先級(jí),利用定制線程池策略,實(shí)現(xiàn)接口級(jí)的線程隔離。
需要指出的是,ServiceComb根據(jù)接口定義來決定采用哪種線程模型,如果返回值是CompletableFuture,業(yè)務(wù)又沒有對(duì)接口指定額外的線程池,則默認(rèn)采用Reactive模式,即業(yè)務(wù)微服務(wù)接口由Vert.X的EventLoop線程執(zhí)行。
5. 作者簡(jiǎn)介
李林鋒,10年Java NIO、平臺(tái)中間件設(shè)計(jì)和開發(fā)經(jīng)驗(yàn),精通Netty、Mina、分布式服務(wù)框架、API Gateway、PaaS等,《Netty進(jìn)階之路》、《分布式服務(wù)框架原理與實(shí)踐》作者。目前在華為終端應(yīng)用市場(chǎng)負(fù)責(zé)業(yè)務(wù)微服務(wù)化、云化、全球化等相關(guān)設(shè)計(jì)和開發(fā)工作。
聯(lián)系方式:新浪微博 Nettying 微信:Nettying
Email:neu_lilinfeng@sina.com
總結(jié)
以上是生活随笔為你收集整理的Netty和RPC框架线程模型分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Reactor学习笔记
- 下一篇: react篇章-React 组件-向组件