分佈式架構系統:深入淺出 RPC --- RPC框架與Dubbo完整使用 - 淺出篇 。

這並不是原理性的解釋文章,而是快速入門,還有一個完整的Java例子。一篇我覺得不錯的文章推薦:深入淺出 RPC - 淺出篇 

一、RPC

  1. 什麼是RPC?

    RPC(Remote Procedure Call)遠程過程調用。見名知意 - 從遠程主機調用一個過程/函數。

    RPC的目標是:使得本程序調用其它遠程主機上的函數,好像調用本程序內的函數一樣簡單,並且屏蔽編程語言的差異性。

    要實現上述目標首先需要設計一種通訊協議,被稱之爲RPC協議(Protocol):

    • RPC協議不是某一個具體的協議,而是一個類型名,代表一類叫做RPC的協議。

    • RPC協議是在TCP/UDP之上的應用層協議,廣義上可以跨越平臺、語言進行應用間通訊(說廣義是因爲可以開發一個協議但只支持單個語言)。

  2. 爲什麼要用RPC?

    其實這是系統開發到一定階段的強烈需求驅動的。

    1. 當我們開發的系統邏輯簡單、用戶不多、流量不大時,我們只需要一個單一應用系統,即此時我們用不着RPC。

    2. 隨着我們的系統業務增多、訪問量增大時,我們會發現一臺單機運行此係統已經無法應付壓力。此時,我們可以將系統業務拆分成幾個互不關聯的系統,分別部署在各自機器上,以劃清邏輯並減小壓力。此時,我們也可以不需要RPC,因爲應用之間是互不關聯的。

    3. 當我們的業務越來越多、應用系統也越來越多時,自然的,我們會發現有些功能已經不能簡單劃分開來或者劃分不出來。此時,可以將公共業務邏輯抽離出來,將之組成獨立的服務Service應用 。而原有的、新增的應用都可以與那些獨立的Service應用 交互,以此來完成完整的業務功能。所以此時,我們急需一種高效的應用程序之間的通訊手段來完成這種需求,所以你看,RPC大顯身手的時候來了!

    其實#3描述的場景也是服務化 微服務 分佈式系統架構 的基礎場景。即RPC框架就是實現以上結構的有力方式。

  3. 有哪些RPC?

    有很多RPC框架:CORBAR、Thrift、Dubbo等等。基本上他們分爲兩種類別:

    • 跨語言的。
    • 單一語言的,如果你的分佈式應用架構主體都是Java應用,顯然我們不應該使用跨語言的RPC來多一層中轉浪費效率。

    就Java來說,我認爲其本身API提供的RMI就是一種RPC協議,但是其畢竟太原始,需要自己去添加很多機制才能上生產環境。所以,今天介紹下我最近使用的Dubbo框架。

二、Dubbo使用實例

  1. 什麼是Dubbo?

    Dubbo是阿里巴巴爲Java開發的RPC 框架,據網上評價來看非常不錯。在Dubbo開源後很多公司都使用其來構建自己的分佈式架構。今天我來做一個使用實例。

    由於Dubbo官方文檔已經把一切都說的很詳細了,我就不沒意思的摘抄了,放上地址:官網

  2. 官網上也有詳細使用方法,那我爲什麼還要寫個使用實例呢?

    是因爲,似乎到2012年,Dubbo已經比較穩定的完成了所有開發,所以現在Dubbo其實是在一個鬆散的維護狀態下的。有些文檔內容已經失效:地址無法訪問,一些錯誤沒有明確說明。所以參照官網會有一些問題,我這裏就是解決了某些問題而完成的一個實例,放在這裏供大家參考。

建議大家先去看文檔,形成一個整體概念再做實例。 
我的整體架構是這樣的:

  • 使用Dubbo來服務化(基於Spring)。

  • 使用Zookeeper集羣作爲Dubbo服務註冊中心Zookeeper簡介與安裝)。

  • 使用Dubbo提供的一個JavaWeb項目作爲Dubbo服務管理控制檯。

  • 創建了一個服務提供者項目(pom父項目) - 叫dubbo-practice-provider

  • 創建了一個服務消費者項目(pom父項目) - 叫dubbo-practice-consumer。 
    另外說一點,這兩個只是練習項目,實際上一個項目可以既是提供者也是消費者。

步驟

  1. 首先,要確保Zookeeper的安裝和配置正確,可以直接按照我另一篇文章Zookeeper簡介與安裝來做。

  2. 我們需要一個Dubbo服務管理控制檯:

    本身這個項目的war包,Dubbo在其文檔中是給出了下載地址的,但是地址已經失效了。所以,現在只能去其GitHub地址上自己下載源碼下來打包了。

    1. 使用Eclipse,用其自帶的git插件下載dubbo項目整體,地址是:https://github.com/alibaba/dubbo.git

    2. 先將dubbo項目轉爲Maven項目,然後單獨將其中的子Maven項目dubbo-admin導出來,這就是一個JavaWeb項目。

    3. 但是這個項目,別直接Maven打包,因爲它有一些依賴問題需要修改,打開其pom.xml文件:

      <!-- 修改了兩點。
          1. 原本的version是${project.parent.version},其值在pom.xml上方有配置,實際上就是2.5.4-SNAPSHOT,但是經過查看發現在MAVEN庫中,Dubbo團隊只更新到了2.5.3。這個2.5.4-SNAPSHOT實際上是當前我們下載的這個源碼的版本,我們不想自己打包使用這個版本。所以就使用MAVEN上的2.5.3.
          2. 另一個是增加了<exclusions>spring,這是因爲dubbo缺省會依賴Spring,版本爲2.5.6.SEC03。但是下面一個依賴配置com.alibaba.citrus.citrus-webx-all卻也缺省依賴Spring,版本爲3.2.16.RELEASE。    
      -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>dubbo</artifactId>
          <version>2.5.3</version>
          <exclusions>
              <exclusion>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      如果使用Spring的2.5.6.SEC03版本直接打包,就會有如下錯誤:

      ERROR context.ContextLoader - Context initialization failed
      org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'uriBrokerService': Cannot create inner bean '(inner bean)' of type [com.alibaba.citrus.service.uribroker.impl.URIBrokerServiceImpl$URIBrokerInfo] while setting bean property 'brokers' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#25': Cannot create inner bean 'server' of type [com.alibaba.citrus.service.uribroker.uri.GenericURIBroker] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'server': Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'URIType' of bean class [com.alibaba.citrus.service.uribroker.uri.GenericURIBroker]: Bean property 'URIType' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:230)
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:122)
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:287)
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:126)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    4. 接着,如果此項目你不打算部署到與任意一個Zookeeper一個機器的話,就需要修改/dubbo-admin/src/main/webapp/WEB-INF/dubbo.properties文件,在其中指定你的Zookeeper地址(要保證這些機器能互相通訊)。

    5. 沒有要修改的了。可以使用Maven的package命令打包了。之後部署war項目,可以按照官網的部署方式,也就是將之部署爲ROOT應用,官網地址點這裏

  3. 服務提供者項目

    源碼地址:dubbo-practice-provider 
    其中有兩個子項目:

    • dubbo-practice-provider-api:暴漏接口和JavaBeans,讓實現項目引用然後去實現、讓消費者引用然後調用。這個比較簡單,一看就懂就不展開講了。
    • dubbo-practice-provider-impl:上面api項目的實現項目,是一個普通Java項目;

    實現者項目dubbo-practice-provider-impl的主要內容就是Dubbo如何暴漏一個服務的使用了,說一下:

    1. 首先是依賴關係,pom.xml

      
      <!-- 上一個API項目 -->
      <dependency>
          <groupId>dubbo-practice-provider-api</groupId>
          <artifactId>dubbo-practice-provider-api</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
      <!-- 本項目用的Spring,版本4.2.2.RELEASE -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <!-- dubbo,版本2.5.3 -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>dubbo</artifactId>
          <version>${dubbo.version}</version>
      </dependency>
      <!-- dubbo使用的zookeeper,版本3.4.8 -->
      <dependency>
          <groupId>org.apache.zookeeper</groupId>
          <artifactId>zookeeper</artifactId>
          <version>${zookeeper.version}</version>
      </dependency>
      <!-- zookeeper的一種客戶端zkclient,版本0.1 -->
      <dependency>
          <groupId>com.github.sgroschupf</groupId>
          <artifactId>zkclient</artifactId>
          <version>${zkclient.version}</version>
      </dependency>
      • 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
    2. 其次是dubbo配置,配置在Spring配置文件中,我放在/META-INF/spring/spring-dubbo.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
      xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
      http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
      
      <!-- 提供方應用信息,用於計算依賴關係 -->
      <dubbo:application name="dubbo-practice-provider" />
      
      <!-- 使用Zookeeper集羣註冊中心暴露服務地址 -->
      <dubbo:registry protocol="zookeeper" address="192.168.157.130:2181,192.168.157.129:2181" />
      
      <!-- 用dubbo協議在20880端口暴露服務,一個項目需要一個端口 -->
      <dubbo:protocol name="dubbo" port="20880" />
      
      <!-- Service 提供者 -->
      <!-- 聲明需要暴露的服務接口,interface指定接口,ref指定真正的實現者(SpringBean的id) -->
      <dubbo:service interface="com.ddup.dubbo.service.api.PersonService" ref="personService" />
      
      </beans>
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    3. 最後,做好之後就可以運行了,我寫了一個簡單的啓動服務類/dubbo-practice-provider-impl/src/main/java/com/ddup/dubbo/service/impl/DubboContainerStart.java,運行這個就行了,不要關。
  4. 服務消費者項目

    源碼地址:dubbo-practice-consumer; 
    主要就是Dubbo服務的調用了,見/META-INF/spring/spring-dubbo.xml

    <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 -->
    <dubbo:application name="dubbo-practice-consumer" />
    
    <!-- 使用與提供者一樣的Zookeeper集羣註冊中心,來獲取服務提供者信息 -->
    <dubbo:registry protocol="zookeeper" address="192.168.157.130:2181,192.168.157.129:2181" />
    
    <!-- 生成遠程服務代理,可以和本地bean一樣使用personService,init是否飢餓式初始化這個引用 -->
    <dubbo:reference id="personService" interface="com.ddup.dubbo.service.api.PersonService" init="true" />
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然後,運行/dubbo-practice-consumer/src/main/java/com/ddup/dubbo/consumer/SpringStart.java,鵝妹子嚶!!!可以看到,調用成功啦!

  5. 在上面#2說的管理控制檯上,現在你就可以看到服務了,能看到服務者以及每個服務的消費者等等信息;

    登錄 
    這裏寫圖片描述

    查看Dubbo服務 
    這裏寫圖片描述


以上!


TIPS:

  1. dubbo-admin項目的tomcat啓動後無法訪問:

    打開catalina.out查看錯誤

    [root@localhost logs]# vim catalina.out
    • 1

    如果發現如下錯誤,是因爲Zookeeper沒有成功啓動,可以去檢查Zookeeper的狀態。

    INFO velocity.VelocityEngine - SpringResourceLoaderAdapter : initialization starting.
    INFO velocity.VelocityEngine - SpringResourceLoaderAdapter : set path '/templates/common/'
    INFO velocity.VelocityEngine - SpringResourceLoaderAdapter : initialization complete.
    INFO rule.ExtensionMappingRule - Initialized extension.input:ExtensionMappingRule with cache disabled
    INFO rule.ExtensionMappingRule - Initialized extension.output:ExtensionMappingRule with cache disabled
    INFO rule.DirectModuleMappingRule - Initialized action:DirectModuleMappingRule with cache disabled
    INFO rule.DirectModuleMappingRule - Initialized screen.notemplate:DirectModuleMappingRule with cache disabled
    INFO rule.FallbackModuleMappingRule - Initialized screen:FallbackModuleMappingRule with cache enabled
    INFO rule.DirectTemplateMappingRule - Initialized screen.template:DirectTemplateMappingRule with cache disabled
    INFO rule.FallbackTemplateMappingRule - Initialized layout.template:FallbackTemplateMappingRule with cache enabled
    INFO rule.DirectModuleMappingRule - Initialized control.notemplate:DirectModuleMappingRule with cache disabled
    INFO rule.FallbackModuleMappingRule - Initialized control:FallbackModuleMappingRule with cache enabled
    INFO rule.DirectTemplateMappingRule - Initialized control.template:DirectTemplateMappingRule with cache disabled
    INFO zkclient.ZkEventThread - Starting ZkClient event thread.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  2. Provider的服務與Consumer引用時的一些問題:

    1. 關閉啓動時檢查 
      Dubbo默認會在啓動時檢查依賴的服務是否可用,不可用會拋出異常,阻止Spring初始化完成。如果對有些服務不關心,或者出現了循環依賴,必須有一方先啓動時,可以關閉啓動時檢查。方式如下:

      <dubbo:reference interface="com.xxx.XxxService" check="false" />
      • 1
    2. 引用默認還是延遲初始化的,只有引用被注入到其它Bean,或者被getBean()獲取時,纔會初始化。如果需要飢餓加載,即Dubbo啓動時就立即生成動態代理實例,則可以配置:

      <dubbo:reference interface="com.xx.XxxService" init="true" />
      • 1

2017.07.31更新:Dubbo官網聲明官方要重新開始重點維護此項目了!


轉載註明出處:http://blog.csdn.net/u010297957/article/details/51702076

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章