Dubbo是 Alibaba 开源的分布式服务框架远程调用框架,在网络间传输数据,就须要通讯协议和序列化。java
一 通讯协议web
Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,可是Dubbo官网是推荐咱们使用Dubbo协议的,默认也是用的dubbo协议。redis
先介绍几种常见的协议:spring
1. dubbo协议
缺省协议,使用基于mina1.1.7+hessian3.2.1的tbremoting交互。
链接个数:单链接
链接方式:长链接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者没法压满提供者,尽可能不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用json
一、dubbo默认采用dubbo协议,dubbo协议采用单一长链接和NIO异步通信,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的状况
二、他不适合传送大数据量的服务,好比传文件,传视频等,除非请求量很低。
配置以下:浏览器
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name=“dubbo” port=“9090” server=“netty” client=“netty” codec=“dubbo”
serialization=“hessian2” charset=“UTF-8” threadpool=“fixed” threads=“100” queues=“0” iothreads=“9”
buffer=“8192” accepts=“1000” payload=“8388608” />
三、Dubbo协议缺省每服务每提供者每消费者使用单一长链接,若是数据量较大,可使用多个链接。springboot
<dubbo:protocol name="dubbo" connections="2" />
四、为防止被大量链接撑挂,可在服务提供方限制大接收链接数,以实现服务提供方自我保护服务器
<dubbo:protocol name="dubbo" accepts="1000" />
网络
2. rmi协议
Java标准的远程调用协议。
链接个数:多链接
链接方式:短链接
传输协议:TCP
传输方式:同步传输
序列化:Java标准二进制序列化
适用范围:传入传出参数数据包大小混合,消费者与提供者个数差很少,可传文件。
适用场景:常规远程服务方法调用,与原生RMI服务互操做并发
RMI协议采用JDK标准的java.rmi.*实现,采用阻塞式短链接和JDK标准序列化方式 。
3. hessian协议
基于Hessian的远程调用协议。
链接个数:多链接
链接方式:短链接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
一、Hessian协议用于集成Hessian的服务,Hessian底层采用Http通信,采用Servlet暴露服务,Dubbo缺省内嵌Jetty做为服务器实现。
二、Hessian是Caucho开源的一个RPC框架:http://hessian.caucho.com,其通信效率高于WebService和Java自带的序列化。
4. http协议
基于http表单的远程调用协议。参见:[HTTP协议使用说明]
链接个数:多链接
链接方式:短链接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
5. webservice协议
基于WebService的远程调用协议。
链接个数:多链接
链接方式:短链接
传输协议:HTTP
传输方式:同步传输
序列化:SOAP文本序列化
适用场景:系统集成,跨语言调用
二 序列化
序列化是将一个对象变成一个二进制流就是序列化, 反序列化是将二进制流转换成对象。
为何要序列化?
1. 减少内存空间和网络传输的带宽
2. 分布式的可扩展性
3. 通用性,接口可共用。
Dubbo序列化支持java、compactedjava、nativejava、fastjson、dubbo、fst、hessian二、kryo,其中默认hessian2。其中java、compactedjava、nativejava属于原生java的序列化。
dubbo序列化:阿里还没有开发成熟的高效java序列化实现,阿里不建议在生产环境使用它。
hessian2序列化:hessian是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2序列化,而是阿里修改过的,它是dubbo RPC默认启用的序列化方式。
json序列化:目前有两种实现,一种是采用的阿里的fastjson库,另外一种是采用dubbo中本身实现的简单json库,但其实现都不是特别成熟,并且json这种文本序列化性能通常不如上面两种二进制序列化。
java序列化:主要是采用JDK自带的Java序列化实现,性能很不理想。
dubbo序列化主要由Serialization(序列化策略)、DataInput(反序列化,二进制->对象)、DataOutput(序列化,对象->二进制流) 来进行数据的序列化与反序列化。其关系类图为:
看一下Serialization的接口:
1 /** 2 * Serialization. (SPI, Singleton, ThreadSafe) 3 */ 4 @SPI("hessian2") 5 public interface Serialization { 6 7 /** 8 * get content type id 9 * 10 * @return content type id 11 */ 12 byte getContentTypeId(); 13 14 /** 15 * get content type 16 * 17 * @return content type 18 */ 19 String getContentType(); 20 21 /** 22 * create serializer 23 * 24 * @param url 25 * @param output 26 * @return serializer 27 * @throws IOException 28 */ 29 @Adaptive 30 ObjectOutput serialize(URL url, OutputStream output) throws IOException; 31 32 /** 33 * create deserializer 34 * 35 * @param url 36 * @param input 37 * @return deserializer 38 * @throws IOException 39 */ 40 @Adaptive 41 ObjectInput deserialize(URL url, InputStream input) throws IOException; 42 43 }
从上面类图能够看出各个Serialization实现类调用了各自的output和input,咱们看一下默认的hessian2的实现。
1 public class Hessian2Serialization implements Serialization { 2 3 public static final byte ID = 2; 4 5 public byte getContentTypeId() { 6 return ID; 7 } 8 9 public String getContentType() { 10 return "x-application/hessian2"; 11 } 12 13 public ObjectOutput serialize(URL url, OutputStream out) throws IOException { 14 return new Hessian2ObjectOutput(out); 15 } 16 17 public ObjectInput deserialize(URL url, InputStream is) throws IOException { 18 return new Hessian2ObjectInput(is); 19 } 20 21 }
output实现类:
1 public class Hessian2ObjectOutput implements ObjectOutput { 2 private final Hessian2Output mH2o; 3 4 public Hessian2ObjectOutput(OutputStream os) { 5 mH2o = new Hessian2Output(os); 6 mH2o.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY); 7 } 8 9 public void writeBool(boolean v) throws IOException { 10 mH2o.writeBoolean(v); 11 } 12 13 public void writeByte(byte v) throws IOException { 14 mH2o.writeInt(v); 15 } 16 17 public void writeShort(short v) throws IOException { 18 mH2o.writeInt(v); 19 } 20 21 public void writeInt(int v) throws IOException { 22 mH2o.writeInt(v); 23 } 24 25 public void writeLong(long v) throws IOException { 26 mH2o.writeLong(v); 27 } 28 29 public void writeFloat(float v) throws IOException { 30 mH2o.writeDouble(v); 31 } 32 33 public void writeDouble(double v) throws IOException { 34 mH2o.writeDouble(v); 35 } 36 37 public void writeBytes(byte[] b) throws IOException { 38 mH2o.writeBytes(b); 39 } 40 41 public void writeBytes(byte[] b, int off, int len) throws IOException { 42 mH2o.writeBytes(b, off, len); 43 } 44 45 public void writeUTF(String v) throws IOException { 46 mH2o.writeString(v); 47 } 48 49 public void writeObject(Object obj) throws IOException { 50 mH2o.writeObject(obj); 51 } 52 53 public void flushBuffer() throws IOException { 54 mH2o.flushBuffer(); 55 } 56 }
input实现类:
1 public class Hessian2ObjectInput implements ObjectInput { 2 private final Hessian2Input mH2i; 3 4 public Hessian2ObjectInput(InputStream is) { 5 mH2i = new Hessian2Input(is); 6 mH2i.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY); 7 } 8 9 public boolean readBool() throws IOException { 10 return mH2i.readBoolean(); 11 } 12 13 public byte readByte() throws IOException { 14 return (byte) mH2i.readInt(); 15 } 16 17 public short readShort() throws IOException { 18 return (short) mH2i.readInt(); 19 } 20 21 public int readInt() throws IOException { 22 return mH2i.readInt(); 23 } 24 25 public long readLong() throws IOException { 26 return mH2i.readLong(); 27 } 28 29 public float readFloat() throws IOException { 30 return (float) mH2i.readDouble(); 31 } 32 33 public double readDouble() throws IOException { 34 return mH2i.readDouble(); 35 } 36 37 public byte[] readBytes() throws IOException { 38 return mH2i.readBytes(); 39 } 40 41 public String readUTF() throws IOException { 42 return mH2i.readString(); 43 } 44 45 public Object readObject() throws IOException { 46 return mH2i.readObject(); 47 } 48 49 @SuppressWarnings("unchecked") 50 public <T> T readObject(Class<T> cls) throws IOException, 51 ClassNotFoundException { 52 return (T) mH2i.readObject(cls); 53 } 54 55 public <T> T readObject(Class<T> cls, Type type) throws IOException, ClassNotFoundException { 56 return readObject(cls); 57 } 58 59 }
其余的实现类也是相似。
若是想要改变序列化方式,能够更改配置,xml配置可使用<dubbo:protocol serialization="fastjson" />,springboot配置可使用dubbo.protocol.serialization=fastjson。
hessian 是一个比较老的序列化实现了,并且它是跨语言的,因此不是单独针对java进行优化的。而dubbo RPC实际上彻底是一种Java to Java的远程调用,其实没有必要采用跨语言的序列化方式(固然确定也不排斥跨语言的序列化)。
如今有一些新的序列化:
专门针对Java语言的:Kryo,FST等等跨语言的:Protostuff,ProtoBuf,Thrift,Avro,MsgPack等等这些序列化方式的性能多数都显著优于 hessian2 (甚至包括还没有成熟的dubbo序列化)。因此咱们能够 为 dubbo 引入 Kryo 和 FST 这两种高效 Java 来优化 dubbo 的序列化。