协议是两个网络实体进行通信的基础,数据在网络上从一个实体传输到另一个实体,以字节流的形式传递到对端。在这个字节流的世界里,如果没有协议,就无法将这个一维的字节流重塑成为二维或者多维的数据结构以及领域对象。
协议是双方确定的交流语义,比如:我们设计一个字符串传输的协议,它允许客户端发送一个字符串,服务端接收到对应的字符串。这个协议很简单,首先发送一个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.
可以看到通信协议需要定义语法、语义以及通信上的同步操作,这里描述的内容实际就是对前面自定义字符串传输协议的形式化描述。
1、dubbo 缺省协议 采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况
2、不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
缺省协议,使用基于mina1.1.7+hessian3.2.1的tbremoting交互。
特性
3、Dubbo协议缺省每服务每提供者每消费者使用单一长连接,如果数据量较大,可以使用多个连接。
4、为防止被大量连接撑挂,可在服务提供方限制最大接收连接数,以实现服务提供方自我保护
1、RMI协议采用JDK标准的java.rmi.*
实现,采用阻塞式短连接
和JDK标准序列化
方式 。
注:
如果正在使用RMI提供服务给外部访问(公司内网环境应该不会有攻击风险),同时应用里依赖了老的common-collections包(dubbo不会依赖这个包,请排查自己的应用有没有使用)的情况下,存在反序列化安全风险。
请检查应用:
将commons-collections3 请升级到3.2.2版本:
https://commons.apache.org/proper/commons-collections/release_3_2_2.html
将commons-collections4 请升级到4.1版本:
https://commons.apache.org/proper/commons-collections/release_4_1.html
新版本的commons-collections解决了该问题 。
特性
接口
如果服务接口继承了java.rmi.Remote
接口,可以和原生RMI互操作,即:
提供者用Dubbo的RMI协议暴露服务,消费者直接用标准RMI接口调用,或者提供方用标准RMI暴露服务,消费方用Dubbo的RMI协议调用。
如果服务接口没有继承java.rmi.Remote
接口,缺省Dubbo将自动生成一个com.xxx.XxxService$Remote
的接口,并继承java.rmi.Remote
接口,并以此接口暴露服务,
但如果设置了
,将不生成$Remote
接口,而使用Spring的RmiInvocationHandler接口暴露服务,和Spring兼容。
Hessian 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。
Dubbo 的 Hessian 协议可以和原生 Hessian 服务互操作,即:
Hessian 是 Caucho 开源的一个 RPC 框架,其通讯效率高于 WebService 和 Java 自带的序列化。
特性
约束
1、参数及返回值需实现Serializable接口
2、参数及返回值不能自定义实现List, Map, Number, Date, Calendar等接口,只能用JDK自带的实现,因为hessian会做特殊处理,自定义实现类中的属性值都会丢失。
基于http表单的远程调用协议。
特性
基于 WebService 的远程调用协议,基于 Apache CXF的 frontend-simple 和 transports-http 实现。
可以和原生 WebService 服务互操作,即:
特性
1、基于CXF的 frontend-simple 和 transports-http 实现。
2、CXF是Apache开源的一个RPC框架:http://cxf.apache.org,由Xfire和Celtix合并而来 。
可以和原生WebService服务互操作,即:
提供者用Dubbo的WebService协议暴露服务,消费者直接用标准WebService接口调用,或者提供方用标准WebService暴露服务,消费方用Dubbo的WebService协议调用。
约束
参数及返回值需实现Serializable接口
参数尽量使用基本类型和POJO。
当前 dubbo 支持的 thrift 协议是对 thrift 原生协议 [2] 的扩展,在原生协议的基础上添加了一些额外的头信息,比如 service name,magic number 等。
使用 dubbo thrift 协议同样需要使用 thrift 的 idl compiler 编译生成相应的 java 代码,后续版本中会在这方面做一些增强。
常见问题
Thrift不支持null值,不能在协议中传null
基于 memcached实现的 RPC 协议。
基于 Redis实现的 RPC 协议。
基于标准的Java REST API——JAX-RS 2.0(Java API for RESTful Web Services的简写)实现的REST调用支持。
Dubbo 自 2.7.5 版本开始支持 gRPC 协议,对于计划使用 HTTP/2 通信,或者想利用 gRPC 带来的 Stream、反压、Reactive 编程等能力的开发者来说, 都可以考虑启用 gRPC 协议。
大概需要以下步骤: