注:文章中使用的dubbo源碼版本為2.5.4
零、文章目錄
- Consumer發送請求
- Provider接收請求并發送響應
- Consumer接收響應
一、Consumer發送請求
1.1 代碼入口
- 在 dubbo剖析:二 服務引用 中講到,服務引用方根據引用接口
DemoService
,使用dubbo的代理工廠類JavassistProxyFactory.getProxy()
創建出該接口的動態代理對象。 - 當用戶想調用
DemoService
的相關方法時,實際是調用了代理對象的相關方法,從InvokerInvocationHandler.invoke()
進入Consumer請求發送流程。
1.2 整體流程
- 上圖從上往下展示了服務引用方發送一個RPC請求的關鍵步驟,經歷了“代理層”、“集群層”、“過濾監聽擴展點”、“調用協議層”、“信息交換層”、“網絡傳輸層”。
- 紫色實線條表示各層關鍵類的方法調用,藍色虛線表示關鍵類的初始化過程。
1)代理執行(InvokerInvocationHandler.invoke):
- 服務引用的過程中,由
ReferenceConfig
使用JavassistProxyFactory
為引用接口創建了代理對象; - 服務引用方調用dubbo代理類
DemoService.sayHello
時,實際執行InvokerInvocationHandler.invoke()
方法,即這是Consumer發送請求的起點; -
InvokerInvocationHandler
內包含一個Invoker
,在JavassistProxyFactory.getProxy()
過程中通過其構造器注入,該Invoker
為一個集群路由功能的AbstractClusterInvoker
;
2)集群容錯+負載均衡(AbstractClusterInvoker.invoke):
- 服務引用的過程中,由
RegistryProtocol
使用Cluster.join()
創建集群Invoker
,Cluster
由ExtensionLoader.getExtensionLoader(Cluster.class).getExtension("mergeable")
動態生成; - 集群
Invoker
根據負載均衡算法有多種不同實現類(failover、failfast、failsafe、failback),具體使用哪一種由對應的Cluster
實現決定; -
AbstractClusterInvoker
通過Directory.list()
方法獲取請求路徑對應的Invoker
列表; -
AbstractClusterInvoker
再通過LoadBalance.select()
方法從多個Invoker
中選取一個做本次調用,即負載均衡算法(Random、RoundRobin、LeastActive);
3)Filter鏈擴展點(ProtocolFilterWrapper + ProtocolListenerWrapper):
- 在
ReferenceConfig
進行服務引用的過程中,通過refProtocol.refer()
創建Invoker
對象; -
refprotocol.refer()
先后經過修飾類ProtocolFilterWrapper
、ProtocolListenerWrapper
,最后執行RegistryProtocol
;ProtocolFilterWrapper
和ProtocolListenerWrapper
就是Dubbo
引入的擴展點; - 擴展點對請求發送和接收的核心功能流程無影響,目的是以插件的方式進行一些輔助功能處理,這里不再進一步展開;
4)調用協議層執行(AbstractInvoker.invoke):
- 經過集群路由和擴展點,現在將直接執行
AbstractInvoker.invoke
方法,開始真正的遠程調用了; - 服務引用的過程中,由
RegistryDirectory
使用Protocol.refer()
創建遠程執行AbstractInvoker
,Protocol
默認采用default實現,即DubboProtocol
; -
AbstractInvoker
有多種協議的具體實現(dubbo、rmi、hessian、http),具體使用哪一種協議由對應的Protocol
實現決定,默認采用dubbo協議為DubboInvoker
; -
DubboInvoker
中包含了ExchangeClient
的引用,通過DubboInvoker
的構造器注入;
5)交換層執行(ExchangeClient.request):
- 遠程執行
Invoker
通過其引用的ExchangeClient.request
完成遠程調用請求的發送并得到ResponseFuture
,然后調用ResponseFuture.get()
得到 遠程調用結果Result
; - 服務引用的過程中,由
DubboProtocol
使用Exchanger.connect()
創建ExchangeClient
; -
Exchanger
的實現類為HeaderExchanger
,由ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type)
動態生成; -
ExchangeClient
在Client
的基礎上封裝了請求響應模式(其以Request、Response、ResponseFuture為核心,后續單獨文章講解),這也是交換層的核心功能;
6)網絡層執行(Client.send):
- 交換層
ExchangeClient.request
封裝請求響應模式后,最終依賴網絡層Client.send
將請求消息通過網絡發送給服務提供方; - 服務引用的過程中,由
HeaderExchanger
使用Transporter.connect()
創建Client
并完成初始連接操作,Client
有多種網絡層實現(netty、mina...),具體使用哪一種由對應的Transporter
實現決定; -
Transporter
有多種網絡層實現(netty、mina...),由ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension()
動態生成,默認為NettyTransporter
; - 最后,
NettyClient
使用其包含的底層NettyChannel
完成網絡消息發送的功能;
二、Provider接收請求并發送響應
2.1 代碼入口
- 在 dubbo剖析:一 服務發布 中講到,服務提供方通過
NettyServer
完成服務端創建及監聽工作。 - 在
NettyServer
的doOpen()
階段創建了網絡事件處理器NettyHandler
,當服務端收到客戶端消息時,將觸發NettyHandler
的messageReceived()
方法。
2.2 整體流程
- 上圖從上往下表示了服務提供方接收到一個網絡請求時的處理步驟,經歷了一個
Handler
處理器鏈,鏈中的每個Handler
負責實現自己的處理功能。
1)Netty網絡事件處理器(NettyHandler):
- 繼承自Netty的原生網絡時間處理器實現類
SimpleChannelHandler
,定義了網絡建連(channelConnected)、斷連(channelDisconnected)、消息接收(messageReceived)、異常(exceptionCaught)等事件處理方法; - 維護了
<ip:port, channel>
的對應關系Map<String, Channel>channels
,在網絡建連/斷連時進行相應put/remove操作,并暴露給NettyServer
使用; - 接收到網絡消息時,執行
messageReceived()
方法,將Netty的原生Channel
轉換為Dubbo封裝的NettyChannel
,并將事件傳遞給其包含的ChannelHandler
處理;
2)復合消息處理器(MultiMessageHandler):
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof MultiMessage) {
MultiMessage list = (MultiMessage) message;
for (Object obj : list) {
handler.received(channel, obj);
}
} else {
handler.received(channel, message);
}
}
- 處理
MultiMessage
,將其拆分成多個Message
處理;
3)心跳消息處理器(HeartbeatHandler):
- 消息收發時重置當前通道的最新消息收發時間,用于配合
HeaderExchangeServer
和HeaderExchangeClient
中的心跳檢測任務HeartBeatTask
; - 攔截并處理心跳請求/響應消息。對心跳請求消息,構建對應的心跳響應消息并通過Channel發送回去;對心跳響應消息,僅記錄日志后返回,不做功能上的處理;
4)業務線程轉換處理器(AllChannelHandler):
-
Dubbo
通過該處理器完成了 IO線程 與 業務線程 的解耦! - 內部封裝了業務線程池,默認使用
FixedThreadPool
;
public class FixedThreadPool implements ThreadPool {
public Executor getExecutor(URL url) {
String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
注意點:
a)線程池默認業務線程數為200
b)隊列默認采用SynchronousQueue
- 將接收到的網絡消息事件封裝成可執行任務
ChannelEventRunnable
,交由業務線程池處理;
5)業務解碼處理器(DecodeHandler):
- 進行業務請求響應的解碼工作;
- 對
Request
和Response
中攜帶的消息體或結果體,如果其實現了Decodeable
接口,則進行一次解碼處理;
6)交換層請求響應處理器(HeaderExchangeHandler):
- 交換層真正完成請求響應收發功能的處理器!
- 將網絡層
Channel
轉換為交換層ExchangeChannel
,為其增加了請求響應方法request()
; - 判斷收到的網絡消息類型,根據類型分別執行不同的處理邏輯;
if (message instanceof Request) {
Request request = (Request) message;
if (request.isEvent()) {
handlerEvent(channel, request);
} else {
//case a: 請求響應模型的請求處理
if (request.isTwoWay()) {
Response response = handleRequest(exchangeChannel, request);
channel.send(response);
}
//case b: 單向消息接收的處理
else {
handler.received(exchangeChannel, request.getData());
}
}
} else if (message instanceof Response) {
//case c: 請求響應模型的響應處理
handleResponse(channel, (Response) message);
}
a)請求響應模型的Request消息:調用ExchangeHandlerAdapter.reply()
獲取執行結果Result
-->
將本地執行結果Result
封裝成RPC響應Response
--> 通過channel.send()
發送RPC響應;
Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException {
Response res = new Response(req.getId(), req.getVersion());
Object msg = req.getData();
try {
// 調用```ExchangeHandlerAdapter.reply()```獲取執行結果```Result```
Object result = handler.reply(channel, msg);
res.setStatus(Response.OK);
res.setResult(result);
} catch (Throwable e) {
res.setStatus(Response.SERVICE_ERROR);
res.setErrorMessage(StringUtils.toString(e));
}
//將本地執行結果```Result```封裝成RPC響應```Response```
return res;
}
b)單向請求消息的處理:調用ExchangeHandlerAdapter.received()
處理請求消息,如果該消息是Invocation
則執行reply()
邏輯但不主動發送RPC響應Response
;
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
reply((ExchangeChannel) channel, message);
} else {
super.received(channel, message);
}
}
c)請求響應模型的Response消息:調用DefaultFuture.received()
處理響應消息。
...注:請求響應模型(Request
,Response
,DufaultFuture
)相關后續專門分析,此處不展開...
7)真正本地實現類方法的執行(ExchangeHandlerAdapter):
-
ExchangeHandlerAdapter
由DubboProtocol
創建,并實現了reply()
方法; -
reply()
方法,實際通過RPC調用參數Invocation
從DubboProtocol.exporterMap
中獲取到對應的本地實現DubboExporter
--> 進而獲取到對應的本地執行AbstractProxyInvoker
--> 最終通過AbstractProxyInvoker.invoke()
方法,以反射的方式執行真正實現類的對應方法,完成RPC請求。
三、Consumer接收響應
整體流程與 “Provider接收請求” 一樣,唯一的區別是在 交換層請求響應處理器(HeaderExchangeHandler
)步驟中會執行 “分支c:請求響應模型的Response消息”,將Response
交由DefaultFuture
處理。