Dubbo : 簡單來說,Dubbo 是一個服務治理的框架,集中管理RPC調用,並提供多種訪問策略和負載來滿足應用系統之間的相互調用。
- 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>
接口定義
-
定義Maven接口項目
pom.xml<
project
xmlns
=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<
modelVersion
>4.0.0</
modelVersion
>
<
groupId
>com.z</
groupId
>
<
artifactId
>Iexample</
artifactId
>
<
version
>1.0</
version
>
</
project
>
-
定義接口
ISayHello.java1234package
com.z.iexample;
public
interface
ISayHello {
public
String sayHelloWaitAnswer(String s);
}
服務提供方(Provider)
-
定義Maven服務端項目,並提供相應依賴(Iexample,dubbo,zookeeper)。
pom.xml<
project
xmlns
=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<
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了。
-
實現接口的服務類
SayHelloImpl.java123456789101112131415161718192021package
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());
}
}
-
准備Spring的配置文件,因為這個示例是基於Spring Context實現的。
applicationContext.xml<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
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
=
"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
>
-
提供主程序入口
Main.java1234567891011121314151617package
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)
-
定義Maven項目,提供消費者的依賴
pom.xml<
project
xmlns
=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<
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
>
消費者的依賴也是根據服務而定,基本上與服務提供者相同,只是不需要實現接口,只需要調用即可。
-
提供Spring配置文件
applicationContext.xml<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
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
=
"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
>
-
提供Main入口調用服務
Main.java1234567891011121314151617181920212223242526272829303132333435package
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
- Dubbo里很多標簽在應用環境內都是唯一的,只有<dubbo:service>和<dubbo:reference>是多份的,但是需要注意,這兩個標簽的底層實現都是非常重的,所以盡量保證使用單例模式。
- 有時候在應用啟動時可能使用的服務還沒有注冊,這個時候默認啟動會報錯,可以在reference標簽添加check="false"來關閉啟動的檢測,只在真正發起調用時去檢查。
- Dubbo中存在很多的配置,從上往下有很多繼承關系,所以默認需要的配置很少,但是越小范圍的配置越高,在小范圍內沒有時默認采用上一級的配置,application,registry,provider,consumer都是教高層的配置,具體的配置在Dubbo官方文檔中有詳細的說明,大家可以去自己研究一下。
- 出現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"/>