Dubbo RPC執行緒模型 原始碼分析

Ziegler Han發表於2020-12-29

協議啟動流程

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執行緒。

 

相關文章