搜索关注微信公众号"捉虫大师",后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践。

协议

协议通俗易懂地解释就是通信双方需要遵循的约定。

我们了解的常见的网络传输协议有tcp、udp、http等。再到我们常用的基础组件,一般来说client端与server端也有相应的协议,如redis、mysql、zookeeper等都是各自约定的私有协议,同样今天标题中的dubbo协议也是一种私有协议,他们都是应用层协议,基于tcp或udp设计。

通常应用层协议都是基于tcp和udp,可靠传输通常使用tcp,如大多数的基础组件,如redis、mysql。只有能容忍丢失且需要很高的性能时使用udp协议,比如metric上报等场景。

这里介绍几种基于tcp的应用协议。

redis协议

redis协议足够简单,所以先介绍一下。redis协议基于tcp设计,客户端和服务器发送的命令一律使用\r\n(CRLF)结尾。他的格式如下

*<参数数量> CRLF
$<参数1 字节数量> CRLF
<参数1的数据> CRLF
...
$<参数n 字节数量> CRLF
<参数n的数据> CRLF

举个例子,client向server端发送命令 set mykey myvalue

*3 CRLF
$3 CRLF
SET CRLF
$5 CRLF
mykey CRLF
$7 CRLF
myvalue CRLF

也就是 *3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n

关于redis协议更详细信息可以看这个链接:

http://redisdoc.com/topic/protocol.html

http协议

http协议是我们最常见的协议,它的请求报文格式是由三部分组成:

  • 请求行:包括method、url、version,由空格分隔,\r\n结尾
  • 请求头:多行,每行是key:value的格式,以\r\n结尾
  • 请求体:请求头与请求体直接由一个空白行分隔,请求体的长度在请求头中由content-length给出

redis和http协议的处理方式截然不同。他们都是基于tcp,而tcp协议传输的数据是流式的,通俗地说就是它就像水流,不断地发送字节,tcp保证不重复,不丢包。而接收端要拿到想要的数据必须得从流式的数据中“判断出数据包的边界”,这就是tcp的粘包问题,解决它通常有三种方法:

  1. 发送固定长度的消息
  2. 使用特殊标记区分消息间隔
  3. 将消息的尺寸和消息一起发送

redis协议使用了第2种,http和接下来要介绍的dubbo协议使用了第3种,固定长度的消息比较理想,在实际中很少遇到。

dubbo协议

由于dubbo支持的协议很多,本文提到的dubbo协议特指dubbo框架的默认协议,也就是dubbo的私有协议。它的格式如下:

  • 0-15: 魔数,判断是否是dubbo协议
  • 16: 判断是请求还是返回
  • 17: 判断是否期望返回
  • 18: 判断是否为事件消息,如心跳事件
  • 19-23: 序列化标志
  • 24-31: 标志响应状态(类似http status)
  • 32-63: 请求id
  • 64-95: 内容长度(字节)
  • 96-?: 序列化后的内容(换行符分隔)

常用的attachments在dubbo协议的哪里?

dubbo的attachments,我们通常将他类比为http协议的header,可以携带一些隐式的参数信息(不用编码到请求对象中),如压测标志等。从他的类型

private Map<String, String> attachments;

基本可以推断出attachments存在于dubbo协议的96字节之后的内容中,因为前面头的根本放不下这个map。

从dubbo的实现中可以看出,dubbo的一个请求被封装为一个DecodeableRpcInvocation对象,里面包含了methodNameparameterTypesargumentsattachments等,将该对象序列化后填入dubbo协议的96字节后的内容中发送出去。

使用时,consumer端:

RpcContext.getContext().setAttachment("hello", "from_consumer");

provider端:

RpcContext.getContext().getAttachment("hello");

这里能看出dubbo协议相比较http协议来说设计的还是有所欠缺的,想要拿到一些隐式参数,或者想要知道请求发往哪里,必须得把请求体解析出来才可以,这也是dubbo协议往mesh方向发展的一个绊脚石。

dubbo协议支持在返回值中带回attachments吗?

consumer端向provider端发送请求可以在头部携带隐式参数,那么返回时也可以从provider端带回到consumer端吗?

比如provider回传给consumer它自身的处理耗时,consumer计算出请求的响应时间,两者相减即可得到网络耗时,此时provider端最好是将耗时放在attachments中隐式地传回。

dubbo的协议是请求和回复都是相同格式,理论上consumer可以带隐式参数到provider端,则provider端肯定也可以回传。

从dubbo的返回对象DecodeableRpcResult中可以看到是存在attachments的,但从实际的测试来看,2.7.x版本是不支持的,但2.6.x(>=2.6.3)版本是支持的。

provider端设置:

RpcContext.getServerContext().setAttachment("hello", "from_provider");

consumer端获取:

RpcContext.getServerContext().getAttachment("hello")

github上相关的issue链接如下:

https://github.com/apache/dubbo/pull/1843

协议和序列化有什么区别?

我们可能会经常听到这样的说法,dubbo除了dubbo协议外还支持rest、thrift、grpc等协议,也支持hessian、json序列化。协议与序列化是什么关系?

通过刚刚介绍的dubbo协议格式或许就能明白,dubbo协议是如上的格式包含了头和内容,其中96字节之后的内容是序列化后的内容,默认使用hessian2序列化,也可以修改为fastjson、gson、jdk等。只需要配置即可修改协议

<dubbo:protocol name="dubbo" serialization="fastjson"/>

如果非要做个类比的话,就是你不仅可以通过http协议传输json格式的数据,也可以传输xml格式的数据。http就是协议,json和xml就是序列化。

最后

dubbo协议的设计虽然有所欠缺,但依然不能阻止它成为dubbo使用最广泛的协议。


搜索关注微信公众号"捉虫大师",后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践。

聊聊dubbo协议的更多相关文章

  1. Dubbo(五):Dubbo中的URL统一资源模型与Dubbo协议

    一.URL简介 URL也就是Uniform Resource Locator,中文叫统一资源定位符.Dubbo中无论是服务消费方,或者服务提供方,或者注册中心.都是通过URL进行定位资源的.所以今天来 ...

  2. dubbo源码分析4-基于netty的dubbo协议的server

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  3. Dubbo协议与连接控制

    协议参考手册 (+) (#) 推荐使用Dubbo协议 性能测试报告各协议的性能情况,请参见:性能测试报告 (+) dubbo:// (+) (#) Dubbo缺省协议采用单一长连接和NIO异步通讯,适 ...

  4. Dubbo协议

    参考dubbo官方文档http://dubbo.apache.org/zh-cn/docs/user/references/protocol/dubbo.html dubbo共支持如下几种通信协议: ...

  5. dubbo协议下的单一长连接与多线程并发如何协同工作

    上班的路上突然就冒出了这么个问题:既然在dubbo中描述消费者和提供者之间采用的是单一长连接,那么如果消费者端是高并发多线程模型的web应用,单一长连接如何解决多线程并发请求问题呢? 其实如果不太了解 ...

  6. dubbo hessian+dubbo协议

    Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况 Hessian协议用于集成Hessian的服务,Hessian底层采 ...

  7. 聊聊Http协议

    http协议是大家在互联网中最为熟悉的协议,只要上网大家都会遇到,但是,很多人被问道什么是http协议,http协议的内容是什么就懵了.这里,我们随便聊聊http协议. 首先,我们说说协议.我一直觉得 ...

  8. dubbo协议参考手册(转)

    原文链接:http://wely.iteye.com/blog/2331332 协议参考手册 (+) (#) 推荐使用Dubbo协议 性能测试报告各协议的性能情况,请参见:性能测试报告 (+) dub ...

  9. Dubbo源码分析:Dubbo协议解码

    Dubbo协议解码时序图

  10. 聊聊Dubbo - Dubbo可扩展机制实战

    1. Dubbo的扩展机制 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架.今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性. 如同罗马不是一天建成的,任何系统都一定是从 ...

随机推荐

  1. 掌握 Linux PC 性能之基准测试

    导读 基准测试是一项测试或一系列测试,用来确定某个计算机硬件运行起来的状况有多好:在许多情况下,“基准测试”实际上等同于“压力测试”,通过测试硬件的极限,然后可以将测得的结果与其他硬件测得的结果作一番 ...

  2. 53. Maximum Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  3. 张艾迪(创始人):世界级天才女孩Eidyzhang

    让整个世界与我们一同解读世界第一天才:Eidyzhang 她改变了整个世界.她的故事也激励了整个世界的不论亚洲.欧洲.非洲.南美州.北美洲.南极洲 天才Eidyzhang的故事激励了整个世界不论黑人. ...

  4. MySQL5.7重置root密码

    版本更新 缘故,好多网上的教程都不适用了,甚至连官网的文档也不是能够顺利操作的. 如果 MySQL 正在运行,首先杀之: killall -TERM mysqld. 运行mysqld_safe --s ...

  5. php 面向对象二

    多态: 多态就是多种形态:多态分为方法重写和方法重载,但是php不支持方法重载 重写: 子类和父类的方法名必须一致,严格标准要求参数必须一致,但是参数可以不一致 子类中覆盖的方法不能比父类的方法访问权 ...

  6. JS中的按位非(~)的使用技巧

    按位非 按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码 现在让我来看几个例子 例子1 console.log(4); console.log(~4); console.log( ...

  7. 【BubbleCup X】F:Product transformation

    按照题解的规律,首先能看出前面每个数幂次的性质. 然后发掘约数的性质 #include<bits/stdc++.h> ; typedef long long ll; using names ...

  8. 如何禁用 a 标签的点击事件

    a标签是没有disable属性的 ,如果想用disable 禁用a标签的点击事件,也可以实现: 1.a标签要用disable属性,必须和pointer-events属性一起使用, html代码: &l ...

  9. EffectiveJava(1) 构造器和静态工厂方法

    构造器和静态工厂方法 **构造器是大家创建类时的构造方法,即使不显式声明,它也会在类内部隐式声明,使我们可以通过类名New一个实例. 静态方法是构造器的另一种表现形式** 主题要点:何时以及如何创建对 ...

  10. 修改SQL Server 2005的默认端口

    修改SQL Server 2005的默认端口 1.打开SQL Server的配置管理程序 Microsoft SQL Server 2005->配置工具->SQL Server Confi ...