建議看原文 轉自:https://blog.csdn.net/xiaojin21cen/article/details/79834222 1、dubbo 協議 (默認) 2、rmi 協議 3、hessian 協議 4、http 協議 5、webservice 協議 6、thrift 協議 7、memcached 協議 8、redis 協議 面試題: Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多種協議,但是Dubbo官網是推薦我們使用Dubbo協議的。 下面我們就針對Dubbo的每種協議詳解講解,以便我們在實際應用中能夠正確取舍。 1、dubbo 協議 (默認)
缺省協議,使用基於mina1.1.7+hessian3.2.1的tbremoting交互。 連接個數:單連接 連接方式:長連接 傳輸協議:TCP 傳輸方式:NIO異步傳輸 序列化:Hessian 二進制序列化 適用范圍:傳入傳出參數數據包較小(建議小於100K),消費者比提供者個數多,單一消費者無法壓滿提供者,盡量不要用dubbo協議傳輸大文件或超大字符串。 適用場景:常規遠程服務方法調用 1、dubbo默認采用dubbo協議,dubbo協議采用單一長連接和NIO異步通訊,適合於小數據量大並發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的情況 2、他不適合傳送大數據量的服務,比如傳文件,傳視頻等,除非請求量很低。 配置如下: <dubbo:protocol name="dubbo" port="20880" /> <!-- Set default protocol: --> <dubbo:provider protocol="dubbo" /> <~-- Set service protocol --> <dubbo:service protocol="dubbo" /> <!-- Multi port --> <dubbo:protocol id="dubbo1" name="dubbo" port="20880" /> <dubbo:protocol id="dubbo2" name="dubbo" port="20881" />. <!-- Dubbo protocol options: --> <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” /> 3、Dubbo協議缺省每服務每提供者每消費者使用單一長連接,如果數據量較大,可以使用多個連接。 <dubbo:protocol name="dubbo" connections="2" /> <dubbo:service connections=”0”>或<dubbo:reference connections=”0”>表示該服務使用JVM共享長連接。(缺省) <dubbo:service connections=”1”>或<dubbo:reference connections=”1”>表示該服務使用獨立長連接。 <dubbo:service connections=”2”>或<dubbo:reference connections=”2”>表示該服務使用獨立兩條長連接。 4、為防止被大量連接撐掛,可在服務提供方限制大接收連接數,以實現服務提供方自我保護 <dubbo:protocol name="dubbo" accepts="1000" /> 為什么要消費者比提供者個數多? 因dubbo協議采用單一長連接,假設網絡為千兆網卡(1024Mbit=128MByte),根據測試經驗數據每條連接最多只能壓滿7MByte(不同的環境可能不一樣,供參考),理論上1個服務提供者需要20個服務消費者才能壓滿網卡 為什么不能傳大包? 因dubbo協議采用單一長連接,如果每次請求的數據包大小為500KByte,假設網絡為千兆網卡(1024Mbit=128MByte),每條連接最大7MByte(不同的環境可能不一樣,供參考),單個服務提供者的TPS(每秒處理事務數)最大為:128MByte / 500KByte = 262。單個消費者調用單個服務提供者的TPS(每秒處理事務數)最大為:7MByte / 500KByte = 14。如果能接受,可以考慮使用,否則網絡將成為瓶頸。 為什么采用異步單一長連接? 因為服務的現狀大都是服務提供者少,通常只有幾台機器,而服務的消費者多,可能整個網站都在訪問該服務,比如Morgan的提供者只有6台提供者,卻有上百台消費者,每天有1.5億次調用,如果采用常規的hessian服務,服務提供者很容易就被壓跨,通過單一連接,保證單一消費者不會壓死提供者,長連接,減少連接握手驗證等,並使用異步IO,復用線程池,防止C10K問題。 接口增加方法,對客戶端無影響,如果該方法不是客戶端需要的,客戶端不需要重新部署; 輸入參數和結果集中增加屬性,對客戶端無影響,如果客戶端並不需要新屬性,不用重新 部署; 輸入參數和結果集屬性名變化,對客戶端序列化無影響,但是如果客戶端不重新部署,不管輸入還是輸出,屬性名變化的屬性值是獲取不到的。 總結:服務器端 和 客戶端 對 領域對象 並不需要完全一致,而是按照最大匹配原則。 如果不是集成Spring,單獨配置如下: dubbo.service.protocol=dubbo
2、rmi 協議
Java標准的遠程調用協議。 連接個數:多連接 連接方式:短連接 傳輸協議:TCP 傳輸方式:同步傳輸 序列化:Java標准二進制序列化 適用范圍:傳入傳出參數數據包大小混合,消費者與提供者個數差不多,可傳文件。 適用場景:常規遠程服務方法調用,與原生RMI服務互操作 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接口,並以此接口暴露服務, 但如果設置了<dubbo:protocol name="rmi" codec="spring" />,將不生成$Remote接口,而使用Spring的RmiInvocationHandler接口暴露服務,和Spring兼容。 <!-- Define rmi protocol --> <dubbo:protocol name="rmi" port="1099" />. <!-- Set default protocol: --> <dubbo:provider protocol="rmi" /> <!-- Set service protocol: --> <dubbo:service protocol="rmi" /> <!-- Multi port --> <dubbo:protocol id="rmi1" name="rmi" port="1099" /> <dubbo:protocol id="rmi2" name="rmi" port="2099" /> <dubbo:service protocol="rmi1" /> <!-- Spring compatible: --> <dubbo:protocol name="rmi" codec="spring" />
3、hessian 協議 基於Hessian的遠程調用協議。 連接個數:多連接 連接方式:短連接 傳輸協議:HTTP 傳輸方式:同步傳輸 序列化:表單序列化 適用范圍:傳入傳出參數數據包大小混合,提供者比消費者個數多,可用瀏覽器查看,可用表單或URL傳入參數,暫不支持傳文件。 適用場景:需同時給應用程序和瀏覽器JS使用的服務。 1、Hessian協議用於集成Hessian的服務,Hessian底層采用Http通訊,采用Servlet暴露服務,Dubbo缺省內嵌Jetty作為服務器實現。 2、Hessian是Caucho開源的一個RPC框架:http://hessian.caucho.com,其通訊效率高於WebService和Java自帶的序列化。 依賴: <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.7</version> </dependency> 可以和原生Hessian服務互操作,即: 提供者用Dubbo的Hessian協議暴露服務,消費者直接用標准Hessian接口調用,或者提供方用標准Hessian暴露服務,消費方用Dubbo的Hessian協議調用。 約束 1、參數及返回值需實現Serializable接口 2、參數及返回值不能自定義實現List, Map, Number, Date, Calendar等接口,只能用JDK自帶的實現,因為hessian會做特殊處理,自定義實現類中的屬性值都會丟失。 <!-- Define hessian protocol: --> <dubbo:protocol name="hessian" port="8080" server="jetty" /> <!-- Set default protocol: --> <dubbo:provider protocol="hessian" /> <!-- Set service protocol: --> <dubbo:service protocol="hessian" /> <!-- Multi port: --> <dubbo:protocol id="hessian1" name="hessian" port="8080" /> <dubbo:protocol id="hessian2" name="hessian" port="8081" /> <!-- Directly provider: --> <dubbo:reference id="helloService" interface="HelloWorld" url="hessian://10.20.153.10:8080/helloWorld" /> <!-- Jetty Server --> <dubbo:protocol ... server="jetty" /> <!-- Servlet Bridge Server --> <dubbo:protocol ... server="servlet" /> web.xml配置: <servlet> <servlet-name>dubbo</servlet-name> <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dubbo</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> 注意:如果使用servlet派發請求 協議的端口必須與servlet容器的端口相同, 協議的上下文路徑必須與servlet應用的上下文路徑相同。
4、http 協議 基於http表單的遠程調用協議。參見:[HTTP協議使用說明] 連接個數:多連接 連接方式:短連接 傳輸協議:HTTP 傳輸方式:同步傳輸 序列化:表單序列化 適用范圍:傳入傳出參數數據包大小混合,提供者比消費者個數多,可用瀏覽器查看,可用表單或URL傳入參數,暫不支持傳文件。 適用場景:需同時給應用程序和瀏覽器JS使用的服務。 1、采用Spring的 HttpInvoker 實現 配置 <dubbo:protocol name="http" port="8080" /> <!-- Jetty Server --> <dubbo:protocol ... server="jetty" /> <!-- Servlet Bridge Server --> <dubbo:protocol ... server="servlet" /> web.xml配置 <servlet> <servlet-name>dubbo</servlet-name> <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dubbo</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> 注意:如果使用 servlet 派發請求 協議的端口<dubbo:protocol port="8080" />必須與servlet容器的端口相同, 協議的上下文路徑<dubbo:protocol contextpath="foo" />必須與servlet應用的上下文路徑相同。
5、webservice 協議 基於WebService的遠程調用協議 連接個數:多連接 連接方式:短連接 傳輸協議:HTTP 傳輸方式:同步傳輸 序列化:SOAP文本序列化 適用場景:系統集成,跨語言調用 1、基於CXF的 frontend-simple 和 transports-http 實現。 2、CXF是Apache開源的一個RPC框架:http://cxf.apache.org,由Xfire和Celtix合並而來 。 依賴 <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-simple</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>2.6.1</version> </dependency> 可以和原生WebService服務互操作,即: 提供者用Dubbo的WebService協議暴露服務,消費者直接用標准WebService接口調用,或者提供方用標准WebService暴露服務,消費方用Dubbo的WebService協議調用。 約束: 參數及返回值需實現Serializable接口 參數盡量使用基本類型和POJO。 <!-- Define webservice protocol --> <dubbo:protocol name="webservice" port="8080" server="jetty" /> <!-- Set default protocol --> <dubbo:provider protocol="webservice" /> <!-- Set service protocol --> <dubbo:service protocol="webservice" /> <!-- Multi port --> <dubbo:protocol id="webservice1" name="webservice" port="8080" /> <dubbo:protocol id="webservice2" name="webservice" port="8081" /> <!-- Directly provider --> <dubbo:reference id="helloService" interface="HelloWorld" url="webservice://10.20.153.10:8080/com.foo.HelloWorld" /> <!-- WSDL --> http://10.20.153.10:8080/com.foo.HelloWorld?wsdl <!-- Jetty Server: (default) --> <dubbo:protocol ... server="jetty" /> <!-- Servlet Bridge Server: (recommend) --> <dubbo:protocol ... server="servlet" /> web.xml <servlet> <servlet-name>dubbo</servlet-name> <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dubbo</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> 注意:如果使用servlet派發請求: 協議的端口必須與servlet容器的端口相同, 協議的上下文路徑必須與servlet應用的上下文路徑相同。 6、thrift 協議 當前 dubbo 支持的 thrift 協議是對 thrift 原生協議的擴展,在原生協議的基礎上添加了一些額外的頭信息,比如service name,magic number等。使用dubbo thrift協議同樣需要使用thrift的idl compiler編譯生成相應的java代碼,后續版本中會在這方面做一些增強 依賴 <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.8.0</version> </dependency> 配置: <dubbo:protocol name="thrift" port="3030" /> Thrift不支持null值,不能在協議中傳null 7、memcached 協議 可以通過腳本或監控中心手工填寫表單注冊memcached服務的地址: RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); 然后在客戶端使用時,不需要感知Memcached的地址: <dubbo:reference id="cache" interface="http://10.20.160.198/wiki/display/dubbo/java.util.Map" group="member" /> 或者點對點直連 <dubbo:reference id="cache" interface="http://10.20.160.198/wiki/display/dubbo/java.util.Map" url="memcached://10.20.153.10:11211" /> 自定義接口 <dubbo:reference id="cache" interface="com.foo.CacheService" url="memcached://10.20.153.10:11211" /> 方法名建議和memcached的標准方法名相同,即:get(key), set(key, value), delete(key)。 如果方法名和memcached的標准方法名不相同,則需要配置映射關系:(其中”p:xxx”為spring的標准p標簽) <dubbo:reference id="cache" interface="com.foo.CacheService" url="memcached://10.20.153.10:11211" p:set="putFoo" p:get="getFoo" p:delete="removeFoo" /> 8、redis 協議 可以通過腳本或監控中心手工填寫表單注冊redis服務的地址: RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("redis://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); 然后在客戶端使用時,不需要感知Redis的地址: <dubbo:reference id="store" interface="http://10.20.160.198/wiki/display/dubbo/java.util.Map" group="member" /> 點對點直連 <dubbo:reference id="store" interface="http://10.20.160.198/wiki/display/dubbo/java.util.Map" url="redis://10.20.153.10:6379" /> 自定義接口 <dubbo:reference id="store" interface="com.foo.StoreService" url="redis://10.20.153.10:6379" /> 方法名建議和redis的標准方法名相同,即:get(key), set(key, value), delete(key)。 如果方法名和redis的標准方法名不相同,則需要配置映射關系:(其中”p:xxx”為spring的標准p標簽) <dubbo:reference id="cache" interface="com.foo.CacheService" url="memcached://10.20.153.10:11211" p:set="putFoo" p:get="getFoo" p:delete="removeFoo" /> 面試題: 1、dubbo 默認使用什么序列化框架,你知道的還有哪些? 默認使用Hessian序列化。還有Duddo、FastJson、Java自帶序列化。 2、dubbo推薦用什么協議? 默認使用dubbo協議。