RPC就是把攔截到的方法參數(shù),轉(zhuǎn)成可以在網(wǎng)絡(luò)中傳輸?shù)亩M制,并保證在服務(wù)提供方能正確地還原出語義,最終實現(xiàn)像調(diào)用本地一樣地調(diào)用遠程的目的。
1 RPC架構(gòu)
RPC本質(zhì)遠程調(diào)用,就要通過網(wǎng)絡(luò)來傳輸數(shù)據(jù)??紤]到可靠性,一般默認采用TCP協(xié)議。為屏蔽網(wǎng)絡(luò)傳輸復雜性,要封裝一個單獨的數(shù)據(jù)傳輸模塊收發(fā)二進制數(shù)據(jù),即傳輸模塊。
用戶請求是基于方法調(diào)用,方法出入?yún)?shù)都是對象數(shù)據(jù),要提前轉(zhuǎn)成二進制,即序列化過程。但只是把方法調(diào)用參數(shù)的二進制數(shù)據(jù)傳輸?shù)椒?wù)提供方不夠,要在方法調(diào)用參數(shù)的二進制數(shù)據(jù)后增加“斷句”符,分隔出不同的請求,在兩個“斷句”符號中間放的內(nèi)容就是請求的二進制數(shù)據(jù),即協(xié)議封裝。
這兩個不同過程目的一樣,保證數(shù)據(jù)在網(wǎng)絡(luò)中正確傳輸:
數(shù)據(jù)能夠傳輸
傳輸后能正確還原出傳輸前的語義
可把這兩個處理過程放在架構(gòu)中的同一個模塊,統(tǒng)稱為協(xié)議模塊。
還可在協(xié)議模塊加壓縮功能,壓縮過程也是對傳輸?shù)亩M制數(shù)據(jù)進行操作。在實際網(wǎng)絡(luò)傳輸過程中,請求數(shù)據(jù)包在數(shù)據(jù)鏈路層可能因太大而被拆分成多個數(shù)據(jù)包進行傳輸,為減少被拆分次數(shù),導致整個傳輸過程時間太長,可在RPC調(diào)用時:在方法調(diào)用參數(shù)或者返回值的二進制數(shù)據(jù)大于某個閾值的情況下,我們可以通過壓縮框架進行無損壓縮,然后在另外一端也用同樣的壓縮算法進行解壓,保證數(shù)據(jù)可還原。
傳輸和協(xié)議兩模塊是RPC最基礎(chǔ)功能,它們使對象可正確傳輸?shù)椒?wù)提供方。但距離RPC目標——實現(xiàn)像調(diào)用本地一樣調(diào)用遠程,還缺點。要讓這兩個模塊同時工作,要手寫一些黏合代碼,但這些代碼對使用RPC的研發(fā)無意義,且屬于一個重復工作,導致使用體驗不友好。
要在RPC里把這些細節(jié)對研發(fā)屏蔽,讓他們感覺不到本地調(diào)用和遠程調(diào)用區(qū)別。假設(shè)有用到Spring,希望RPC能讓我們把一個RPC接口定義成一個Spring Bean,并且這個Bean也會統(tǒng)一被Spring Bean Factory管理,可在項目中通過Spring依賴注入到方式引用。這是RPC調(diào)用的入口,一般叫Bootstrap模塊。
點對點(Point to Point)版本的RPC框架就完成了,一般這種模式的RPC框架為單機版,沒有集群能力。
集群能力:針對同一接口有多個服務(wù)提供者,但這多個服務(wù)提供者對調(diào)用方透明,所以在RPC里還要給調(diào)用方找到所有的服務(wù)提供方,并在RPC里維護好接口跟服務(wù)提供者地址的關(guān)系,調(diào)用方在發(fā)起請求時,才能快速找到對應接收地址,即“服務(wù)發(fā)現(xiàn)”。
但服務(wù)發(fā)現(xiàn)只解決接口和服務(wù)提供方地址映射關(guān)系查找,是一種“靜態(tài)數(shù)據(jù)”,對RPC來說,每次發(fā)送請求時都要用TCP連接的,相對服務(wù)提供方IP地址,TCP連接狀態(tài)瞬息萬變,所以RPC框架要有連接管理器去維護TCP連接狀態(tài)。
有了集群,提供方可能就需要管理好這些服務(wù),RPC就要內(nèi)置一些服務(wù)治理功能,如服務(wù)提供方權(quán)重的設(shè)置、調(diào)用授權(quán)等一些常規(guī)治理手段。而服務(wù)調(diào)用方需要額外做哪些事?每次調(diào)用前,都要根據(jù)服務(wù)提供方設(shè)置的規(guī)則,從集群中選擇可用的連接,以發(fā)送請求。
按分層設(shè)計原則,將這些功能模塊分為:
2 可擴展架構(gòu)
RPC框架怎么支持插件化架構(gòu)?可將每個功能點抽象成一個接口,將這個接口作為插件契約,然后把這個功能的接口與功能實現(xiàn)分離,并提供接口默認實現(xiàn)。
JDK自帶SPI可動態(tài)為某接口尋找服務(wù)實現(xiàn),要在Classpath下的META-INF/services目錄創(chuàng)建一個以服務(wù)接口命名的文件,文件內(nèi)容就是接口具體實現(xiàn)類。
JDK自帶SPI的缺陷
不能按需加載,ServiceLoader加載某接口實現(xiàn)類時,會遍歷全部獲取,即接口的實現(xiàn)類得全部載入并實例化,造成不必要浪費。
擴展如果依賴其它的擴展,就做不到自動注入和裝配,很難和其他框架集成,如擴展里面依賴了一個Spring Bean,原生Java SPI就不支持。
加上插件功能,RPC框架就包含了兩大核心體系——核心功能體系與插件體系:
整個架構(gòu)就成了一個微內(nèi)核架構(gòu),我們將每個功能點抽象成一個接口,將這個接口作為插件的契約,然后把這個功能的接口與功能的實現(xiàn)分離并提供接口的默認實現(xiàn)。
這樣的架構(gòu)可擴展性好,實現(xiàn)開閉原則,用戶方便通過插件擴展實現(xiàn)功能,而且不需要修改核心功能本身
保持了核心包的精簡,依賴外部包少,有效減少開發(fā)人員引入RPC導致的包版本沖突問題。
3 總結(jié)
我們都知道軟件開發(fā)的過程很復雜,不僅是因為業(yè)務(wù)需求經(jīng)常變化,更難的是在開發(fā)過程中要保證團隊成員的目標統(tǒng)一。我們需要用一種可溝通的話語、可“觸摸”的愿景達成目標,我認為這就是軟件架構(gòu)設(shè)計的意義。
但僅從功能角度設(shè)計出的軟件架構(gòu)并不夠健壯,系統(tǒng)不僅要能正確地運行,還要以最低的成本進行可持續(xù)的維護,因此我們十分有必要關(guān)注系統(tǒng)的可擴展性。只有這樣,才能滿足業(yè)務(wù)變化的需求,讓系統(tǒng)的生命力不斷延伸。
4 FAQ
① 使用jmeter進行壓力測試。jmeter官網(wǎng)中支持進行定制sampler取樣器,寫好的jar包放在lib\ext下,再啟動jmter時就能看到了。
插件化是一個概念,有很多種實現(xiàn)方式,這種也算。
② spring的spring.factories這一套也是利用的面向接口編程,感覺比jdk自帶的spi也好很多,既然有些問題,那為啥jdk的spi不優(yōu)化一下?
jdk我理解更多是標準。
③ jdk自帶spi一般會有一個接口加載很多實現(xiàn)類的情況嗎,因為只能用迭代器遍歷,導致只能用類型判斷才能找到自己想要的類,這樣感覺不夠優(yōu)雅吧,所以我感覺應該都是一個接口配置一個實現(xiàn)類這樣就是使用者想要的情況了。
那樣插件的意義就不存在了!
④ 業(yè)務(wù)為工業(yè)設(shè)備聯(lián)網(wǎng)數(shù)據(jù)采集,設(shè)備種類和型號繁多,產(chǎn)品中通過抽象出一套“驅(qū)動”的概念,把每類設(shè)備當作一個插件開發(fā),整體產(chǎn)品架構(gòu)不變,感覺有點這個概念。只是產(chǎn)品還不夠大,其他插件體系還不夠明確
- [03-26]電纜溝蓋板吊環(huán)怎么安裝
- [02-18]電纜溝蓋板標準尺寸有哪幾種規(guī)格?
- [11-09]電纜溝蓋板吊環(huán)怎么安裝
- [03-27]電纜溝蓋板揭蓋計算
- [11-08]電纜溝的蓋板開啟后的正確使用方法
- [11-23]Rpc蓋板電纜溝蓋板材料哪種好?
- [11-27]山東電纜溝承重型蓋板
- [03-31]電纜溝蓋板鍍鋅方式分為冷鍍鋅和熱鍍鋅
- [08-27]RPC電纜溝蓋板的厚度標準是多少
- [08-17]電纜溝蓋板滿足什么特點
- [03-10]RPC活性粉末混凝土蓋板的發(fā)展
- [03-07]電纜溝蓋板在生產(chǎn)時需要注意哪些危險操作
- [03-06]RPC蓋板的蒸壓工藝
- [03-03]高鐵上的電纜溝槽為什么要用RPC蓋板?
- [03-02]超高性能混凝土的強度能達到多少?
- [02-27]關(guān)于電力蓋板出現(xiàn)凹陷的幾個原因
- [02-25]影響電纜溝蓋板壽命的因素,你知道有哪些?
- [02-24]復合井蓋相比于傳統(tǒng)井蓋有哪些優(yōu)點
- [02-19]RPC蓋板的環(huán)保措施有哪些
- [02-14]RPC蓋板環(huán)保措施有哪些呢