美文网首页
dubbo rpc 初探

dubbo rpc 初探

作者: 卫渐行 | 来源:发表于2019-12-14 20:50 被阅读0次

    由于网络的抖动的原因,经常在cat监控当中,看到dubbo的com.alibaba.dubbo.rpc.RpcException报错的时候;于是对于dubbo rpc流程,以及请求协议有了一定的兴趣;下面结合dubbo源码以及自己的学习体会,介绍一下dubbo rpc过程,以及dubbo默认的数据包结构;

    dubbo 一次rpc过程

    在看到dubbo rpc的过程,想起了head first 中介绍的命令模式(如下图模型),于是我将两者结合,帮助我理解dubbo rpc的流程(自己理解,不一定特别准确到位)


    image

    按照上面模式,将一次dubbo的调用,划分几个角色:

    • 1: 顾客 本地的HelloService;
    • 2: 订单--> Invocation[sayHello("Hi")] dubbo会将通过rpc的请求封装成本地的代理类,然后通过proxy.invoke(invocation)的方法;能够标准化不同接口的RPC的处理规范
    • 3:女顾客,Invoke,是一个可执行的实体,所有的顾客的请求以及厨师做好的餐点,都要通过女顾客负责转接;客户端会将请求的实体,向女招待元靠拢,并且需要女招待传递到厨师那里;厨师做好的餐点也需要依赖女招待员传递给顾客
    • 4: 厨师:helloServiceImpl,负责方法的实现;

    helloService(顾客) --sayHello("HI")----> dubboInvoker(将请求的实体打包成一个代理类,然后发起doInvoke(Invocation))
    ---Invoke(女招待)--->Requestor---send(request)-->socket-->socketChannelHandle--->socket--->Responseder()---invoke(Invocation 女招待)--->DubboExporter--->helloServiceImpl(getProxy and invoke,厨师)

    helloService(顾客) --sayHello("HI")----> dubboInvoker(将请求的实体打包成一个代理类,然后发起doInvoke(Invocation))
    ---Invoke(女招待)--->Requestor---send(request)-->socket-->socketChannelHandle--->socket--->Responseder()---invoke(Invocation 女招待)--->DubboExporter--->helloServiceImpl(getProxy and invoke,厨师)

    image

    图片来自网络于1

    在dubbo源码中,有三个概念要非常的清楚:

    • protocol : 它是invoker暴露 和引用的主功能入口,他负责Invoker的生命周期的管理
    • invoker : 它是dubbo核心模型,其他模型都会向他靠拢,或是转换成它,它代表一个可执行体;可向他发一个远程的实现,也可以是一个集群的实现
    • Invocation: 它持有调用过程的中变量,比如方法名,以及参数;dubbo请求实体序列化的过程中,主要是将Invacation实例进行序列化;

    下面是官方介绍的,dubbo实现一次dubbo远程调用的过程;


    image

    dubbo rpc 协议

    其中RPC协议指明了程序如何进行序列化和网络传输,也就是说一个RPC协议的实现等于一个非透明的RPC调用。下面主要介绍dubbo默认的自定义的dubbo协议;

    • request body payload:将请求的数据封装成Invocation(接口,参数类型,参数)以及attachement参数进行序列化,按照一定的规则,序列化成固定格式的二进制文件;
    • request header : 魔法数,标志位(请求,响应,事件ID),可以参考以下源码


      image
          Serialization serialization = getSerialization(channel);
        // header. 
        byte[] header = new byte[HEADER_LENGTH];
        // set magic number. 设置魔法数 dabb
        Bytes.short2bytes(MAGIC, header);
        // set request and serialization flag.
        header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());
        //是否又返回值
        if (req.isTwoWay()) {
            header[2] |= FLAG_TWOWAY;
        }
        //是否为事件,heartbeat
        if (req.isEvent()) {
            header[2] |= FLAG_EVENT;
        }
    
        // set request id. 设置requestID,有返回值,根据ID返回,
        Bytes.long2bytes(req.getId(), header, 4);
    
        // encode request data. 对请求实体进行加密
        int savedWriteIndex = buffer.writerIndex();
        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
        ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
        ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
        if (req.isEvent()) {
            encodeEventData(channel, out, req.getData());
        } else {
         //对请求实体,进行序列化
            encodeRequestData(channel, out, req.getData(), req.getVersion());
        }
        out.flushBuffer();
        if (out instanceof Cleanable) {
            ((Cleanable) out).cleanup();
        }
        bos.flush();
        bos.close();
        int len = bos.writtenBytes();
        //检查
        checkPayload(channel, len);
        Bytes.int2bytes(len, header, 12);
    
        // write 写入头部
        buffer.writerIndex(savedWriteIndex);
        buffer.writeBytes(header); // write header.
        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
    

    上面是dubbo请求对象的编码过程,该过程首先会通过位运算将消息头写入到 header 数组中。然后对 Request 对象的 data 字段执行序列化操作,序列化后的数据最终会存储到 ChannelBuffer 中。序列化操作执行完后,可得到数据序列化后的长度 len,紧接着将 len 写入到 header 指定位置处。最后再将消息头字节数组 header 写入到 ChannelBuffer 中,整个编码过程就结束了

    总结:

    上述我们简单介绍了dubbo RPC的过程,并且介绍了三个重要的角色,protocol,invoke,invocation;这能帮助我们从宏观上理解一次RPC过程;其次我们介绍了dubbo自定义的协议,完成了dubbo中用什么数据格式传递数据的问题。

    reference:

    相关文章

      网友评论

          本文标题:dubbo rpc 初探

          本文链接:https://www.haomeiwen.com/subject/pqehnctx.html