概述
众所流传,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 |
| |
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效率要高一点
- 请求头较小,没有额外信息。
- http的编解码工作由http服务器做一层编解码,再由我们的应用服务器做一次编解码(如json)才到我们的jvm之中。而dubbo这种一般不需要二次编码,直接编码二进制,然后传输。
最后
以上就是烂漫发带为你收集整理的Dubbo源码解析(十二)dubbo 协议探秘的全部内容,希望文章能够帮你解决Dubbo源码解析(十二)dubbo 协议探秘所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复