這並不是原理性的解釋文章,而是快速入門,還有一個完整的Java例子。一篇我覺得不錯的文章推薦:深入淺出 RPC - 淺出篇 。
一、RPC
-
什麼是RPC?
RPC(Remote Procedure Call)遠程過程調用。見名知意 - 從遠程主機調用一個過程/函數。
RPC的目標是:使得本程序調用其它遠程主機上的函數,好像調用本程序內的函數一樣簡單,並且屏蔽編程語言的差異性。
要實現上述目標首先需要設計一種通訊協議,被稱之爲RPC協議(Protocol):
-
RPC協議不是某一個具體的協議,而是一個類型名,代表一類叫做RPC的協議。
-
RPC協議是在TCP/UDP之上的應用層協議,廣義上可以跨越平臺、語言進行應用間通訊(說廣義是因爲可以開發一個協議但只支持單個語言)。
-
-
爲什麼要用RPC?
其實這是系統開發到一定階段的強烈需求驅動的。
-
當我們開發的系統邏輯簡單、用戶不多、流量不大時,我們只需要一個單一應用系統,即此時我們用不着RPC。
-
隨着我們的系統業務增多、訪問量增大時,我們會發現一臺單機運行此係統已經無法應付壓力。此時,我們可以將系統業務拆分成幾個互不關聯的系統,分別部署在各自機器上,以劃清邏輯並減小壓力。此時,我們也可以不需要RPC,因爲應用之間是互不關聯的。
-
當我們的業務越來越多、應用系統也越來越多時,自然的,我們會發現有些功能已經不能簡單劃分開來或者劃分不出來。此時,可以將公共業務邏輯抽離出來,將之組成獨立的服務Service應用 。而原有的、新增的應用都可以與那些獨立的Service應用 交互,以此來完成完整的業務功能。所以此時,我們急需一種高效的應用程序之間的通訊手段來完成這種需求,所以你看,RPC大顯身手的時候來了!
其實
#3
描述的場景也是服務化 、微服務 和分佈式系統架構 的基礎場景。即RPC框架就是實現以上結構的有力方式。 -
-
有哪些RPC?
有很多RPC框架:CORBAR、Thrift、Dubbo等等。基本上他們分爲兩種類別:
- 跨語言的。
- 單一語言的,如果你的分佈式應用架構主體都是Java應用,顯然我們不應該使用跨語言的RPC來多一層中轉浪費效率。
就Java來說,我認爲其本身API提供的
RMI
就是一種RPC協議,但是其畢竟太原始,需要自己去添加很多機制才能上生產環境。所以,今天介紹下我最近使用的Dubbo框架。
二、Dubbo使用實例
-
什麼是Dubbo?
Dubbo是阿里巴巴爲Java開發的RPC 框架,據網上評價來看非常不錯。在Dubbo開源後很多公司都使用其來構建自己的分佈式架構。今天我來做一個使用實例。
由於Dubbo官方文檔已經把一切都說的很詳細了,我就不沒意思的摘抄了,放上地址:官網。
-
官網上也有詳細使用方法,那我爲什麼還要寫個使用實例呢?
是因爲,似乎到2012年,Dubbo已經比較穩定的完成了所有開發,所以現在Dubbo其實是在一個鬆散的維護狀態下的。有些文檔內容已經失效:地址無法訪問,一些錯誤沒有明確說明。所以參照官網會有一些問題,我這裏就是解決了某些問題而完成的一個實例,放在這裏供大家參考。
建議大家先去看文檔,形成一個整體概念再做實例。
我的整體架構是這樣的:
-
使用
Dubbo
來服務化(基於Spring
)。 -
使用
Zookeeper集羣
作爲Dubbo服務
的註冊中心
(Zookeeper簡介與安裝)。 -
使用
Dubbo
提供的一個JavaWeb
項目作爲Dubbo服務
管理控制檯。 -
創建了一個服務提供者項目(pom父項目) - 叫dubbo-practice-provider。
-
創建了一個服務消費者項目(pom父項目) - 叫dubbo-practice-consumer。
另外說一點,這兩個只是練習項目,實際上一個項目可以既是提供者也是消費者。
步驟
-
首先,要確保Zookeeper的安裝和配置正確,可以直接按照我另一篇文章Zookeeper簡介與安裝來做。
-
我們需要一個Dubbo服務管理控制檯:
本身這個項目的
war
包,Dubbo在其文檔中是給出了下載地址的,但是地址已經失效了。所以,現在只能去其GitHub地址上自己下載源碼下來打包了。-
使用Eclipse,用其自帶的git插件下載dubbo項目整體,地址是:https://github.com/alibaba/dubbo.git;
-
先將
dubbo項目
轉爲Maven項目,然後單獨將其中的子Maven項目dubbo-admin
導出來,這就是一個JavaWeb項目。 -
但是這個項目,別直接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
-
接着,如果此項目你不打算部署到與任意一個Zookeeper一個機器的話,就需要修改
/dubbo-admin/src/main/webapp/WEB-INF/dubbo.properties
文件,在其中指定你的Zookeeper
地址(要保證這些機器能互相通訊)。 -
沒有要修改的了。可以使用Maven的package命令打包了。之後部署war項目,可以按照官網的部署方式,也就是將之部署爲ROOT應用,官網地址點這裏。
-
-
服務提供者項目
源碼地址:dubbo-practice-provider
其中有兩個子項目:dubbo-practice-provider-api
:暴漏接口和JavaBeans,讓實現項目引用然後去實現、讓消費者引用然後調用。這個比較簡單,一看就懂就不展開講了。dubbo-practice-provider-impl
:上面api項目的實現項目,是一個普通Java項目;
實現者項目
dubbo-practice-provider-impl
的主要內容就是Dubbo如何暴漏一個服務的使用了,說一下:-
首先是依賴關係,
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
-
其次是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
- 最後,做好之後就可以運行了,我寫了一個簡單的啓動服務類
/dubbo-practice-provider-impl/src/main/java/com/ddup/dubbo/service/impl/DubboContainerStart.java
,運行這個就行了,不要關。
-
服務消費者項目
源碼地址: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
,鵝妹子嚶!!!可以看到,調用成功啦! -
在上面
#2
說的管理控制檯上,現在你就可以看到服務了,能看到服務者以及每個服務的消費者等等信息;登錄
查看Dubbo服務
以上!
TIPS:
-
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
-
Provider的服務與Consumer引用時的一些問題:
-
關閉啓動時檢查
Dubbo默認會在啓動時檢查依賴的服務是否可用,不可用會拋出異常,阻止Spring初始化完成。如果對有些服務不關心,或者出現了循環依賴,必須有一方先啓動時,可以關閉啓動時檢查。方式如下:<dubbo:reference interface="com.xxx.XxxService" check="false" />
- 1
-
引用默認還是延遲初始化的,只有引用被注入到其它Bean,或者被
getBean()
獲取時,纔會初始化。如果需要飢餓加載,即Dubbo啓動時就立即生成動態代理實例,則可以配置:<dubbo:reference interface="com.xx.XxxService" init="true" />
- 1
-
2017.07.31更新:Dubbo官網聲明官方要重新開始重點維護此項目了!
轉載註明出處:http://blog.csdn.net/u010297957/article/details/51702076