我是靠谱客的博主 烂漫发带,最近开发中收集的这篇文章主要介绍Dubbo源码解析(十二)dubbo 协议探秘,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

众所流传,rpc协议十高性能的协议,是远超http协议的性能呢,但是现在由于异构跨语言系统的之间的交互与调用,从而springcloud 大放异彩,而springcloud 使用的就是http协议,当前跨语言协议还有thrift,protobuff、avro等。当然之前dubbo是hession序列化,导致只有java客户端。但是现在已经dubbo-nodejs,dubbo-php这些项目了(还没看,囧)。

那么这个dubbo协议长什么样呢,在我们眼中的http、tcp协议的包体应该都历历在目。大约是header + body,当然这个dubbo也不失众人所望,仍是如此结构
在这里插入图片描述

Header

详细头总共有128位,即16字节,第0-15位是MagicNumer

下标说明
0-7高位魔法数
8-15低位魔法数
16标记消息是请求(1)还是响应(0)
17标记消息是否需要返回,1需要返回,0不需要
18标记消息是心跳、连接、断开这种事件还是普通的请求响应,1表示事件
19-23标记此消息的序列化方式,fastjson是6
24-31
  • 20 - OK
  • 30 - CLIENT_TIMEOUT
  • 31 - SERVER_TIMEOUT
  • 40 - BAD_REQUEST
  • 50 - BAD_RESPONSE
  • 60 - SERVICE_NOT_FOUND
  • 70 - SERVICE_ERROR
  • 80 - SERVER_ERROR
  • 90 - CLIENT_ERROR
  • 100 - SERVER_THREADPOOL_EXHAUSTED
32-95请求ID,Long类型
96-127消息体长度,Integer类型

消息体

128之后表示消息体内容,但是有个注意的点,他是有一定顺序的。在使用hession序列化的时候,直接使用的是writeUTF方法。

  • Dubbo version
  • Service name
  • Service version
  • Method name
  • Method parameter types
  • Method arguments
  • Attachments
    看一看代码,或许就比较清晰了。

hession2编码相关代码

        RpcInvocation inv = (RpcInvocation) data;

        out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION));
        out.writeUTF(inv.getAttachment(Constants.PATH_KEY));
        out.writeUTF(inv.getAttachment(Constants.VERSION_KEY));

        out.writeUTF(inv.getMethodName());
        out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));
        Object[] args = inv.getArguments();
        if (args != null)
            for (int i = 0; i < args.length; i++) {
                out.writeObject(encodeInvocationArgument(channel, inv, i));
            }
        out.writeObject(inv.getAttachments());

hession2解码相关代码

public Object decode(Channel channel, InputStream input) throws IOException {
        ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
                .deserialize(channel.getUrl(), input);
        // 1. 读取dubbo-version
        setAttachment(Constants.DUBBO_VERSION_KEY, in.readUTF());
        // 2. 读取服务path
        setAttachment(Constants.PATH_KEY, in.readUTF());
        // 3. 读取服务version
        setAttachment(Constants.VERSION_KEY, in.readUTF());
        
        // 4. 读取远程方法名
        setMethodName(in.readUTF());
        try {
            Object[] args;
            Class<?>[] pts;
            // 读取方法参数描述
            // @see ReflectUtils.getDesc(Class<?> clazz)
            String desc = in.readUTF();
            if (desc.length() == 0) {
                pts = DubboCodec.EMPTY_CLASS_ARRAY;
                args = DubboCodec.EMPTY_OBJECT_ARRAY;
            } else {
                // 解析
                pts = ReflectUtils.desc2classArray(desc);
                args = new Object[pts.length];
                for (int i = 0; i < args.length; i++) {
                    try {
                        // 遍历读取参数
                        args[i] = in.readObject(pts[i]);
                    } catch (Exception e) {
                        if (log.isWarnEnabled()) {
                            log.warn("Decode argument failed: " + e.getMessage(), e);
                        }
                    }
                }
            }
            // 设置方法参数类型
            setParameterTypes(pts);
            
            // 读取attachments
            Map<String, String> map = (Map<String, String>) in.readObject(Map.class);
            if (map != null && map.size() > 0) {
                Map<String, String> attachment = getAttachments();
                if (attachment == null) {
                    attachment = new HashMap<String, String>();
                }
                attachment.putAll(map);
                setAttachments(attachment);
            }
            //判断是否是callback
            for (int i = 0; i < args.length; i++) {
                args[i] = decodeInvocationArgument(channel, this, pts, i, args[i]);
            }
            
            // 设置args 
            setArguments(args);

        } catch (ClassNotFoundException e) {
            throw new IOException(StringUtils.toString("Read invocation data failed.", e));
        } finally {
            if (in instanceof Cleanable) {
                ((Cleanable) in).cleanup();
            }
        }
        return this;
    }

看了这个协议,或许明白了些许为什么比http效率要高一点

  1. 请求头较小,没有额外信息。
  2. http的编解码工作由http服务器做一层编解码,再由我们的应用服务器做一次编解码(如json)才到我们的jvm之中。而dubbo这种一般不需要二次编码,直接编码二进制,然后传输。

最后

以上就是烂漫发带为你收集整理的Dubbo源码解析(十二)dubbo 协议探秘的全部内容,希望文章能够帮你解决Dubbo源码解析(十二)dubbo 协议探秘所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部