首页 > 其他分享 >Dubbo 协议详解

Dubbo 协议详解

时间:2024-07-01 12:30:30浏览次数:3  
标签:Dubbo 字节 协议 标识 详解 byte 序列化

Solomon_肖哥弹架构 跟大家“弹弹” 分布式微服务Dubbo 协议详解
欢迎 点赞,收藏,关注。

关注本人的公众号Solomon肖哥弹架构获取更多的惊喜

协议的概念

协议是两个网络实体进行通信的基础,数据在网络上从一个实体传输到另一个实体,以字节流的形式传递到对端。在这个字节流的世界里,如果没有协议,就无法将这个一维的字节流重塑成为二维或者多维的数据结构以及领域对象。

协议是什么

协议是双方确定的交流语义,比如:我们设计一个字符串传输的协议,它允许客户端发送一个字符串,服务端接收到对应的字符串。这个协议很简单,首先发送一个4字节的消息总长度,然后再发送1字节的字符集charset长度,接下来就是消息的payload,字符集名称和字符串正文。

发送一个iso-8859-1的字符串abc到对端。经过协议编码,内容是:18 = 4 + 1 + 10 + 3|10|iso-8859-1|abc,当这些字节流发往服务端后,当服务端收到字节流后,首先读取4个字节,将其转换为int,在这个例子中是18,接下来继续读14个字节,将首个字节得到字符集名称长度10,将后续内容的前10字节转换为字符串,内容是iso-8859-1,使用该字符集将后续的字节数组造型成为字符串new String(bytes, “iso-8859-1”)。

在前面自定义字符串传输协议的例子中,我们已经看到协议在双方传输数据中起到的作用,没有协议就无法完成数据交换,下面是维基百科对于通信协议的定义。

In telecommunication, a communication protocol is a system of rules that allow two or more entities of a communications system to transmit information via any kind of variation of a physical quantity. The protocol defines the rules syntax, semantics and synchronization of communication and possible error recovery methods. Protocols may be implemented by hardware, software, or a combination of both.

可以看到通信协议需要定义语法、语义以及通信上的同步操作,这里描述的内容实际就是对前面自定义字符串传输协议的形式化描述。

Codec的定义

org.apache.dubbo.remoting.Codec2定义为I/O的 Codec 过程,因此主要的方法就是encode和decode,具体定义如下所示:

@SPI
public interface Codec2 {

    @Adaptive({Constants.CODEC_KEY})
    void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException;

    @Adaptive({Constants.CODEC_KEY})
    Object decode(Channel channel, ChannelBuffer buffer) throws IOException;


    enum DecodeResult {
        NEED_MORE_INPUT, SKIP_SOME_INPUT
    }

}

Codec工作在一种协议上,encode是将通信对象编码到ByteBufferWrapper中,decode是将从网络上读取的ChannelBuffer解码为Object,也就是通信对象。

常见的协议模式

应用层协议一般的形式有三种:定长协议、特殊结束符和协议头+payload模式,下面介绍一下这些形式的具体内容。

从网络上以流的形式进行数据的读取,需要确定的是一次有意义的传输内容在读到何时结束,因为一个一个byte传输过来,需要有一个结束。而且数据在网络上的传输,存在粘包和半包的情况,能够应对这个问题的办法就是协议能够准确的识别,当粘包发生时不会多读,当半包发生时会继续读取

定长协议

定长的协议是指协议内容的长度是固定的,比如协议byte长度是50,当从网络上读取50个byte后,就进行decode解码操作。定长协议在读取或者写入时,效率比较高,因为数据缓存的大小基本都确定了,就好比数组一样,缺陷就是适应性不足,以RPC场景为例,很难估计出定长的长度是多少。

可以参考Netty的FixedLengthFrameDecoder

特殊结束符

相比定长协议,如果能够定义一个特殊字符作为每个协议单元结束的标示,就能够以变长的方式进行通信,从而在数据传输和高效之间取得平衡,比如用特殊字符\n。

特殊结束符方式的问题是过于简单的思考了协议传输的过程,对于一个协议单元必须要全部读入才能够进行处理,除此之外必须要防止用户传输的数据不能同结束符相同,否则就会出现紊乱。

可以参考Netty的DelimiterBasedFrameDecoder

变长协议(协议头+payload)

一般是自定义协议,会以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度。

+———+
|定长|
+———+
|内容|
+———+

可以参考Netty的LengthFieldBasedFrameDecoder

Dubbo 协议实际上就是一种变长协议,后面的章节会详细介绍。

Dubbo 协议

协议概览

Dubbo 框架定义了私有的RPC协议,其中请求和响应协议的具体内容我们使用表格来展示。

协议详情

  • Magic - Magic High & Magic Low (16 bits)
    • 标识协议版本号,Dubbo 协议:0xdabb
  • Req/Res (1 bit)
    • 标识是请求或响应。请求: 1; 响应: 0。
  • 2 Way (1 bit)
    • 仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。
  • Event (1 bit)
    • 标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。
  • Serialization ID (5 bit)
    • 标识序列化类型:比如 fastjson 的值为6。
  • Status (8 bits)
    • 仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。
      • 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_ERROR
  • Request ID (64 bits)
    • 标识唯一请求。类型为long。
  • Data Length (32 bits)
    • 序列化后的内容长度(可变部分),按字节计数。int类型。
  • Variable Part
    • 被特定的序列化类型(由序列化 ID 标识)序列化后,每个部分都是一个 byte [] 或者byte
      • 如果是请求包 ( Req/Res = 1),则每个部分依次为:
        • Dubbo version
        • Service name
        • Service version
        • Method name
        • Method parameter types
        • Method arguments
        • Attachments
      • 如果是响应包(Req/Res = 0),则每个部分依次为:
        • 返回值类型(byte),标识从服务器端返回的值类型:
          • 返回空值:RESPONSE_NULL_VALUE 2
          • 正常响应值: RESPONSE_VALUE 1
          • 异常:RESPONSE_WITH_EXCEPTION 0
        • 返回值:从服务端返回的响应bytes

注意: 对于(Variable Part)变长部分,当前版本的Dubbo 框架使用json序列化时,在每部分内容间额外增加了换行符作为分隔,请在Variable Part的每个part后额外增加换行符, 如:

Dubbo version bytes (换行符)
Service name bytes  (换行符)
...

Dubbo 协议的优缺点

优点

  • 协议设计上很紧凑,能用 1 个 bit 表示的,不会用一个 byte 来表示,比如 boolean 类型的标识。
  • 请求、响应的 header 一致,通过序列化器对 content 组装特定的内容,代码实现起来简单

可以改进的点

  • 类似于 http 请求,通过 header 就可以确定要访问的资源,而 Dubbo 需要涉及到用特定序列化协议才可以将服务名、方法、方法签名解析出来,并且这些资源定位符是 string 类型或者 string 数组,很容易转成 bytes,因此可以组装到 header 中。类似于 http2 的 header 压缩,对于 rpc 调用的资源也可以协商出来一个int来标识,从而提升性能,如果在header上组装资源定位符的话,该功能则更易实现。

  • 通过 req/res 是否是请求后,可以精细定制协议,去掉一些不需要的标识和添加一些特定的标识。比如status,twoWay标识可以严格定制,去掉冗余标识。还有超时时间是作为 Dubbo 的 attachment 进行传输的,理论上应该放到请求协议的header中,因为超时是网络请求中必不可少的。提到 attachment ,通过实现可以看到 attachment 中有一些是跟协议 content中已有的字段是重复的,比如 path和version等字段,这些会增大协议尺寸。

  • Dubbo 会将服务名com.alibaba.middleware.hsf.guide.api.param.ModifyOrderPriceParam,转换为Lcom/alibaba/middleware/hsf/guide/api/param/ModifyOrderPriceParam;,理论上是不必要的,最后追加一个;即可。

  • Dubbo 协议没有预留扩展字段,没法新增标识,扩展性不太好,比如新增响应上下文的功能,只有改协议版本号的方式,但是这样要求客户端和服务端的版本都进行升级,对于分布式场景很不友好

你的点赞与关注 是 Solomon_肖哥弹架构持续的动力。

历史热点文章

相关文章

  • Dubbo 如何自定义协议为业务通信带来扩展
    Solomon_肖哥弹架构跟大家“弹弹”Dubbo自定义协议扩展欢迎点赞,收藏,关注。关注本人的公众号Solomon肖哥弹架构获取更多精彩内容Dubbo自定义协议扩展1、扩展说明RPC协议扩展,封装远程调用细节。契约:当用户调用refer()所返回的Invoker对象的invoke()方法......
  • c指针详解(2)--- 指针与数组
    在大致了解了c语言中变量在内存中的分配、存活等方面后,我们再来看看数组在内存中又是如何呈现的。这里我们就只讨论静态数组,动态数组涉及到动态内存分配,这里就不详细展开了。那么什么是静态数组呢?要理解这个数据结构,我们可以将其切分为两个概念:静态与数组。数组:数组其实就是一......
  • 动态路由RIP协议
    一、拓扑二、 配置路由器端口IP地址R1R2  三.配置步骤1.Router(config)#routerrip       !启用RIP动态路由协议2.Router(config-router)#version{1|2}       !指定RIP协议的版本,不写默认版本1(一般都默认)3.Router(config-router......
  • Stable Diffusion之最全详解图解
    稳定扩散(StableDiffusion)是指在图论和网络科学领域中,一种基于随机漫步的扩散模型。该模型可以用来描述节点在网络上的扩散过程,例如信息传播、疾病传播等。稳定扩散模型的基本思想是,节点在网络上随机选择邻居节点进行转移,转移概率与节点之间的连接强度相关。具体来说,稳定扩散......
  • 54、Flink 测试工具测试 Flink 作业详解
    测试Flink作业a)JUnit规则MiniClusterWithClientResourceApacheFlink提供了一个名为MiniClusterWithClientResource的Junit规则,用于针对本地嵌入式小型集群测试完整的作业。叫做MiniClusterWithClientResource.要使用MiniClusterWithClientResource,需要添加......
  • 53、Flink 测试工具测试用户自定义函数详解
    1.测试用户自定义函数a)单元测试无状态、无时间限制的UDF示例:无状态的MapFunction。publicclassIncrementMapFunctionimplementsMapFunction<Long,Long>{@OverridepublicLongmap(Longrecord)throwsException{returnrecord+1;}......
  • SSE使用详解
    一、SSE简介SSE是一种在网页开发中使用的、基于HTTP长连接技术,允许服务器向客户端浏览器实时推送更新。客户端通过创建一个EventSource对象并指向服务器上的一个URL来发起请求,这个请求保持打开状态,服务器可以在这个单一的TCP连接上不断发送新的数据块。这些数据块被称为“......
  • Mysql表的增删改查详解
    3.表的增删改查创建一个学生表DROPTABLEIFEXISTSstudent;CREATETABLEstudent(idINT,snINTcomment'学号',nameVARCHAR(20)comment'姓名',qq_mailVARCHAR(20)comment'QQ邮箱');单行数据+全列插入插入两条记录,value_list数量必须......
  • CUDA编程的注意事项和使用流程详解
    目录一、背景二、CUDA编程的基本概念 2.1、CUDA线程(Thread):2.2、线程块(Block):2.3、网格(Grid):2.4、内存模型:三、CUDA编程流程3.1.环境配置3.2.编写CUDA代码 3.2.1、初始化和分配内存3.2.2、数据传输3.2.3、内核函数(Kernel)调用3.2.4、结果传回主机3.2.5、释放资源......
  • sqlmap注入详解
    免责声明:本文仅做分享...目录1.介绍2.特点3.下载4.帮助文档5.常见命令指定目标请求HTTPcookie头HTTPUser-Agent头HTTP协议的证书认证HTTP(S)代理HTTP请求延迟设定超时时间设定重试超时设定随机改变的参数值利用正则过滤目标网址避免过多的错误请求被屏......