1)dubbo 支持哪些通信协议?
2)支持哪些序列化协议?
3)说一下 Hessian 的数据结构?
4)PB 知道吗?
5)为什么 PB 的效率是最高的?
dubbo 分成哪些层,怎么发起 rpc 请求,注册、发现、调用,这些是基本的。
序列化,就是把数据结构或者是一些对象,转换为二进制串的过程,而反序列化是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
1.dubbo 支持不同的通信协议
Dubbo 的设计目的是为了满足高并发小数据量的 rpc 调用,在大数据量下的性能表现并不好,建议使用 rmi 或 http 协议。
dubbo 协议 dubbo://
默认就是走 dubbo 协议,单一长连接,进行的是 NIO 异步通信,基于 hessian 作为序列化协议。使用的场景是:传输数据量小(每次请求在 100kb 以内),但是并发量很高,以及服务消费者机器数远大于服务提供者机器数的情况。
为了要支持高并发场景,一般是服务提供者就几台机器,但是服务消费者有上百台,可能每天调用量达到上亿次!此时用长连接是最合适的,就是跟每个服务消费者维持一个长连接就可以,可能总共就 100 个连接。然后后面直接基于长连接 NIO 异步通信,可以支撑高并发请求。
长连接,通俗点说,就是建立连接过后可以持续发送请求,无须再建立连接。
而短连接,每次要发送请求之前,需要先重新建立一次连接。
rmi 协议 rmi://
RMI 协议采用 JDK 标准的 java.rmi.* 实现,采用阻塞式短连接和 JDK 标准序列化方式。多个短连接,适合消费者和提供者数量差不多的情况,适用于文件的传输,一般较少用。
hessian 协议 hessian://
Hessian 1 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。走 hessian 序列化协议,多个短连接,适用于提供者数量比消费者数量还多的情况,适用于文件的传输,一般较少用。
http 协议 http://
基于 HTTP 表单的远程调用协议,采用 Spring 的 HttpInvoker 实现。走表单序列化。
thrift 协议 thrift://
当前 dubbo 支持的 thrift 协议是对 thrift 原生协议的扩展,在原生协议的基础上添加了一些额外的头信息,比如 service name,magic number 等。
webservice 协议 webservice://
基于 WebService 的远程调用协议,基于 Apache CXF 的 frontend-simple 和 transports-http 实现。走 SOAP 文本序列化。
memcached 协议 memcached://
redis 协议 redis://
rest 协议 rest://
基于标准的 Java REST API——JAX-RS 2.0(Java API for RESTful Web Services 的简写)实现的 REST 调用支持。
gPRC 协议 grpc://
Dubbo 自 2.7.5 版本开始支持 gRPC 协议,对于计划使用 HTTP/2 通信,或者想利用 gRPC 带来的 Stream、反压、Reactive 编程等能力的开发者来说, 都可以考虑启用 gRPC 协议。
2.dubbo 支持的序列化协议
dubbo 支持 hession、Java 二进制序列化、json(fastjson)、SOAP 文本序列化多种序列化协议。但是 hessian 是其默认的序列化协议。
说一下 Hessian 的数据结构
Hessian 的对象序列化机制有 8 种原始类型:
- 原始二进制数据
- boolean
- 64-bit date(64 位毫秒值的日期)
- 64-bit double
- 32-bit int
- 64-bit long
- null
- UTF-8 编码的 string
另外还包括 3 种递归类型:
- list for lists and arrays
- map for maps and dictionaries
- object for objects
还有一种特殊的类型:
- ref:用来表示对共享对象的引用。
为什么 PB 的效率是最高的?
Protobuf 是网络传输中经常会用到的协议,优点是版本间兼容性强,对数据序列化时的极致压缩使得 Protobuf 包体积比 xml、json 等格式要小很多,节约流量。 Ref: https://cloud.tencent.com/developer/article/1520442
其实 PB 之所以性能如此好,主要得益于两个:
- 使用 proto 编译器,自动进行序列化和反序列化,速度非常快,比 XML 和 JSON 快数倍;
- 数据压缩效果好,即序列化后的数据量体积小,传输起来带宽和速度上会有优化。
3.请求编码
主要看类:ExchangeCodec.encodeRequest ()
- 获取序列化的方式,没有默认为 hessian 方式
- 构建存储 header 的字节数组,大小是 16bytes(128bits)
- 设置 2 字节为魔数:0xdabb(魔数的作用和文件的后缀是类似的,但是真正表示一个文件的类型不是文件的后缀,而是魔数)
- 16-31 这两字节:16-20 表示采用何种方式序列化;21 表示请求 / 心跳;22 表示是 twoway 还是 oneway(这 2 种我也不知道啥意思);23 表示请求消息 / 响应消息;当消息是响应消息时,24-31 表示返回的状态。
- request id,8 字节,表示消息的 id,这个对于某个 consumer 是递增的。
- 写出 body,这个 body 才是 rpc message,包含请求方法名,参数等信息,长度不能超出 2^32 (4 字节表示的)
- 设置数据长度,4 字节,即 body 的长度
TCP 和 IP 的解析,操作系统已经做了,对于上层应用,只需要关系 dubbo 的解析。
从上面的分析可以看出,dubbo 发送的数据是 16 字节头+body(4 字节来描述这个长度)