一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - 編程技術(shù) - 如何手?jǐn)]一個(gè)較為完整的RPC框架?

如何手?jǐn)]一個(gè)較為完整的RPC框架?

2022-03-01 22:07Java知音 編程技術(shù)

最近在公司分享了手?jǐn)]RPC,因此做一個(gè)總結(jié)。一起來(lái)看一下吧 。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

概念篇

RPC 是什么?

RPC 稱遠(yuǎn)程過程調(diào)用(Remote Procedure Call),用于解決分布式系統(tǒng)中服務(wù)之間的調(diào)用問題。通俗地講,就是開發(fā)者能夠像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程的服務(wù)。所以,RPC的作用主要體現(xiàn)在這兩個(gè)方面:

  • 屏蔽遠(yuǎn)程調(diào)用跟本地調(diào)用的區(qū)別,讓我們感覺就是調(diào)用項(xiàng)目?jī)?nèi)的方法;
  • 隱藏底層網(wǎng)絡(luò)通信的復(fù)雜性,讓我們更專注于業(yè)務(wù)邏輯。

RPC 框架基本架構(gòu)

下面我們通過一幅圖來(lái)說(shuō)說(shuō) RPC 框架的基本架構(gòu)

如何手?jǐn)]一個(gè)較為完整的RPC框架?

RPC 框架包含三個(gè)最重要的組件,分別是客戶端、服務(wù)端和注冊(cè)中心。在一次 RPC 調(diào)用流程中,這三個(gè)組件是這樣交互的:

  • 服務(wù)端在啟動(dòng)后,會(huì)將它提供的服務(wù)列表發(fā)布到注冊(cè)中心,客戶端向注冊(cè)中心訂閱服務(wù)地址;
  • 客戶端會(huì)通過本地代理模塊 Proxy 調(diào)用服務(wù)端,Proxy 模塊收到負(fù)責(zé)將方法、參數(shù)等數(shù)據(jù)轉(zhuǎn)化成網(wǎng)絡(luò)字節(jié)流;
  • 客戶端從服務(wù)列表中選取其中一個(gè)的服務(wù)地址,并將數(shù)據(jù)通過網(wǎng)絡(luò)發(fā)送給服務(wù)端;
  • 服務(wù)端接收到數(shù)據(jù)后進(jìn)行解碼,得到請(qǐng)求信息;
  • 服務(wù)端根據(jù)解碼后的請(qǐng)求信息調(diào)用對(duì)應(yīng)的服務(wù),然后將調(diào)用結(jié)果返回給客戶端。

RPC 框架通信流程以及涉及到的角色

如何手?jǐn)]一個(gè)較為完整的RPC框架?

從上面這張圖中,可以看見 RPC 框架一般有這些組件:服務(wù)治理(注冊(cè)發(fā)現(xiàn))、負(fù)載均衡、容錯(cuò)、序列化/反序列化、編解碼、網(wǎng)絡(luò)傳輸、線程池、動(dòng)態(tài)代理等角色,當(dāng)然有的RPC框架還會(huì)有連接池、日志、安全等角色。

具體調(diào)用過程

如何手?jǐn)]一個(gè)較為完整的RPC框架?

 

  1. 服務(wù)消費(fèi)方(client)以本地調(diào)用方式調(diào)用服務(wù)
  2. client stub 接收到調(diào)用后負(fù)責(zé)將方法、參數(shù)等封裝成能夠進(jìn)行網(wǎng)絡(luò)傳輸?shù)南Ⅲw
  3. client stub 將消息進(jìn)行編碼并發(fā)送到服務(wù)端
  4. server stub 收到消息后進(jìn)行解碼
  5. server stub 根據(jù)解碼結(jié)果調(diào)用本地的服務(wù)
  6. 本地服務(wù)執(zhí)行并將結(jié)果返回給 server stub
  7. server stub 將返回導(dǎo)入結(jié)果進(jìn)行編碼并發(fā)送至消費(fèi)方
  8. client stub 接收到消息并進(jìn)行解碼
  9. 服務(wù)消費(fèi)方(client)得到結(jié)果

RPC 消息協(xié)議

RPC調(diào)用過程中需要將參數(shù)編組為消息進(jìn)行發(fā)送,接收方需要解組消息為參數(shù),過程處理結(jié)果同樣需要經(jīng)編組、解組。消息由哪些部分構(gòu)成及消息的表示形式就構(gòu)成了消息協(xié)議。

RPC調(diào)用過程中采用的消息協(xié)議稱為RPC消息協(xié)議。

實(shí)戰(zhàn)篇

從上面的概念我們知道一個(gè)RPC框架大概有哪些部分組成,所以在設(shè)計(jì)一個(gè)RPC框架也需要從這些組成部分考慮。從RPC的定義中可以知道,RPC框架需要屏蔽底層細(xì)節(jié),讓用戶感覺調(diào)用遠(yuǎn)程服務(wù)像調(diào)用本地方法一樣簡(jiǎn)單,所以需要考慮這些問題:

  • 用戶使用我們的RPC框架時(shí)如何盡量少的配置
  • 如何將服務(wù)注冊(cè)到ZK(這里注冊(cè)中心選擇ZK)上并且讓用戶無(wú)感知
  • 如何調(diào)用透明(盡量用戶無(wú)感知)的調(diào)用服務(wù)提供者
  • 啟用多個(gè)服務(wù)提供者如何做到動(dòng)態(tài)負(fù)載均衡
  • 框架如何做到能讓用戶自定義擴(kuò)展組件(比如擴(kuò)展自定義負(fù)載均衡策略)
  • 如何定義消息協(xié)議,以及編解碼
  • ...等等

上面這些問題在設(shè)計(jì)這個(gè)RPC框架中都會(huì)給予解決。

技術(shù)選型

  • 注冊(cè)中心 目前成熟的注冊(cè)中心有Zookeeper,Nacos,Consul,Eureka,這里使用ZK作為注冊(cè)中心,沒有提供切換以及用戶自定義注冊(cè)中心的功能。
  • IO通信框架 本實(shí)現(xiàn)采用 Netty 作為底層通信框架,因?yàn)镹etty 是一個(gè)高性能事件驅(qū)動(dòng)型的非阻塞的IO(NIO)框架,沒有提供別的實(shí)現(xiàn),也不支持用戶自定義通信框架
  • 消息協(xié)議 本實(shí)現(xiàn)使用自定義消息協(xié)議,后面會(huì)具體說(shuō)明

項(xiàng)目總體結(jié)構(gòu)

如何手?jǐn)]一個(gè)較為完整的RPC框架?

從這個(gè)結(jié)構(gòu)中可以知道,以rpc命名開頭的是rpc框架的模塊,也是本項(xiàng)目RPC框架的內(nèi)容,而consumer是服務(wù)消費(fèi)者,provider是服務(wù)提供者,provider-api是暴露的服務(wù)API。

整體依賴情況

如何手?jǐn)]一個(gè)較為完整的RPC框架?

項(xiàng)目實(shí)現(xiàn)介紹

要做到用戶使用我們的RPC框架時(shí)盡量少的配置,所以把rpc框架設(shè)計(jì)成一個(gè)starter,用戶只要依賴這個(gè)starter,基本那就可以了。

為什么要設(shè)計(jì)成兩個(gè) starter (client-starter/server-starter) ?

這個(gè)是為了更好的體現(xiàn)出客戶端和服務(wù)端的概念,消費(fèi)者依賴客戶端,服務(wù)提供者依賴服務(wù)端,還有就是最小化依賴。

為什么要設(shè)計(jì)成 starter ?

基于spring boot自動(dòng)裝配機(jī)制,會(huì)加載starter中的 spring.factories 文件,在文件中配置以下代碼,這里我們starter的配置類就生效了,在配置類里面配置一些需要的bean。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.rrtv.rpc.client.config.RpcClientAutoConfiguration

發(fā)布服務(wù)和消費(fèi)服務(wù)

  • 對(duì)于發(fā)布服務(wù)

服務(wù)提供者需要在暴露的服務(wù)上增加注解 @RpcService,這個(gè)自定義注解是基于 @service 的,是一個(gè)復(fù)合注解,具備@service注解的功能,在@RpcService注解中指明服務(wù)接口和服務(wù)版本,發(fā)布服務(wù)到ZK上,會(huì)根據(jù)這個(gè)兩個(gè)元數(shù)據(jù)注冊(cè)

如何手?jǐn)]一個(gè)較為完整的RPC框架?

  • 發(fā)布服務(wù)原理:

服務(wù)提供者啟動(dòng)之后,根據(jù)spring boot自動(dòng)裝配機(jī)制,server-starter的配置類就生效了,在一個(gè) bean 的后置處理器(RpcServerProvider)中獲取被注解 @RpcService 修飾的bean,將注解的元數(shù)據(jù)注冊(cè)到ZK上。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

  • 對(duì)于消費(fèi)服務(wù)

消費(fèi)服務(wù)需要使用自定義的 @RpcAutowired 注解標(biāo)識(shí),是一個(gè)復(fù)合注解,基于 @Autowired。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

  • 消費(fèi)服務(wù)原理

要讓客戶端無(wú)感知的調(diào)用服務(wù)提供者,就需要使用動(dòng)態(tài)代理,如上面所示, HelloWordService 沒有實(shí)現(xiàn)類,需要給它賦值代理類,在代理類中發(fā)起請(qǐng)求調(diào)用。

基于spring boot自動(dòng)裝配,服務(wù)消費(fèi)者啟動(dòng),bean 后置處理器 RpcClientProcessor 開始工作,它主要是遍歷所有的bean,判斷每個(gè)bean中的屬性是否有被 @RpcAutowired 注解修飾,有的話把該屬性動(dòng)態(tài)賦值代理類,這個(gè)再調(diào)用時(shí)會(huì)調(diào)用代理類的 invoke 方法。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

代理類 invoke 方法通過服務(wù)發(fā)現(xiàn)獲取服務(wù)端元數(shù)據(jù),封裝請(qǐng)求,通過netty發(fā)起調(diào)用。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

注冊(cè)中心

本項(xiàng)目注冊(cè)中心使用ZK,由于注冊(cè)中心被服務(wù)消費(fèi)者和服務(wù)提供者都使用。所以把ZK放在rpc-core模塊。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

rpc-core 這個(gè)模塊如上圖所示,核心功能都在這個(gè)模塊。服務(wù)注冊(cè)在 register 包下。

服務(wù)注冊(cè)接口,具體實(shí)現(xiàn)使用ZK實(shí)現(xiàn)。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

負(fù)載均衡策略

負(fù)載均衡定義在rpc-core中,目前支持輪詢(FullRoundBalance)和隨機(jī)(RandomBalance),默認(rèn)使用隨機(jī)策略。由rpc-client-spring-boot-starter指定。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

通過ZK服務(wù)發(fā)現(xiàn)時(shí)會(huì)找到多個(gè)實(shí)例,然后通過負(fù)載均衡策略獲取其中一個(gè)實(shí)例

如何手?jǐn)]一個(gè)較為完整的RPC框架?

可以在消費(fèi)者中配置 rpc.client.balance=fullRoundBalance 替換,也可以自定義負(fù)載均衡策略,通過實(shí)現(xiàn)接口 LoadBalance,并將創(chuàng)建的類加入IOC容器即可。由于我們配置 @ConditionalOnMissingBean,所以會(huì)優(yōu)先加載用戶自定義的 bean。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

自定義消息協(xié)議、編解碼

所謂協(xié)議,就是通信雙方事先商量好規(guī)則,服務(wù)端知道發(fā)送過來(lái)的數(shù)據(jù)將如何解析。

  • 自定義消息協(xié)議

如何手?jǐn)]一個(gè)較為完整的RPC框架?

  • 魔數(shù):魔數(shù)是通信雙方協(xié)商的一個(gè)暗號(hào),通常采用固定的幾個(gè)字節(jié)表示。魔數(shù)的作用是防止任何人隨便向服務(wù)器的端口上發(fā)送數(shù)據(jù)。例如 java Class 文件開頭就存儲(chǔ)了魔數(shù) 0xCAFEBABE,在加載 Class 文件時(shí)首先會(huì)驗(yàn)證魔數(shù)的正確性
  • 協(xié)議版本號(hào):隨著業(yè)務(wù)需求的變化,協(xié)議可能需要對(duì)結(jié)構(gòu)或字段進(jìn)行改動(dòng),不同版本的協(xié)議對(duì)應(yīng)的解析方法也是不同的。
  • 序列化算法:序列化算法字段表示數(shù)據(jù)發(fā)送方應(yīng)該采用何種方法將請(qǐng)求的對(duì)象轉(zhuǎn)化為二進(jìn)制,以及如何再將二進(jìn)制轉(zhuǎn)化為對(duì)象,如 JSON、Hessian、Java 自帶序列化等。
  • 報(bào)文類型:在不同的業(yè)務(wù)場(chǎng)景中,報(bào)文可能存在不同的類型。RPC 框架中有請(qǐng)求、響應(yīng)、心跳等類型的報(bào)文。
  • 狀態(tài):狀態(tài)字段用于標(biāo)識(shí)請(qǐng)求是否正常(SUCCESS、FAIL)。
  • 消息ID:請(qǐng)求唯一ID,通過這個(gè)請(qǐng)求ID將響應(yīng)關(guān)聯(lián)起來(lái),也可以通過請(qǐng)求ID做鏈路追蹤。
  • 數(shù)據(jù)長(zhǎng)度:標(biāo)明數(shù)據(jù)的長(zhǎng)度,用于判斷是否是一個(gè)完整的數(shù)據(jù)包
  • 數(shù)據(jù)內(nèi)容:請(qǐng)求體內(nèi)容

編解碼

編解碼實(shí)現(xiàn)在 rpc-core 模塊,在包 com.rrtv.rpc.core.codec下。

自定義編碼器通過繼承 netty 的 MessageToByteEncoder>類實(shí)現(xiàn)消息編碼。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

自定義解碼器通過繼承 netty 的 ByteToMessageDecoder類實(shí)現(xiàn)消息解碼。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

如何手?jǐn)]一個(gè)較為完整的RPC框架?

解碼時(shí)需要注意TCP粘包、拆包問題

什么是TCP粘包、拆包

TCP 傳輸協(xié)議是面向流的,沒有數(shù)據(jù)包界限,也就是說(shuō)消息無(wú)邊界。客戶端向服務(wù)端發(fā)送數(shù)據(jù)時(shí),可能將一個(gè)完整的報(bào)文拆分成多個(gè)小報(bào)文進(jìn)行發(fā)送,也可能將多個(gè)報(bào)文合并成一個(gè)大的報(bào)文進(jìn)行發(fā)送。因此就有了拆包和粘包。

在網(wǎng)絡(luò)通信的過程中,每次可以發(fā)送的數(shù)據(jù)包大小是受多種因素限制的,如 MTU 傳輸單元大小、滑動(dòng)窗口等。

所以如果一次傳輸?shù)木W(wǎng)絡(luò)包數(shù)據(jù)大小超過傳輸單元大小,那么我們的數(shù)據(jù)可能會(huì)拆分為多個(gè)數(shù)據(jù)包發(fā)送出去。如果每次請(qǐng)求的網(wǎng)絡(luò)包數(shù)據(jù)都很小,比如一共請(qǐng)求了 10000 次,TCP 并不會(huì)分別發(fā)送 10000 次。TCP采用的 Nagle(批量發(fā)送,主要用于解決頻繁發(fā)送小數(shù)據(jù)包而帶來(lái)的網(wǎng)絡(luò)擁塞問題) 算法對(duì)此作出了優(yōu)化。

所以,網(wǎng)絡(luò)傳輸會(huì)出現(xiàn)這樣:

如何手?jǐn)]一個(gè)較為完整的RPC框架?

tcp_package.png

  1. 服務(wù)端恰巧讀到了兩個(gè)完整的數(shù)據(jù)包 A 和 B,沒有出現(xiàn)拆包/粘包問題;
  2. 服務(wù)端接收到 A 和 B 粘在一起的數(shù)據(jù)包,服務(wù)端需要解析出 A 和 B;
  3. 服務(wù)端收到完整的 A 和 B 的一部分?jǐn)?shù)據(jù)包 B-1,服務(wù)端需要解析出完整的 A,并等待讀取完整的 B 數(shù)據(jù)包;
  4. 服務(wù)端接收到 A 的一部分?jǐn)?shù)據(jù)包 A-1,此時(shí)需要等待接收到完整的 A 數(shù)據(jù)包;
  5. 數(shù)據(jù)包 A 較大,服務(wù)端需要多次才可以接收完數(shù)據(jù)包 A。

如何解決TCP粘包、拆包問題

解決問題的根本手段:找出消息的邊界:

  • 消息長(zhǎng)度固定

每個(gè)數(shù)據(jù)報(bào)文都需要一個(gè)固定的長(zhǎng)度。當(dāng)接收方累計(jì)讀取到固定長(zhǎng)度的報(bào)文后,就認(rèn)為已經(jīng)獲得一個(gè)完整的消息。當(dāng)發(fā)送方的數(shù)據(jù)小于固定長(zhǎng)度時(shí),則需要空位補(bǔ)齊。

消息定長(zhǎng)法使用非常簡(jiǎn)單,但是缺點(diǎn)也非常明顯,無(wú)法很好設(shè)定固定長(zhǎng)度的值,如果長(zhǎng)度太大會(huì)造成字節(jié)浪費(fèi),長(zhǎng)度太小又會(huì)影響消息傳輸,所以在一般情況下消息定長(zhǎng)法不會(huì)被采用。

  • 特定分隔符

在每次發(fā)送報(bào)文的尾部加上特定分隔符,接收方就可以根據(jù)特殊分隔符進(jìn)行消息拆分。分隔符的選擇一定要避免和消息體中字符相同,以免沖突。否則可能出現(xiàn)錯(cuò)誤的消息拆分。比較推薦的做法是將消息進(jìn)行編碼,例如 base64 編碼,然后可以選擇 64 個(gè)編碼字符之外的字符作為特定分隔符

  • 消息長(zhǎng)度 + 消息內(nèi)容

消息長(zhǎng)度 + 消息內(nèi)容是項(xiàng)目開發(fā)中最常用的一種協(xié)議,接收方根據(jù)消息長(zhǎng)度來(lái)讀取消息內(nèi)容。

本項(xiàng)目就是利用 “消息長(zhǎng)度 + 消息內(nèi)容” 方式解決TCP粘包、拆包問題的。所以在解碼時(shí)要判斷數(shù)據(jù)是否夠長(zhǎng)度讀取,沒有不夠說(shuō)明數(shù)據(jù)沒有準(zhǔn)備好,繼續(xù)讀取數(shù)據(jù)并解碼,這里這種方式可以獲取一個(gè)個(gè)完整的數(shù)據(jù)包。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

序列化和反序列化

序列化和反序列化在 rpc-core 模塊 com.rrtv.rpc.core.serialization 包下,提供了 HessianSerialization 和 JsonSerialization 序列化。

默認(rèn)使用 HessianSerialization 序列化。用戶不可以自定義。

序列化性能:

  • 空間上

如何手?jǐn)]一個(gè)較為完整的RPC框架?

serialization_space.png

  • 時(shí)間上

如何手?jǐn)]一個(gè)較為完整的RPC框架?

serialization_time.png

網(wǎng)絡(luò)傳輸,使用netty

netty 代碼固定的,值得注意的是 handler 的順序不能弄錯(cuò),以服務(wù)端為例,編碼是出站操作(可以放在入站后面),解碼和收到響應(yīng)都是入站操作,解碼要在前面。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

image.png

客戶端 RPC 調(diào)用方式

成熟的 RPC 框架一般會(huì)提供四種調(diào)用方式,分別為同步 Sync、異步 Future、回調(diào) Callback和單向 Oneway。

  • Sync 同步調(diào)用

客戶端線程發(fā)起 RPC 調(diào)用后,當(dāng)前線程會(huì)一直阻塞,直至服務(wù)端返回結(jié)果或者處理超時(shí)異常。

如何手?jǐn)]一個(gè)較為完整的RPC框架?

sync.png

  • Future 異步調(diào)用

客戶端發(fā)起調(diào)用后不會(huì)再阻塞等待,而是拿到 RPC 框架返回的 Future 對(duì)象,調(diào)用結(jié)果會(huì)被服務(wù)端緩存,客戶端自行決定后續(xù)何時(shí)獲取返回結(jié)果。當(dāng)客戶端主動(dòng)獲取結(jié)果時(shí),該過程是阻塞等待的

如何手?jǐn)]一個(gè)較為完整的RPC框架?

future.png

  • Callback 回調(diào)調(diào)用

客戶端發(fā)起調(diào)用時(shí),將 Callback 對(duì)象傳遞給 RPC 框架,無(wú)須同步等待返回結(jié)果,直接返回。當(dāng)獲取到服務(wù)端響應(yīng)結(jié)果或者超時(shí)異常后,再執(zhí)行用戶注冊(cè)的 Callback 回調(diào)

如何手?jǐn)]一個(gè)較為完整的RPC框架?

callback.png

  • Oneway 單向調(diào)用

客戶端發(fā)起請(qǐng)求之后直接返回,忽略返回結(jié)果

如何手?jǐn)]一個(gè)較為完整的RPC框架?

oneway.png

這里使用的是第一種:客戶端同步調(diào)用,其他的沒有實(shí)現(xiàn)。邏輯在 RpcFuture 中,使用 CountDownLatch 實(shí)現(xiàn)阻塞等待(超時(shí)等待)

如何手?jǐn)]一個(gè)較為完整的RPC框架?

整體架構(gòu)和流程

如何手?jǐn)]一個(gè)較為完整的RPC框架?

流程分為三塊:服務(wù)提供者啟動(dòng)流程、服務(wù)消費(fèi)者啟動(dòng)、調(diào)用過程

服務(wù)提供者啟動(dòng)

  1. 服務(wù)提供者 provider 會(huì)依賴 rpc-server-spring-boot-starter
  2. ProviderApplication 啟動(dòng),根據(jù)springboot 自動(dòng)裝配機(jī)制,RpcServerAutoConfiguration 自動(dòng)配置生效
  3. RpcServerProvider 是一個(gè)bean后置處理器,會(huì)發(fā)布服務(wù),將服務(wù)元數(shù)據(jù)注冊(cè)到ZK上
  4. RpcServerProvider.run 方法會(huì)開啟一個(gè) netty 服務(wù)

服務(wù)消費(fèi)者啟動(dòng)

  1. 服務(wù)消費(fèi)者 consumer 會(huì)依賴 rpc-client-spring-boot-starter
  2. ConsumerApplication 啟動(dòng),根據(jù)springboot 自動(dòng)裝配機(jī)制,RpcClientAutoConfiguration 自動(dòng)配置生效
  3. 將服務(wù)發(fā)現(xiàn)、負(fù)載均衡、代理等bean加入IOC容器
  4. 后置處理器 RpcClientProcessor 會(huì)掃描 bean ,將被 @RpcAutowired 修飾的屬性動(dòng)態(tài)賦值為代理對(duì)象

調(diào)用過程

  1. 服務(wù)消費(fèi)者 發(fā)起請(qǐng)求http://localhost:9090/hello/world?name=hello
  2. 服務(wù)消費(fèi)者 調(diào)用 helloWordService.sayHello() 方法,會(huì)被代理到執(zhí)行 ClientStubInvocationHandler.invoke() 方法
  3. 服務(wù)消費(fèi)者 通過ZK服務(wù)發(fā)現(xiàn)獲取服務(wù)元數(shù)據(jù),找不到報(bào)錯(cuò)404
  4. 服務(wù)消費(fèi)者 自定義協(xié)議,封裝請(qǐng)求頭和請(qǐng)求體
  5. 服務(wù)消費(fèi)者 通過自定義編碼器 RpcEncoder 將消息編碼
  6. 服務(wù)消費(fèi)者 通過 服務(wù)發(fā)現(xiàn)獲取到服務(wù)提供者的ip和端口, 通過Netty網(wǎng)絡(luò)傳輸層發(fā)起調(diào)用
  7. 服務(wù)消費(fèi)者 通過 RpcFuture 進(jìn)入返回結(jié)果(超時(shí))等待
  8. 服務(wù)提供者 收到消費(fèi)者請(qǐng)求
  9. 服務(wù)提供者 將消息通過自定義解碼器 RpcDecoder 解碼
  10. 服務(wù)提供者 解碼之后的數(shù)據(jù)發(fā)送到 RpcRequestHandler 中進(jìn)行處理,通過反射調(diào)用執(zhí)行服務(wù)端本地方法并獲取結(jié)果
  11. 服務(wù)提供者 將執(zhí)行的結(jié)果通過 編碼器 RpcEncoder 將消息編碼。(由于請(qǐng)求和響應(yīng)的協(xié)議是一樣,所以編碼器和解碼器可以用一套)
  12. 服務(wù)消費(fèi)者 將消息通過自定義解碼器 RpcDecoder 解碼
  13. 服務(wù)消費(fèi)者 通過RpcResponseHandler將消息寫入 請(qǐng)求和響應(yīng) 池中,并設(shè)置 RpcFuture 的響應(yīng)結(jié)果
  14. 服務(wù)消費(fèi)者 獲取到結(jié)果

以上流程具體可以結(jié)合代碼分析,代碼后面會(huì)給出

環(huán)境搭建

  • 操作系統(tǒng):Windows
  • 集成開發(fā)工具:IntelliJ IDEA
  • 項(xiàng)目技術(shù)棧:SpringBoot 2.5.2 + JDK 1.8 + Netty 4.1.42.Final
  • 項(xiàng)目依賴管理工具:Maven 4.0.0
  • 注冊(cè)中心:Zookeeeper 3.7.0

項(xiàng)目測(cè)試

  • 啟動(dòng) Zookeeper 服務(wù)器:bin/zkServer.cmd
  • 啟動(dòng) provider 模塊 ProviderApplication
  • 啟動(dòng) consumer 模塊 ConsumerApplication
  • 測(cè)試:瀏覽器輸入 http://localhost:9090/hello/world?name=hello,成功返回 您好:hello, rpc 調(diào)用成功

項(xiàng)目代碼地址

https://gitee.com/listen_w/rpc.git

原文地址:https://mp.weixin.qq.com/s/wqs7QjdzikH96Gl1TK6knA

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 色哟哟在线资源 | 阿 好深 快点 老师受不了 | 91午夜在线观看 | h杯奶水太多h | 欧美日韩免费一区二区在线观看 | 精品免费久久久久久影院 | 免费91麻豆精品国产自产在线观看 | 美女mm131爽爽爽久久 | 高清在线免费 | 久久综合狠狠综合久久综合88 | 门卫老张和女警花小说 | 四虎成人影院 | 四虎精品在线视频 | 精品午夜寂寞影院在线观看 | 精品国产精品国产 | 欧美xxoo做爰猛烈视频 | 出差被灌醉绝伦的上司日本 | 国产一区二区三区水野朝阳 | 国产成人精品999在线 | 国产成人99久久亚洲综合精品 | 毛片资源站 | 国产成人高清精品免费5388密 | 思思玖玖玖在线精品视频 | 丝袜老师好湿好紧我要进去了 | 丁香六月色 | 免费毛片| 欧美男男xxx激情做受 | 精品99视频 | 免费永久观看美女视频网站网址 | 亚洲精品123区在线观看 | 女人扒开下面让男人桶爽视频 | 国产精品久久久精品日日 | 亚洲欧美影院 | 大乳女子一级毛片 | 亚洲国产精品久久无套麻豆 | 小柔的性放荡羞辱日记动漫 | 华人亚洲欧美精品国产 | 四虎精品免费国产成人 | 国产精品对白刺激久久久 | 97青草香蕉依人在线播放 | 四虎影视在线看免费 720p |