原文見:http://blog.csdn.net/hzzhoushaoyu/article/details/43273099
一、前言
部門去年年中開始各種改造,第一步是模塊服務(wù)化,這邊初選dubbo試用在一些非重要模塊上,慢慢引入到一些稍微重要的功能上,半年時間,學(xué)習(xí)過程及線上使用遇到的些問題在此總結(jié)下。
整理這篇文章差不多花了兩天半時間,請尊重勞動成果,如轉(zhuǎn)載請注明出處http://blog.csdn.net/hzzhoushaoyu/article/details/43273099
二、什么是dubbo
Dubbo是阿里巴巴提供的開源的SOA服務(wù)化治理的技術(shù)框架,據(jù)說只是剖出來的一部分開源的,但一些基本的需求已經(jīng)可以滿足的,而且擴展性也非常好(至今沒領(lǐng)悟到擴展性怎么做到的),通過spring bean的方式管理配置及實例,較容易上手且對應(yīng)用無侵入。更多介紹可戳http://alibaba.github.io/dubbo-doc-static/Home-zh.htm。
三、如何使用dubbo
1.服務(wù)化應(yīng)用基本框架

如上圖所示,一個抽象出來的基本框架,consumer和provider是框架中必然存在的,Registry做為全局配置信息管理模塊,推薦生產(chǎn)環(huán)境使用Registry,可實時推送現(xiàn)存活的服務(wù)提供者,Monitor一般用于監(jiān)控和統(tǒng)計RPC調(diào)用情況、成功率、失敗率等情況,讓開發(fā)及運維了解線上運行情況。
應(yīng)用執(zhí)行過程大致如下:
- 服務(wù)提供者啟動,根據(jù)協(xié)議信息綁定到配置的IP和端口上,如果已有服務(wù)綁定過相同IP和端口的則跳過
- 注冊服務(wù)信息至注冊中心
- 客戶端啟動,根據(jù)接口和協(xié)議信息訂閱注冊中心中注冊的服務(wù),注冊中心將存活的服務(wù)地址通知到客戶端,當有服務(wù)信息變更時客戶端可以通過定時通知得到變更信息
- 在客戶端需要調(diào)用服務(wù)時,從內(nèi)存中拿到上次通知的所有存活服務(wù)地址,根據(jù)路由信息和負載均衡機制選擇最終調(diào)用的服務(wù)地址,發(fā)起調(diào)用
- 通過filter分別在客戶端發(fā)送請求前和服務(wù)端接收請求后,通過異步記錄一些需要的信息傳遞到monitor做監(jiān)控或者統(tǒng)計
2.服務(wù)接口定義
一般單獨有一個jar包,維護服務(wù)接口定義、RPC參數(shù)類型、RPC返回類型、接口異常、接口用到的常量,該jar包中不處理任何業(yè)務(wù)邏輯。
比如命名api-0.1.jar,在api-0.1.jar中定義接口
- public interface UserService
- {
- public RpcResponseDto isValidUser(RpcAccountRequestDto requestDto) throws new RpcBusinessException, RpcSystemException;
- }
并在api-0.1.jar中定義RpcResponseDto,RpcAccountRequestDto,RpcBusinessException,RpcSystemException。服務(wù)端通過引用該jar包實現(xiàn)接口并暴露服務(wù),客戶端引用該jar包引用接口的代理實例。
3.注冊中心
開源的dubbo已支持4種組件作為注冊中心,我們部門使用推薦的zookeeper做為注冊中心,由于就瓶頸來說不會出現(xiàn)在注冊中心,風(fēng)險較低,未做特別的研究或比較。
- zookeeper,推薦集群中部署奇數(shù)個節(jié)點,由于zookeeper掛掉一半的機器集群就不可用,所以部署4臺和3臺的集群都是在掛掉2臺后集群不可用
- redis
- multicast,廣播受到網(wǎng)絡(luò)結(jié)構(gòu)的影響,一般本地不想搭注冊中心的話使用這種調(diào)用
- dubbo簡易注冊中心
對于zookeeper客戶端,dubbo在2.2.0之后默認使用zkclient,2.3.0之后提供可選配置Curator,提到這個點的原因主要是因為zkclient發(fā)現(xiàn)一些問題:①服務(wù)器在修改服務(wù)器時間后zkClient會拋出日志錯誤之類的異常然后容器(我們使用resin)掛掉了,也不能確定就是zkClient的問題,接入dubbo之前無該問題②dubbo使用zkclient不傳入連接zookeeper等待超時時間,使用默認的Integer.MAX_VALUE,這樣在zookeeper連不上的情況下不報錯也無法啟動;目前我們準備尋找其他解決方案,比如使用curator試下,還沒正式投入。
4.服務(wù)端
配置應(yīng)用名
- <dubbo:application name="test"/>
配置dubbo注解識別處理器,不指定包名的話會在spring bean中查找對應(yīng)實例的類配置了dubbo注解的配置注冊中心,通過group指定注冊中心分組,可通過register配置是否注冊到該注冊中心以及subscribe配置是否從該注冊中心訂閱
- <dubbo:registry address="zookeeper://127.0.0.1:2181/" group="test"/>
配置服務(wù)協(xié)議,多網(wǎng)卡可通過IP指定綁定的IP地址,不指定或者指定非法IP的情況下會綁定在0.0.0.0,使用Dubbo協(xié)議的服務(wù)會在初始化時建立長連接- <dubbo:protocol name="dubbo" port="20880" accesslog="d:/access.log"></dubbo:protocol>
通過xml配置文件配置服務(wù)暴露,首先要有個spring bean實例(無論是注解配置的還是配置文件配置的),在下面ref中指定bean實例ID,作為服務(wù)實現(xiàn)類- <dubbo:service interface="com.web.foo.service.FirstDubboService" ref="firstDubboServiceImpl" version="1.0"></dubbo:service>
通過注解方式配置服務(wù)暴露,Component是Spring bean注解,Service是dubbo的注解(不要和spring bean的service注解弄混),如前文所述,dubbo注解只會在spring bean中被識別- @Component
- @Service(version="1.0")
- public class FirstDubboServiceImpl implements FirstDubboService
- {
-
- @Override
- public void sayHello(TestDto test)
- {
- System.out.println("Hello World!");
- }
-
- }
5.客戶端
同服務(wù)端配置應(yīng)用名、注解識別處理器和注冊中心。
配置客戶端reference bean??蛻舳烁?wù)端不同的是客戶端這邊沒有實際的實現(xiàn)類的,所以配置的dubbo:reference實際會生成一個spring bean實例,作為代理處理Dubbo請求,然后其他要調(diào)用處直接使用spring bean的方式使用這個實例即可。xml配置文件配置方式,id即為spring bean的id,之后無論是在spring配置中使用ref="firstDubboService"還是通過@Autowired注解都OK
- <dubbo:reference interface="com.web.foo.service.FirstDubboService"
- version="1.0" id="firstDubboService" ></dubbo:reference>
另外開發(fā)、測試環(huán)境可通過指定Url方式繞過注冊中心直連指定的服務(wù)地址,避免注冊中心中服務(wù)過多,啟動建立連接時間過長,如
- <dubbo:reference interface="com.web.foo.service.FirstDubboService"
- version="1.0" id="firstDubboService" url="dubbo://127.0.0.1:20880/"></dubbo:reference>
注解配置方式引用,- @Component
- public class Consumer
- {
- @Reference(version="1.0")
- private FirstDubboService service;
-
- public void test()
- {
- TestDto test = new TestDto();
- test.setList(Arrays.asList(new String[]{"a", "b"}));
- test.setTest("t");
- service.sayHello(test);
- }
- }
Reference被識別的條件是spring bean實例對應(yīng)的當前類中的field,如上是直接修飾spring bean當前類中的屬性這個地方看了下源碼,本應(yīng)該支持當前類和父類中的public set方法,但是看起來是個BUG,Dubbo處理reference處部分源碼如下
- Method[] methods = bean.getClass().getMethods();
- for (Method method : methods) {
- String name = method.getName();
- if (name.length() > 3 && name.startsWith("set")
- && method.getParameterTypes().length == 1
- && Modifier.isPublic(method.getModifiers())
- && ! Modifier.isStatic(method.getModifiers())) {
- try {
- Reference reference = method.getAnnotation(Reference.class);
- if (reference != null) {
- Object value = refer(reference, method.getParameterTypes()[0]);
- if (value != null) {
- method.invoke(bean, new Object[] { });//??這里不是應(yīng)該把value作為參數(shù)調(diào)用么,而且為什么上面if條件判斷參數(shù)為1這里不傳參數(shù)
- }
- }
- } catch (Throwable e) {
- logger.error("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
- }
- }
- }
6.監(jiān)控中心
如果使用Dubbo自帶的監(jiān)控中心,可通過簡單配置即可,先通過github獲得dubbo-monitor的源碼,部署啟動后在應(yīng)用配置如下
- <dubbo:monitor protocol="registry" /> <!--通過注冊中心獲取monitor地址后建立連接-->
- <dubbo:monitor address="dubbo://127.0.0.1:7070/com.alibaba.dubbo.monitor.MonitorService" /> <!--繞過注冊中心直連monitor,同consumer直連-->
7.服務(wù)路由
最重要輔助功能之一,可隨時配置路由規(guī)則調(diào)整客戶端調(diào)用策略,目前dubbo-admin中已提供基本路由規(guī)則的配置UI,到github下載源碼部署后很容易找到地方,這里簡單介紹下怎么用路由。
下面是dubbo-admin的新建路由界面,可配置信息都在圖片中有,
比如現(xiàn)在我們有10.0.0.1~3三臺消費者和10.0.0.4~6三臺服務(wù)提供者,想讓1和2調(diào)用4,3調(diào)用5和6的話,則可以配置兩個規(guī)則,
1.消費者IP:10.0.0.1,10.0.0.2 ;提供者IP:10.0.0.4
2.消費者IP:10.0.0.3;提供者IP:10.0.0.5,10.0.0.6
另外,IP地址支持結(jié)尾為*匹配所有,如10.0.0.*或者10.0.*等。
不匹配的配置規(guī)則和匹配的配置規(guī)則是一致的。
配置完成后可在消費者標簽頁查看路由結(jié)果
8.負載均衡
dubbo提供4種負載均衡方式:
- Random,隨機,按權(quán)重配置隨機概率,調(diào)用量越大分布越均勻,默認是這種方式
- RoundRobin,輪詢,按權(quán)重設(shè)置輪詢比例,如果存在比較慢的機器容易在這臺機器的請求阻塞較多
- LeastActive,最少活躍調(diào)用數(shù),不支持權(quán)重,只能根據(jù)自動識別的活躍數(shù)分配,不能靈活調(diào)配
- ConsistentHash,一致性hash,對相同參數(shù)的請求路由到一個服務(wù)提供者上,如果有類似灰度發(fā)布需求可采用
dubbo的負載均衡機制是在客戶端調(diào)用時通過內(nèi)存中的服務(wù)方信息及配置的負責(zé)均衡策略選擇,如果對自己系統(tǒng)沒有一個全面認知,建議先采用random方式。
9.dubbo過濾器
有需要自己實現(xiàn)dubbo過濾器的,可關(guān)注如下步驟:
- dubbo初始化過程加載META-INF/dubbo/internal/,META-INF/dubbo/,META-INF/services/三個路徑(classloaderresource)下面的com.alibaba.dubbo.rpc.Filter文件
文件配置每行Name=FullClassName,必須是實現(xiàn)Filter接口
@Activate標注擴展能被自動激活
@Activate如果group(provider|consumer)匹配才被加載
@Activate的value字段標明過濾條件,不寫則所有條件下都會被加載,寫了則只有dubbo URL中包含該參數(shù)名且參數(shù)值不為空才被加載
如下是dubbo rpc access log的過濾器,僅對服務(wù)提供方有效,且參數(shù)中需要帶accesslog,也就是配置protocol或者serivce時配置的accesslog="d:/rpc_access.log"
- @Activate(group = Constants.PROVIDER, value = Constants.ACCESS_LOG_KEY)
- public class AccessLogFilter implements Filter {
- }
10.其他特性
- 結(jié)果緩存,省得自己再去寫一個緩存,對緩存沒有特殊要求的話直接使用dubbo的好了
- 分組合并,對RPC接口不同的實現(xiàn)方式分別調(diào)用然后合并結(jié)果的一種調(diào)用模式,比如我們要查用戶是否合法,一種我們要查是否在黑名單,同時我們還要關(guān)注登錄信息是否異常,然后合并結(jié)果
四、前車之鑒
這個主要是在整個學(xué)習(xí)及使用過程中記錄的,以及一些同事在初識過程問過我的,這邊做了整理然后直接列舉在下面:
1.服務(wù)版本號
- <dubbo:serviceinterface=“com.xxx.XxxService” ref=“xxxService” version=“1.0” />
- <dubbo:referenceid=“xxxService” interface=“com.xxx.XxxService” version=“1.0”/>
- 為了今后更換接口定義發(fā)布在線時,可不停機發(fā)布,使用版本號
2.暴露一個內(nèi)網(wǎng)一個外網(wǎng)IP問題
為了在測試環(huán)境提供一個內(nèi)網(wǎng)訪問的地址和一個辦公區(qū)訪問的地址。
•增加一個指定IP為內(nèi)網(wǎng)地址的服務(wù)協(xié)議
•增加一個不指定IP的服務(wù)協(xié)議,但是在/etc/hosts中hostname對應(yīng)的IP要為外網(wǎng)IP
上面這種方案是一開始使用的方案,后面發(fā)現(xiàn)dubbo在啟動過程無論是否配路由還是會一個個去連接,雖然不影響啟動,但是由于存在超時所以會影響啟動時間,而且每臺機器還得特別配置指定IP,后面使用另外一套方案:- 服務(wù)不配置ip,綁定到0.0.0.0,自動獲取保證獲取到是內(nèi)網(wǎng)IP注冊到注冊中心即可,如果不是想要的IP,可以在/etc/hosts中通過綁定Hostname指定IP
- 內(nèi)網(wǎng)訪問方式通過注冊中心或者直連指定內(nèi)網(wǎng)IP和端口
- 外網(wǎng)訪問方式通過直連指定外網(wǎng)IP和端口
使用這種方式需要注意做好防火墻控制等,比如在線默認也是不指定IP,會綁定在0.0.0.0,如果非法人員知道調(diào)用的外網(wǎng)IP和端口,而且可以直接訪問就麻煩了(如果在應(yīng)用中做IP攔截也成,需要注意有防范措施)。
3.dubbo reference注解問題
前文介紹使用時已經(jīng)提到過,@Reference只能在spring bean實例對應(yīng)的當前類中使用,暫時無法在父類使用;如果確實要在父類聲明一個引用,可通過配置文件配置dubbo:reference,然后在需要引用的地方跟引用spring bean一樣就行
4.服務(wù)超時問題
目前如果存在超時,情況基本都在如下幾點:
- 客戶端耗時大,也就是超時異常時的client elapsed xxx,這個是從創(chuàng)建Future對象開始到使用channel發(fā)出請求的這段時間,中間沒有復(fù)雜操作,只要CPU沒問題基本不會出現(xiàn)大耗時,頂多1ms屬于正常
- IOThread繁忙,默認情況下,dubbo協(xié)議一個客戶端與一個服務(wù)提供者會建立一個共享長連接,如果某個客戶端處于特別繁忙而且一直往一個服務(wù)提供者塞請求,可能造成IOThread阻塞,一般非常特殊的情況才會出現(xiàn)
- 服務(wù)端工作線程池中線程全部繁忙,接收消息后塞入隊列等待,如果等待時間比預(yù)想長會引起超時
- 網(wǎng)絡(luò)抖動,如果上述情況都排除了,還出現(xiàn)在請求發(fā)出后,服務(wù)接收請求前超過預(yù)想時間,只能歸類到網(wǎng)絡(luò)抖動了,需要SA一起查看問題
- 服務(wù)自身耗時大,這個需要應(yīng)用自身做好耗時統(tǒng)計,當出現(xiàn)這種情況的時候需要用數(shù)據(jù)來說明問題及規(guī)劃優(yōu)化方案,建議采用緩存埋點的方式統(tǒng)計服務(wù)中各個執(zhí)行階段的耗時情況,最終如果超過預(yù)想時間則把緩存統(tǒng)計的耗時情況打日志,減少日志量,且能夠得到更明確的信息
現(xiàn)在我們應(yīng)用使用過程中發(fā)現(xiàn)兩種類型的耗時,一種我們目前只能歸類到網(wǎng)絡(luò)抖動,后續(xù)需要找運維一起關(guān)注這個問題,另外一種是由于一些歷史原因,數(shù)據(jù)庫查詢?nèi)菀装l(fā)生抖動,總有一個時間點會突然多出很多超時。
5.服務(wù)保護
服務(wù)保護的原則上是避免發(fā)生類似雪崩效應(yīng),盡量將異??刂圃诜?wù)周圍,不要擴散開。
說到雪崩效應(yīng),還得提下dubbo自身的重試機制,默認3次,當失敗時會進行重試,這樣在某個時間點出現(xiàn)性能問題,然后調(diào)用方再連續(xù)重復(fù)調(diào)用,很容易引起雪崩,建議的話還是很據(jù)業(yè)務(wù)情況規(guī)劃好如何進行異常處理,何時進行重試。
服務(wù)保護的話,目前我們主要從以下幾個方面來實施,也不成熟,還在摸索:
經(jīng)領(lǐng)導(dǎo)推薦,還在學(xué)習(xí)Release it,后續(xù)有其他想法,再回頭來編輯。
6.zkclient的問題
前文已經(jīng)提到過zkclient有兩個問題,修改服務(wù)器時間會導(dǎo)致容器掛掉;dubbo使用zkclient沒有傳超時時間導(dǎo)致zookeeper無法連接的時候,直接阻塞Integer.MAX_VALUE。
正在調(diào)研curator,目前只能說curator不會在無法連接的時候直接阻塞。
另外zkclient和curator的jar包應(yīng)該都是jdk1.6編譯的,所以系統(tǒng)還在jdk1.5以下的話無法使用。
7.注冊中心的分組group和服務(wù)的不同實現(xiàn)group
這兩個東西完全不同的概念,使用的時候不要弄混了。
registry上可以配置group,用于區(qū)分不同分組的注冊中心,比如在同一個注冊中心下,有一部分注冊信息是要給開發(fā)環(huán)境用的,有一部分注冊信息時要給測試環(huán)境用的,可以分別用不同的group區(qū)分開,目前對這個理解還不透徹,大致就是用于區(qū)分不同環(huán)境。
service和reference上也可以配置group,這個用于區(qū)分同一個接口的不同實現(xiàn),只有在reference上指定與service相同的group才會被發(fā)現(xiàn),還有前文提到的分組合并結(jié)果也是用的這個。
五、dubbo如何工作的
其實dubbo整個框架內(nèi)容并不算大,仔細看的話可能最多兩天看完一遍,但是目前還是沒領(lǐng)悟到怎么做到的擴展性,學(xué)習(xí)深度還不夠~
要學(xué)習(xí)dubbo源碼的話,必須要拿出官方高清大圖才行。
這張圖看起來挺復(fù)雜的樣子,真正拆分之后對照源碼來看會發(fā)現(xiàn)非常清晰、簡單直觀。
1.如何跟進源碼
入口就是各種dubbo配置項的解析,<dubbo:xxx />都是spring namespace,可以看到dubbo jar包下META-INF里面的spring.handlers,自定義的spring namespace處理器。
對于spring不太熟的同學(xué)可以先了解下這個功能,入口都在這里,解析成功后每個<dubbo:xxx />配置項都對應(yīng)一個spring實例。
2.服務(wù)提供者
首先把這張圖拆分成三塊,首先是服務(wù)端剖去網(wǎng)絡(luò)傳輸模塊,也就是大圖中的右上角。
這里主要抽幾個主要的類,從服務(wù)初始化到接收消息的流程簡單說明下,有興趣的再對照源碼看下會比較清晰。
繼承ServiceConfig,做為服務(wù)配置管理和配置信息校驗,每一個dubbo:service配置或者注解都會對應(yīng)生成一個ServiceBean的實例,維護當前服務(wù)的配置信息,并把一些全局配置塞入到該服務(wù)配置中。
另外ServiceBean本身是一個InitializingBean,在afterPropertiesSet時通過配置信息引導(dǎo)服務(wù)綁定和注冊。
可以留意到ServiceBean還實現(xiàn)了ApplicationListener,在全部spring bean加載完成后判斷是否延遲加載的邏輯。
經(jīng)過serviceBean引導(dǎo)后進入該類,這個地方注意下,Protocol使用的裝飾模式,葉子只有DubboProtocol和RegistryProtocol,在中間調(diào)用中會繞來繞去,而且registry會走一遍這個流程,然后在RegistryProtocol中暴露服務(wù)再走一遍,注意每個類的作用,不要被繞昏了就行,第一次跟進代碼的時候沒留意就暈頭轉(zhuǎn)向的。
在這之前其實還有個ProtocolListenerWrapper,封裝監(jiān)聽器,在服務(wù)暴露后通知到監(jiān)聽器,沒有復(fù)雜邏輯,如果沒特殊需求可以先繞過。
再來說ProtocolFIlterWrapper,這個類的作用就是串聯(lián)filter調(diào)用鏈,如果有看過struts或者spring mvc攔截器源碼的應(yīng)該不會陌生。
注冊中心協(xié)議,如果配置了注冊中心地址,每次服務(wù)暴露肯定首先引導(dǎo)進入這個類中,如果沒有注冊中心連接則會先創(chuàng)建連接,然后再引導(dǎo)真正的服務(wù)協(xié)議暴露流程,會再走一次ProtocolFilterWrapper的流程(這次引導(dǎo)到的葉子是DubboProtocol)。
在服務(wù)暴露返回后,會再執(zhí)行服務(wù)信息的注冊和訂閱操作。
這個類的export相對較簡單,就是引導(dǎo)服務(wù)bind server socket。
另外該類還提供了一個內(nèi)部類,用于處理接收請求,就是下面要提到的ExchangeHandler。
- DubboProtocol$ExchangeHandler
接收反序列化好的請求消息,然后根據(jù)請求信息找到執(zhí)行鏈,將請求再丟入執(zhí)行鏈,讓其最終執(zhí)行到實現(xiàn)類再將執(zhí)行結(jié)果返回即整個過程完成。
3.客戶端
客戶端模塊與服務(wù)端模塊比較類似,只是剛好反過來,一個是暴露服務(wù),一個是引用服務(wù),然后客戶端多出路由和負載均衡。

繼承ReferenceConfig,維護配置信息和配置信息的校驗,該功能與ServiceBean類似
其本身還實現(xiàn)了FactoryBean,作為實例工廠,創(chuàng)建遠程調(diào)用代理類;而且如果不指定為init的reference都是在首次getBean的時候調(diào)用到該factoryBean的getObject才進行初始化
另外實現(xiàn)了InitializingBean,在初始化過程中引導(dǎo)配置信息初始化和構(gòu)建init的代理實例
看到這個類名應(yīng)該就知道是動態(tài)代理的handler,這里作為遠程調(diào)用代理類的處理器在客戶端調(diào)用接口時引導(dǎo)進入invoker調(diào)用鏈
與Service那邊的功能類似,構(gòu)建調(diào)用鏈
與service那邊類似,如果與注冊中心還沒有連接則建立連接,之后注冊和訂閱,再根據(jù)配置的策略返回相應(yīng)的clusterInvoker
比service那邊有個隱藏較深的邏輯需要留意的,就是訂閱過程,RegistryDirectory作為訂閱監(jiān)聽器,在訂閱完成后會通知到RegistryDirectory,然后會刷新invoker,進入引導(dǎo)至DubboProtocol的流程,與變更的service建立長連接,第一次發(fā)生訂閱時就會同步接收到通知并將已存在的service存到字典
在訂閱過程中發(fā)現(xiàn)有service變更則會引導(dǎo)至這里,與服務(wù)建立長連接,整個過程為了得到串聯(lián)執(zhí)行鏈Invoker
ClusterInvoker由RegistryProtocol構(gòu)建完成后,內(nèi)部封裝了Directory,在調(diào)用時會從Directory列舉存活的service對應(yīng)的Invoker,Directory作為被通知對象,在service有變更時也會及時得到通知
調(diào)用時在集群中發(fā)現(xiàn)存在多節(jié)點的話都會通過clusterInvoker來根據(jù)配置抉擇最終調(diào)用的節(jié)點,包括路由方式、負載均衡等
dubbo本身支持的節(jié)點調(diào)用策略包括比如failoverClusterInvoker在失敗時進行重試其他節(jié)點,failfastClusterInvoker在失敗時返回異常,mergeableClusterInvoker則是對多個實現(xiàn)結(jié)果進行合并的等等很多
承接上層的調(diào)用信息,作為調(diào)用結(jié)構(gòu)的葉子,將信息傳遞到exchange層,主要用來和echange交互的功能模塊
4.網(wǎng)絡(luò)傳輸層
從exchange往下都是算網(wǎng)絡(luò)傳輸,包括做序列化、反序列化,使用Netty等IO框架發(fā)送接收消息等邏輯,先前看的時候沒有做統(tǒng)一梳理,后續(xù)有機會再來編輯吧。