Dubbo系列5:Dubbo协议

1. 回顾Dubbo调用过程

我们先回顾一次调用过程经历了哪些处理步骤。
如果我们动手写简单的RPC调用, 则需要把服务调用信息传递到服务端, 每次服务调用的一些公用的信息包括服务调用接口、 方法名、 方法参数类型和方法参数值等, 在传递方法参数值时需要先序列化对象并经过网络传输到服务端, 在服务端需要按照客户端序列化顺序再做一次反序列化来读取信息, 然后拼装成请求对象进行服务反射调用, 最终将调用结果再传给客户端。在Dubbo中实现调用也是基于相同的原理, 下面看一下Dubbo在一次完整的RPC调用流程中经过的步骤:

首先在客户端启动时会从注册中心拉取和订阅对应的服务列表, Cluster会把拉取的服务列表聚合成一个Invoker,每次RPC调用前会通过Directory#list获取providers地址(已经生成好的Invoker列表) , 获取这些服务列表给后续路由和负载均衡使用。对应图①,在①中主要是将多个服务提供者做聚合。 在框架内部另外一个实现Directory接口是RegistryDirectory类, 它和接口名是一对一的关系(每一个接口都有一个RegistryDirectory实例) , 主要负责拉取和订阅服务提供者、 动态配置和路由项。
在Dubbo发起服务调用时, 所有路由和负载均衡都是在客户端实现的。 客户端服务调用首先会触发路由操作, 然后将路由结果得到的服务列表作为负载均衡参数, 经过负载均衡后会选出一台机器进行RPC调用, 这3个步骤依次对应于②、 ③和④。 客户端经过路由和负载均衡后,会将请求交给底层I/O线程池(比如Netty)处理, I/O线程池主要处理读写、 序列化和反序列化等逻辑, 因此这里一定不能阻塞操作, Dubbo也提供参数控制(decode.in.io)参数, 在处理反序列化对象时会在业务线程池中处理。 在⑤中包含两种类似的线程池, 一种是I/O线程池(Netty),另一种是Dubbo业务线程池(承载业务方法调用) 。
Dubbo支持Telnet直接管理某些信息,目前Dubbo将服务调用和Telnet调用做了端口复用, 在编解码层面也做了适配。 在Telnet调用时, 会新建立一个TCP连接, 传递接口、 方法和JSON格式的参数进行服务调用, 在编解码层面简单读取流中的字符串(因为不是Dubbo标准头报文) , 最终交给Telnet对应的Handler去解析方法调用。 如果是非Telnet调用, 则服务提供方会根据传递过来的接口、 分组和版本信息查找Invoker对应的实例进行反射调用。 在⑦中进行了端口复用, 如果是Telnet调用, 则先找到对应的Invoker进行方法调用。 Telnet和正常RPC调用不一样的地方是序列化和反序列化使用的不是Hessian方式, 而是直接使用fastjson进行处理。
我们接下来集中精力探讨更细节的一些知识点, 比如Dubbo协议、编解码实现和线程模型等, 本章篇幅主要放在⑤、 ⑥和⑦中, 我们首先看一下目前Dubbo的协议细节。

2. Dubbo协议

Dubbo协议设计, 其协议设计参考了现有TCP/IP协议, 在阅读图时, 我们发现一次RPC调用包括协议头和协议体两部分。 16字节长的报文头部主要携带了魔法数(Oxdabb),以及当前请求报文是否是Request、 Response>心跳和事件的信息, 请求时也会携带当前报文体内序列化协议编号。 除此之外, 报文头部还携带了请求状态, 以及请求唯一标识和报文体长度。
在这里插入图片描述
理解协议本身的内容对后面的编码器和解码器的实现非常重要, 我们先逐字节、 逐比特位讲解协议内容。
Dubbo协议字段:
在这里插入图片描述
在消息体中, 客户端严格按照序列化顺序写入消息, 服务端也会遵循相同的顺序读取消息,客户端发起请求的消息体依次保存下列7个内容: Dubb。 版本号、 服务接口名、 服务接口版本、 方法名、 参数类型、 方法参数值和请求额外参数(attachment)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵横千里,捭阖四方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值