Dubbo


Dubbo : 簡單來說,Dubbo 是一個服務治理的框架,集中管理RPC調用,並提供多種訪問策略和負載來滿足應用系統之間的相互調用。

RPC 遠程過程調用協議: 它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程序之間攜帶信息數據。在OSI網絡通信模型中,RPC跨越了傳輸層應用層。RPC使得開發包括網絡分布式多程序在內的應用程序更加容易。
RPC采用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。首先,客戶機調用進程發送一個有進程參數的調用信息到服務進程,然后等待應答信息。在服務器端,進程保持睡眠狀態直到調用信息的到達為止。當一個調用信息到達,服務器獲得進程參數,計算結果,發送答復信息,然后等待下一個調用信息,最后,客戶端調用進程接收答復信息,獲得進程結果,然后調用執行繼續進行。
 
Dubbo架構

  • Provider: 暴露服務的服務提供方。
  • Consumer: 調用遠程服務的服務消費方。
  • Registry: 服務注冊與發現的注冊中心。
  • Monitor: 統計服務的調用次調和調用時間的監控中心。
  • Container: 服務運行容器。

注意:Registry 是一個很輕的東西,實際上Dubbo只是在注冊中心共享了服務的相關信息,Dubbo的主體是Provider和Consumer,這兩者都是屬於應用范 圍內的。Monitor也是很輕的模塊,需要有監控服務在Registry進行了注冊應用才能正常使用監控,監控宕掉不影響服務。

 

Dubbo 本身提供了多種協議的支持,hession協議也是其中之一。

dubbo://  dubbo缺省協議采用單一長連接和NIO異步通訊(非組撒),適合於小數據量大並發的服務調用,以及服務消費者機器數大於服務提者機器數的情況。

 

  • Dubbo缺省協議不適合傳送大數據量的服務,比如傳文件,傳視頻等,除非請求量很低。

 

    • rmi://
      RMI協議采用JDK標准的java.rmi.*實現,采用阻塞式短連接和JDK標准序列化方式。
    • hessian://
      Hessian協議用於集成Hessian的服務,Hessian底層采用Http通訊,采用Servlet暴露服務,Dubbo缺省內嵌Jetty作為服務器實現。
    • http://
       基於http的短連接協議,基本不會去使用了。
    • webservice://
       webservice
    • redis://
      Redis是一個高效的KV存儲服務器
    • memcached://
      Memcached是一個高效的KV緩存服務器
    • Thrift://
      Thrift是Facebook捐給Apache的一個RPC框架    

 

注冊中心介紹

Dubbo也支持多種類型的注冊中心,分別有:

    • Multicast
      基於組 播實現的注冊中心,互相發現
    • Zookeeper
      Zookeeper是Apacahe Hadoop的子項目,是一個樹型的目錄服務,支持變更推送,適合作為Dubbo服務的注冊中心,工業強度較高,可用於生產環境,並推薦使用。
    • Redis
      Redis是一個高效的KV存儲服務器
    • Simple
      注冊中心本身就是一個普通的Dubbo服務,可以減少第三方依賴,使整體通訊方式一致。

         <a href="http://alibaba.github.io/dubbo-doc-static/User+Guide-zh.htm" class="external-link" rel="nofollow">User+Guide-zh</a>

 

 

接口定義

  1. 定義Maven接口項目

    pom.xml
       < modelVersion >4.0.0</ modelVersion >
       < groupId >com.z</ groupId >
       < artifactId >Iexample</ artifactId >
       < version >1.0</ version >
    </ project >
  2. 定義接口
     

    ISayHello.java
    1
    2
    3
    4
    package  com.z.iexample;
    public  interface  ISayHello {
         public  String sayHelloWaitAnswer(String s);
    }

服務提供方(Provider)

 

  1. 定義Maven服務端項目,並提供相應依賴(Iexample,dubbo,zookeeper)。

    pom.xml
       < modelVersion >4.0.0</ modelVersion >
       < groupId >com.z</ groupId >
       < artifactId >example-server</ artifactId >
       < version >1.0</ version >
       < dependencies >
         < dependency >
             < groupId >com.z</ groupId >
             < artifactId >Iexample</ artifactId >
             < version >1.0</ version >
         </ dependency >
         < dependency >
             < groupId >com.alibaba</ groupId >
             < artifactId >dubbo</ artifactId >
             < version >2.5.3</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-context</ artifactId >
             < version >3.2.1.RELEASE</ version >
         </ dependency >
         < dependency >
             < groupId >com.github.sgroschupf</ groupId >
             < artifactId >zkclient</ artifactId >
             < version >0.1</ version >
         </ dependency >
         < dependency >
             < groupId >org.slf4j</ groupId >
             < artifactId >slf4j-api</ artifactId >
             < version >1.6.4</ version >
         </ dependency >
         < dependency >
             < groupId >org.slf4j</ groupId >
             < artifactId >slf4j-log4j12</ artifactId >
             < version >1.6.4</ version >
         </ dependency >
         < dependency >
             < groupId >log4j</ groupId >
             < artifactId >log4j</ artifactId >
             < version >1.2.16</ version >
         </ dependency >
       </ dependencies >
    </ project >

    Dubbo對外的依賴是需要什么就增加什么的jar依賴,我們需要到的依賴一個是dubbo自身的依賴,另外一個是注冊中心zookeeper的依賴,需要提供zookeeper的連接客戶端,再者就是需要實現的接口jar了。

  2. 實現接口的服務類

    SayHelloImpl.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package  com.z.example.server.rpc;
    import  java.text.DateFormat;
    import  java.text.SimpleDateFormat;
    import  java.util.Date;
    import  java.util.concurrent.atomic.AtomicInteger;
    import  org.slf4j.Logger;
    import  org.slf4j.LoggerFactory;
    import  com.z.iexample.ISayHello;
    public  class  SayHelloImpl  implements  ISayHello {
         private  final  Logger log = LoggerFactory.getLogger(getClass());
         private  DateFormat dateFormat =  new  SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
         private  String template =  "[%s] - %d." ;
         private  AtomicInteger count =  new  AtomicInteger();
     
         public  String sayHelloWaitAnswer(String s) {
             log.info( "Receive message {} from client" , s);
             Date now =  new  Date();
             String answerTime = dateFormat.format(now);
             return  String.format(template, answerTime, count.getAndIncrement());
         }
    }
  3. 准備Spring的配置文件,因為這個示例是基於Spring Context實現的。

    applicationContext.xml
    <? xml  version = "1.0"  encoding = "UTF-8" ?>
     
         <!-- 提供方應用信息,用於計算依賴關系 -->
         < dubbo:application  name = "say-hello-server"   />
         <!-- Group屬性指定dubbo在zookeeper中以什么路徑開始,group之間相對隔離,如果不寫,則所有服務都從根/開始 -->
         < dubbo:registry  address = "zookeeper://10.10.110.58:2181"  group = "dubbo"  client = "zkclient" />
         <!-- 如果注冊中心里有監控服務進行注冊,則可以開啟下面的配置,監控會從注冊中心尋找監控服務端,通過protocol="registry"指定 -->
    <!--     <dubbo:monitor protocol="registry"/> -->
         <!-- 服務提供方對外提供的連接數控制,connections代表與每一個消費者建立多少連接,accepts代表本服務提供方總共對外提供多少連接 -->
         < dubbo:provider  connections = "5"  accepts = "8" />
     
         <!-- 用dubbo協議在20880端口暴露服務 -->
         < dubbo:protocol  name = "dubbo"  port = "20880" />
     
         <!-- 聲明需要暴露的服務接口 -->
         < dubbo:service  interface = "com.z.iexample.ISayHello"  ref = "simpleServer" />
     
         <!-- 和本地bean一樣實現服務 -->
         < bean  id = "simpleServer"  class = "com.z.example.server.rpc.SayHelloImpl"  />
     
    </ beans >
  4. 提供主程序入口

    Main.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package  com.z.example.server;
    import  java.io.IOException;
    import  org.springframework.context.support.ClassPathXmlApplicationContext;
    public  class  Main {
         /**
          * @param args
          */
         public  static  void  main(String[] args) {
             ClassPathXmlApplicationContext context =  new  ClassPathXmlApplicationContext( "applicationContext.xml" );
             context.start();
             try  {
                 System.in.read();
             catch  (IOException e) {
                 e.printStackTrace();
             }
         }
    }

服務消費方(Consumer)

  1. 定義Maven項目,提供消費者的依賴

    pom.xml
       < modelVersion >4.0.0</ modelVersion >
       < groupId >com.z</ groupId >
       < artifactId >example-client</ artifactId >
       < version >1.0</ version >
       < dependencies >
         < dependency >
             < groupId >com.z</ groupId >
             < artifactId >Iexample</ artifactId >
             < version >1.0</ version >
         </ dependency >
         < dependency >
           < groupId >com.alibaba</ groupId >
           < artifactId >dubbo</ artifactId >
           < version >2.5.3</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-context</ artifactId >
             < version >3.2.1.RELEASE</ version >
         </ dependency >
         < dependency >
             < groupId >org.apache.zookeeper</ groupId >
             < artifactId >zookeeper</ artifactId >
             < version >3.4.6</ version >
         </ dependency >
         < dependency >
             < groupId >com.github.sgroschupf</ groupId >
             < artifactId >zkclient</ artifactId >
             < version >0.1</ version >
         </ dependency >
         < dependency >
             < groupId >org.slf4j</ groupId >
             < artifactId >slf4j-api</ artifactId >
             < version >1.6.4</ version >
         </ dependency >
         < dependency >
             < groupId >org.slf4j</ groupId >
             < artifactId >slf4j-log4j12</ artifactId >
             < version >1.6.4</ version >
         </ dependency >
         < dependency >
             < groupId >log4j</ groupId >
             < artifactId >log4j</ artifactId >
             < version >1.2.16</ version >
         </ dependency >
       </ dependencies >
    </ project >

    消費者的依賴也是根據服務而定,基本上與服務提供者相同,只是不需要實現接口,只需要調用即可。

  2. 提供Spring配置文件

    applicationContext.xml
    <? xml  version = "1.0"  encoding = "UTF-8" ?>
     
         <!-- 提供方應用信息,用於計算依賴關系 -->
         < dubbo:application  name = "say-hello-client"   />
     
         < dubbo:registry  address = "zookeeper://10.10.110.58:2181"  group = "dubbo"  client = "zkclient" />
         <!-- 與服務端相同,有監控服務注冊就可以開啟 -->
         <!-- <dubbo:monitor protocol="registry"/> -->
         <!-- 定義引用的服務 -->
         < dubbo:reference  id = "simpleClient"  interface = "com.z.iexample.ISayHello" />
     
    </ beans >
  3. 提供Main入口調用服務

    Main.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    package  com.z.example.client;
    import  java.io.IOException;
    import  org.slf4j.Logger;
    import  org.slf4j.LoggerFactory;
    import  org.springframework.context.support.ClassPathXmlApplicationContext;
    import  com.z.iexample.ISayHello;
    public  class  Main {
         private  final  Logger log = LoggerFactory.getLogger(getClass());
         private  ClassPathXmlApplicationContext context;
     
         public  Main() {
             context =  new  ClassPathXmlApplicationContext( "applicationContext.xml" );
             context.start();
         }
     
         public  void  start() {
             ISayHello simpleClient  = (ISayHello) context.getBean( "simpleClient" );
             for ( int  i =  0 ; i <  100 ; i++){
                 String answer = simpleClient.sayHelloWaitAnswer( "HOHO "  + i);
                 log.info( "Answer from server {}" , answer);
             }
         }
     
         /**
          * @param args
          */
         public  static  void  main(String[] args) {
             new  Main().start();
             try  {
                 System.in.read();
             catch  (IOException e) {
                 e.printStackTrace();
             }
         }
    }

    這樣啟動后就能正常訪問服務了。

F&Q

    1. Dubbo里很多標簽在應用環境內都是唯一的,只有<dubbo:service>和<dubbo:reference>是多份的,但是需要注意,這兩個標簽的底層實現都是非常重的,所以盡量保證使用單例模式。
    2. 有時候在應用啟動時可能使用的服務還沒有注冊,這個時候默認啟動會報錯,可以在reference標簽添加check="false"來關閉啟動的檢測,只在真正發起調用時去檢查。
    3. Dubbo中存在很多的配置,從上往下有很多繼承關系,所以默認需要的配置很少,但是越小范圍的配置越高,在小范圍內沒有時默認采用上一級的配置,application,registry,provider,consumer都是教高層的配置,具體的配置在Dubbo官方文檔中有詳細的說明,大家可以去自己研究一下。
    4. 出現java.io.IOException: Can not lock the registry cache file /home/deployer/.dubbo/dubbo-registry-xxxxx.cache, ignore and retry later的問題解決方法
      這個問題的出現是因為dubbo在用戶目錄下使用一個文件來緩存注冊中心的服務提供者的信息,那么在使用前會加上文件鎖,所以再一次使用這個文件是獲取鎖就會失敗,解決的方式是:
      1:確認應用內只有一個<registry>標簽,不同文件的情況下,也只能有一個
      2:在<registry>標簽內指定一個文件,使用file屬性 <registry address="xxx" file="xxx"/>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM