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"/>