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 的序列化。