Dubbo協議及序列化

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

相關文章
相關標籤/搜索