Dubbo RPC執行緒模型 原始碼分析
協議啟動流程
DubboProtocol
DubboProtocol.export
DubboProtocol.openServer
DubboProtocol.createServer
Exchangers.bind(url, requestHandler)
new DubboProtocolServer(server)
HeaderExchanger
public class HeaderExchanger implements Exchanger {
public static final String NAME = "header";
@Override
public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
}
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
}
注意:new DecodeHandler(new HeaderExchangeHandler(handler))
1. IO執行緒。Netty接收訊息(RPC協議解析)
NettyServerHandler.channelRead
NettyServer.received >> 父類AbstractPeer.received
MultiMessageHandler.received
HeartbeatHandler.received
AllChannelHandler.received
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getPreferredExecutorService(message);
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
if(message instanceof Request && t instanceof RejectedExecutionException){
sendFeedback(channel, (Request) message, t);
return;
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
上面可以處理IO執行緒與RPC邏輯執行緒的分開。支援訊息處理派發執行緒池。
參考資料:Dubbo 中的執行緒模型
http://dubbo.apache.org/zh/docs/v2.7/user/examples/thread-model/
<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
2. 邏輯執行緒池。處理RPC:包括解析函式引數,處理service邏輯(不包括IO協議解析)
ChannelEventRunnable 處理rpc執行緒,每個物件處理一個(一次)rpc呼叫,通過執行緒池管理。
ChannelEventRunnable.run
DecodeHandler.received
解碼訊息,使用
@Override
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof Decodeable) {
decode(message);
}
if (message instanceof Request) {
decode(((Request) message).getData());
}
if (message instanceof Response) {
decode(((Response) message).getResult());
}
handler.received(channel, message);
}
rpc引數解析使用Hessian方式解碼
message為DecodeableRpcInvocation
呼叫DecodeableRpcInvocation.decode方法
CodecSupport >> Hessian2Serialization >> Hessian2ObjectInput
引數解碼完成後
呼叫HeaderExchangeHandler.received,然後呼叫 handleRequest(exchangeChannel, request);
@Override
public void received(Channel channel, Object message) throws RemotingException {
final ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
if (message instanceof Request) {
// handle request.
Request request = (Request) message;
if (request.isEvent()) {
handlerEvent(channel, request);
} else {
if (request.isTwoWay()) {
handleRequest(exchangeChannel, request);
} else {
handler.received(exchangeChannel, request.getData());
}
}
} else if (message instanceof Response) {
handleResponse(channel, (Response) message);
} else if (message instanceof String) {
if (isClientSide(channel)) {
Exception e = new Exception("Dubbo client can not supported string message: " + message + " in channel: " + channel + ", url: " + channel.getUrl());
logger.error(e.getMessage(), e);
} else {
String echo = handler.telnet(channel, (String) message);
if (echo != null && echo.length() > 0) {
channel.send(echo);
}
}
} else {
handler.received(exchangeChannel, message);
}
}
handleRequest處理中通過future
void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {
Response res = new Response(req.getId(), req.getVersion());
if (req.isBroken()) {
Object data = req.getData();
String msg;
if (data == null) {
msg = null;
} else if (data instanceof Throwable) {
msg = StringUtils.toString((Throwable) data);
} else {
msg = data.toString();
}
res.setErrorMessage("Fail to decode request due to: " + msg);
res.setStatus(Response.BAD_REQUEST);
channel.send(res);
return;
}
// find handler by message class.
Object msg = req.getData();
try {
CompletionStage<Object> future = handler.reply(channel, msg);
future.whenComplete((appResult, t) -> {
try {
if (t == null) {
res.setStatus(Response.OK);
res.setResult(appResult);
} else {
res.setStatus(Response.SERVICE_ERROR);
res.setErrorMessage(StringUtils.toString(t));
}
channel.send(res);
} catch (RemotingException e) {
logger.warn("Send result to consumer failed, channel is " + channel + ", msg is " + e);
}
});
} catch (Throwable e) {
res.setStatus(Response.SERVICE_ERROR);
res.setErrorMessage(StringUtils.toString(e));
channel.send(res);
}
}
接下來呼叫到DubboProtocol.reply
執行緒模型
DecodeHandler.decode與DubboProtocol.reply,與Service處於相同執行緒。
rpc協議接收應該是使用netty的io執行緒。
相關文章
- Dubbo執行緒模型執行緒模型
- Dubbo的執行緒模型執行緒模型
- Dubbo學習筆記(三) RPC核心原理和執行緒模型筆記RPC執行緒模型
- Spark RPC框架原始碼分析(二)RPC執行時序SparkRPC框架原始碼
- Netty原始碼分析之Reactor執行緒模型詳解Netty原始碼React執行緒模型
- 執行緒池原始碼分析執行緒原始碼
- 執行緒池執行模型原始碼全解析執行緒模型原始碼
- Netty原始碼解析一——執行緒池模型之執行緒池NioEventLoopGroupNetty原始碼執行緒模型OOP
- webrtc執行緒模型分析Web執行緒模型
- Tomcat執行緒模型 BIO模型原始碼與調優Tomcat執行緒模型原始碼
- Python執行緒池ThreadPoolExecutor原始碼分析Python執行緒thread原始碼
- 執行緒池之ScheduledThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- 執行緒池之ThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- Dubbo原始碼淺析(一)—RPC框架與Dubbo原始碼RPC框架
- Java多執行緒之Thread原始碼分析Java執行緒thread原始碼
- Java排程執行緒池ScheduledThreadPoolExecutor原始碼分析Java執行緒thread原始碼
- jdk1.8 執行緒池部分原始碼分析JDK執行緒原始碼
- ConcurrentHashMap執行緒安全機制以及原始碼分析HashMap執行緒原始碼
- 多執行緒基礎(十九):Semaphore原始碼分析執行緒原始碼
- 比特幣原始碼分析:多執行緒檢查指令碼比特幣原始碼執行緒指令碼
- 詳解Java執行緒池的ctl(執行緒池控制狀態)【原始碼分析】Java執行緒原始碼
- [原始碼分析] 分散式任務佇列 Celery 多執行緒模型 之 子程式原始碼分散式佇列執行緒模型
- go rpc 原始碼分析GoRPC原始碼
- 使用 Executors,ThreadPoolExecutor,建立執行緒池,原始碼分析理解thread執行緒原始碼
- JUC(4)---java執行緒池原理及原始碼分析Java執行緒原始碼
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- 執行緒池原始碼探究執行緒原始碼
- 執行緒模型執行緒模型
- 從原始碼分析ConcurrentHashMap執行緒安全和高效的特性原始碼HashMap執行緒
- 執行流程原始碼分析原始碼
- 比特幣原始碼分析--RPC比特幣原始碼RPC
- Redis執行緒模型的原理分析蒼癘Redis執行緒模型
- JDK執行緒池原始碼研究JDK執行緒原始碼
- 以太坊原始碼分析(13)RPC分析原始碼RPC
- Netty原始碼死磕一(netty執行緒模型及EventLoop機制)Netty原始碼執行緒模型OOP
- WPF執行緒模型執行緒模型
- redis執行緒模型Redis執行緒模型
- [10]elasticsearch原始碼深入分析——執行緒池的封裝Elasticsearch原始碼執行緒封裝