dubbo源码分析第十四篇一dubbo远程调用第四小节一服务端收发消息

接收流程概览

  • 先通过dubboCodec将数据缓冲区反序列化request对象
  • DubboCountCodec支持多request对象的处理
  • 通过NettyServerHandler处理核心逻辑
  • NettyServerHandler通过NettyChannel获取映射的NettyServer
  • NettyServer通过received链处理请求事件
  • 发送Response对象时,直调netty的NioSocketChannel
    |NettyServer| MultiMessageHandler |HeatBeatHandler|AllChannelHandler|DecodeHandler|HeaderExchangeHandler|ExchangeHandlerAdapter|
    |–|--|–|--|–|--|–|--|
    | handler链处理引擎入口 | 多消息递归处理 |心跳消息处理|dubbo业务线程池策略|一般不起作用,将invocation和result的编解码从netty 编解码线程池延迟到dubbo线程池|负责请求响应关系处理|查找接口完成接口调用|

在这里插入图片描述

编解码源码分析

InternalDecoder.decode - 接收消息入口

  • 缓冲区可读则不断解码
  • 将缓存区和NettyServer传给dubboCountCodec
  • 解码结果输出到out,传递给nettyServerHandler
protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {
        ChannelBuffer message = new NettyBackedChannelBuffer(input);
        获取nettyServer对象
        NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
        try {
            
            do {
                int saveReaderIndex = message.readerIndex();
                dubboCountCodec解码
                Object msg = codec.decode(channel, message);
                if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
                    message.readerIndex(saveReaderIndex);
                    break;
                } else {
                    
                    if (saveReaderIndex == message.readerIndex()) {
                        throw new IOException("Decode without read data.");
                    }
                    输出到nettyServerHandler [out有值 则会触发输出到nettyServerHandler,netty知识不做介绍]
                    if (msg != null) {
                        out.add(msg);
                    }
                }
            } while (message.readable());
        } finally {
            NettyChannel.removeChannelIfDisconnected(ctx.channel());
        }
    }
}

DubboCountCodec.decode

  • 支持多消息处理
  • 调用dubbocodec完成消息反序列化
 public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
    int save = buffer.readerIndex();
    支持多消息解码
    MultiMessage result = MultiMessage.create();
    解码核心:dubbocodec完成解析 【父类解析request dubbocodec解析invocation】
    do {
        Object obj = codec.decode(channel, buffer);
        if (Codec2.DecodeResult.NEED_MORE_INPUT == obj) {
            buffer.readerIndex(save);
            break;
        } else {
            result.addMessage(obj);
            logMessageLength(obj, buffer.readerIndex() - save);
            save = buffer.readerIndex();
        }
    } while (true);

    if (result.isEmpty()) {
        return Codec2.DecodeResult.NEED_MORE_INPUT;
    }
    一个消息则直接去Request
    if (result.size() == 1) {
        return result.get(0);
    }
    多消息也支持
    return result;
}

ExchangeCodec.decode完成消息体反序列化

  • ExchangeCodec作为父类处理Telnet协议和dubbo协议
  • dubboCodec.decodeBody获取序列化方式解析生成request和invocation
  • decodeBody部分不做讲解 参见扩展点一 dubbo协议报文
protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException {
    这里代码全部删除  处理Telnet协议

	
    
    try {
        根据dubbo协议报文解析request和invocation
        return decodeBody(channel, is, header);
    } finally {
        if (is.available() > 0) {
            try {
                if (logger.isWarnEnabled()) {
                    logger.warn("Skip input stream " + is.available());
                }
                StreamUtils.skipUnusedStream(is);
            } catch (IOException e) {
                logger.warn(e.getMessage(), e);
            }
        }
    }
}

handler源码分析

nettyServerHandler.channelRead入口分析

  • 通过映射机制获取handler->NettyServer
  • 调用NettyServer.received
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    通过映射机制获取NettyServer
    NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
    try {
        调用NettyServer.received
        handler.received(channel, msg);
    } finally {
        NettyChannel.removeChannelIfDisconnected(ctx.channel());
    }
}

MultiMessageHandler.received 多消息处理

  • MultiMessageHandler.received 由NettyServer.received
    调用
    -功能拆分消息,触发下一个Handler调用
public void received(Channel channel, Object message) throws RemotingException {
    拆分消息调用心跳HeatBeatHandler.received
    if (message instanceof MultiMessage) {
        MultiMessage list = (MultiMessage) message;
        for (Object obj : list) {
            handler.received(channel, obj);
        }
    } else {
        handler.received(channel, message);
    }
}

HeatBeatHandler.received心跳消息处理

  • 心跳消息则终止下掉
  • 非心跳消息调用(默认)AllChannelHandler
public void received(Channel channel, Object message) throws RemotingException {
    setReadTimestamp(channel);
    是心跳消息则终止链路调用
    if (isHeartbeatRequest(message)) {
        Request req = (Request) message;
        如果是心跳是双向消息则进行回写 同时保障读写通道的顺畅
        if (req.isTwoWay()) {
            回写心跳响应
            Response res = new Response(req.getId(), req.getVersion());
            res.setEvent(Response.HEARTBEAT_EVENT);
            channel.send(res);
            ...... 删除日志
        }
        return;
    }

    如果是心跳响应则直接终止 心跳由消费者发起,提供者接收
    if (isHeartbeatResponse(message)) {
        ...... 删除日志
        return;
    }
    调用AllChannelHandler 负责线程池隔离io线程池
    handler.received(channel, message);
}

AllChannelHandler.received线程池策略-固定200线程同步池

  • 异步调用剩余的handler链路
  • 线程池默认200线程,
  • 完成netty线程与dubbo线程业务隔离
public void received(Channel channel, Object message) throws RemotingException {
    默认Fixed线程池
    ExecutorService executor = getExecutorService();
    try {
        ChannelEventRunnable负责下一个DecodeHandler调用
        executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
    } catch (Throwable t) {
        
        if(message instanceof Request && t instanceof RejectedExecutionException){
            Request request = (Request)message;
            线程池出问题则响应消费者相关错误
            if(request.isTwoWay()){
                String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
                Response response = new Response(request.getId(), request.getVersion());
                response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
                response.setErrorMessage(msg);
                channel.send(response);
                return;
            }
        }
        throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
    }
}

线程池内核参数

    @Override
    public Executor getExecutor(URL url) {
        String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
        默认200
        int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);
        默认0
        int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
        默认SynchronousQueue  AbortPolicyWithReport
        return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS, 
                queues == 0 ? new SynchronousQueue<Runnable>() :
                        (queues < 0 ? new LinkedBlockingQueue<Runnable>()
                                : new LinkedBlockingQueue<Runnable>(queues)),
                new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
    }

DecodeHandler.received

  • 如果dubbocodec没有解析Request.mData或者Response.mResult
  • 则完成解析,一般默认dubboCodec已经完成解析
  • 作用: 进一步轻量化netty线程工作量
  • 解码内容不做展示,参见扩展点一 dubbo协议报文
public void received(Channel channel, Object message) throws RemotingException {
    if (message instanceof Decodeable) {
        decode(message);
    }
    解析invocation对象  默认序列化是Hessian2
    if (message instanceof Request) {
        decode(((Request) message).getData());
    }
    解析result对象 默认序列化是Hessian2
    if (message instanceof Response) {
        decode(((Response) message).getResult());
    }

    handler.received(channel, message);
}

HeaderExchangeHandler.received一核心:生成Response,发送Response

  • 处理请求或者响应
public void received(Channel channel, Object message) throws RemotingException {
    channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
    final ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
    ...... 删除资源处理代码
    if (message instanceof Request) {
        Request request = (Request) message;
        ...... 删除心跳代码 oneway代码
        处理请求    
        handleRequest(exchangeChannel, request);

    } else if (message instanceof Response) {
    	处理响应,参见消费者接受响应
    	作用,取消消费者业务线程阻塞,消费者获取rpc请求的Response结果
        handleResponse(channel, (Response) message);
    } 
    ...... 删除Telnet协议处理和兜底逻辑
    
}

handleRequest处理请求

  • 调用dubboProtocol.requestHandler完成请求处理[调用dubboInvoker]
  • Response.id = req.getId,用于request-Response映射
  • 输出到消费者Response信息
void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {
    Response res = new Response(req.getId(), req.getVersion());
    ...... 删除破损请求
    Object msg = req.getData();
     ...... 删除其他代码  

    调用dubboProtocol.requestHandler完成请求处理
    CompletionStage<Object> future = handler.reply(channel, msg);
    future.whenComplete((appResult, t) -> {
            if (t == null) {
                res.setStatus(Response.OK);
                res.setResult(appResult);
            } else {
                res.setStatus(Response.SERVICE_ERROR);
                res.setErrorMessage(StringUtils.toString(t));
            }
            请求处理完毕发送消息
            channel.send(res);
        
    });
       
}
DubboProtocol.requestHandler.reply()完成接口调用
  • 完成 dubboInvoker的查找
  • 通过wrapper机制调用目标对象
public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {
    ...... 删除其他代码
    Invocation inv = (Invocation) message;
    通过DubboProtocol协议的exporterMap 获取dubboInvoker
    Invoker<?> invoker = getInvoker(channel, inv);

    RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
    dubboInvoker借助Wrapper完成无反射的业务接口方法调用
    Result result = invoker.invoke(inv);
    return result.completionFuture().thenApply(Function.identity());
}
通过暴露的Invoker集合查找Invoker
  • 查找规则: 接口名 + port + 版本号 + 分组
Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
        
    接口名 + port + 版本号 + 分组
    String serviceKey = serviceKey(port, path, inv.getAttachments().get(VERSION_KEY), inv.getAttachments().get(GROUP_KEY));
    去暴露的Invoker集合查找
    DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
    return exporter.getInvoker();
}
invoker.invoke完成业务接口调用
  • 完成filter链路的处理
  • 支持wapper动态代理类模式避免反射提高性能
 AbstractProxyInvoker<T>(proxy, type, url) {
    @Override
    protected Object doInvoke(T proxy, String methodName,
                              Class<?>[] parameterTypes,
                              Object[] arguments) throws Throwable {
        return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
    }
}
HeaderExchangeChannel.send(res)-发送响应
  • HeaderExchangeChannel的channel属性为nettyChannel
    public void send(Object message, boolean sent) throws RemotingException {
        if (closed) {
            throw new RemotingException(this.getLocalAddress(), null, "Failed to send message " + message + ", cause: The channel " + this + " is closed!");
        }
        if (message instanceof Request
                || message instanceof Response
                || message instanceof String) {
            请求 响应 和telnet
            channel.send(message, sent);
        }
        ...... 删除其他场景
    }
NettyChannel.send
  • NettyChannel的channel为NioSocketChannel
  • netty的channel直接调用三层handler模型,其中nettyServerHandler无实质工作
  • 通过dubboCodec完成编码后输出给消费者
public void send(Object message, boolean sent) throws RemotingException {
	nettyServerHandler基本不起作用,调用编码器完成编码 输出到网卡[flush=true]
    ChannelFuture future = channel.writeAndFlush(message);
}

总结

  • 通过codec完成request的解码和Response的编码
  • 通过request,id = response,id 完成请求响应映射
  • 通过handler链明确各handler职责
  • handler作用于接收消息
  • codec作用于收发消息
  • 编解码默认的序列化工具为hessian2
  • 默认的线程池为200大小的固定池
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值