1. 为什么需要 Dubbo
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
2. Dubbo 的架构(摘自http://dubbo.apache.org/zh-cn/docs/user/quick-start.html)
节点角色说明
节点 | 角色说明 |
---|---|
Provider |
暴露服务的服务提供方 |
Consumer |
调用远程服务的服务消费方 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
Container |
服务运行容器 |
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
连通性
- 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
- 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
- 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
- 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
- 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
- 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
- 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
- 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
伸缩性
- 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
- 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
升级性
当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构:
节点角色说明
节点 | 角色说明 |
---|---|
Deployer |
自动部署服务的本地代理 |
Repository |
仓库用于存储服务应用发布包 |
Scheduler |
调度中心基于访问压力自动增减服务提供者 |
Admin |
统一管理控制台 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
3. Dubbo 的使用,快速启动 Dubbo 服务
我这里使用STS建立父子项目,具体的项目结构如下:
其中 dubbo-server项目引用了 api,provider 两个公共模块。pom文件如下:
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
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-server</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-provider</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
|
再来看一下dubbo-api的pom文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-api</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
|
dubbo-provider:
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-provider</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-api</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>
2.5
.
3
</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>
3.4
.
10
</version>
</dependency>
<dependency><!--注册中心-->
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>
0.10
</version>
</dependency>
<dependency><!--多协议-->
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>
4.0
.
38
</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>
2.5
</version>
</dependency>
<dependency><!--多容器启动的时候-->
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>
6.1
.
26
</version>
</dependency>
</dependencies>
</project>
|
最后来看一下dubbo-client的pom文件:
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-client</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-server</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>
2.5
.
6
</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>
3.4
.
10
</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>
0.10
</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>
4.0
.
38
</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>
2.5
</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>
6.1
.
26
</version>
</dependency>
</dependencies>
</project>
|
好了,环境准备好接下去可以进入代码的编写,快速开始一个dubbo项目。先来编写服务提供方,之前我们学习过RPC远程过程调用,这里的机制差不多,同样需要一个接口,通过注册中心把这个服务发布出去:先再api 工程种定义好接口:
1
2
3
4
|
public
interface
IGpHello {
String sayHello(String msg);
}
|
在 provider 项目中对其进行实现:
1
2
3
4
5
6
7
|
public
class
GpHelloImpl
implements
IGpHello{
@Override
public
String sayHello(String msg) {
return
"Hello:"
+msg;
}
}
|
dubbo 是基于 spring 进行拓展的。这里相应的配置需要通过spring的配置文件的方式去加载,我们这里需要新增一个 xml 配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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<br> http://www.springframework.org/schema/beans/spring-beans.xsd<br> http://code.alibabatech.com/schema/dubbo<br> http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>
<!--提供方信息-->
<dubbo:application name=
"dubbo-server"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.155.135:2181"
file=
"d:/dubbo-server"
/>
<!--配置需要发布的协议及端口-->
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<!--需要发布的服务-->
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
/>
<!--需要发布的服务实现类-->
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl"
/>
</beans>
|
由于 dubbo 读取配置文件的默认路径是 classpath下的 META-INF/spring/ 这个路径下,所以我也是放在此路径下,下面启动服务:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
Bootstrap {
public
static
void
main(String[] args)
throws
IOException {
ClassPathXmlApplicationContext context=
new
ClassPathXmlApplicationContext
(
"META-INF/spring/dubbo-server.xml"
);
context.start();
System.in.read();
//阻塞当前进程
}
}
|
对于启动还有另外一种方式:
1
2
3
4
5
6
7
8
|
public
class
Main {
public
static
void
main(String[] args)
throws
IOException {
//默认情况下会使用spring容器来启动服务
com.alibaba.dubbo.container.Main.main(
new
String[]{
"spring"
,
"log4j"
});
}
}
|
这种方式可以指定启动的容器等信息。
接下去会在 zk 服务器上面看到如下节点:/dubbo/com.gupaoedu.dubbo.IGpHello/providers/dubbo下又一个服务注册信息:
%3A%2F%2F192.168.254.1%3A20880%2Fcom.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbosedubbo%3A%2F%2F192.168.254.1%3A20880%2F
com.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubboserver%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello
%26methods%3DsayHello%26owner%3Dwuzz%26pid%3D15704%26side%3Dprovider%26timestamp%3D1543199821689
翻译过来就是
dubbo://192.168.254.1:20880/com.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbosedubbo%3A%2F%2F192.168.254.1%3A20880%2F
com.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubboserver%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello
%26methods%3DsayHello%26owner%3Dwuzz%26pid%3D15704%26side%3Dprovider%26timestamp%3D1543199821689
红色部分后面就是请求的一些参数,版本信息等等的请求参数。这样就把服务注册好了。现在我们需要来看看服务调用方,客户端调用也需要一个配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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-client"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry address=
"zookeeper://192.168.254.135:2181"
/>
<!--调用的服务名称,协议-->
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
protocol=
"dubbo"
/>
</beans>
|
然后启动服务进行调用,控制台输出Hello:WUZZ 完成服务调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
App {
public
static
void
main(String[] args)
throws
IOException, InterruptedException {
ClassPathXmlApplicationContext context =
new
ClassPathXmlApplicationContext(
"dubbo-client.xml"
);
// 得到IGpHello的远程代理对象
IGpHello iGpHello = (IGpHello) context.getBean(
"gpHelloService"
);
System.out.println(iGpHello.sayHello(
"GUPAO"
));
Thread.sleep(
1000
);
System.in.read();
}
}
|
4. Dubbo 注册中心原理
注册中心原理在之前我们RPC集成ZK注册中心我们就说过,这里简单重复一下,就是利用zookeeper的节点特性,在一个服务根节点永久节点下创建一个带有协议地址和参数的临时节点,同时客户端获取服务节点集合并且注册事件,在服务注册及服务宕机的时候引发watch事件来监控服务的上下线。
5. 多协议支持
多协议支持的演示,我这里把刚刚哪个服务换成dubbo跟hessian协议,两种协议支持,需要在provider项目的 dubbo-server.xml种配置如下信息:
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
|
<?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-server"
owner=
"mic"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.155.135:2181"
/>
<dubbo:registry id=
"zk2"
address=
"zookeeper://192.168.155.135:2181"
/>
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<dubbo:protocol port=
"8080"
name=
"hessian"
/>
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
protocol=
"dubbo,hessian"
registry=
"zk1"
/>
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl"
/>
</beans>
|
启动项目后我们会发现zookeeper节点下出现2条注册信息的节点,这样就配置好了多协议服务支持:
hessian%3A%2F%2F192.168.254.1%3A8080%2Fcom.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbo-server%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello%26methods%3DsayHello%26owner%3Dmic%26pid%3D24084%26side%3Dprovider%26timestamp%3D1543201939061, dubbo%3A%2F%2F192.168.254.1%3A20880%2Fcom.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbo-server%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello%26methods%3DsayHello%26owner%3Dmic%26pid%3D24084%26side%3Dprovider%26timestamp%3D1543201933970
客户端调用也需要相应的配置,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?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-client"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry address=
"zookeeper://192.168.155.135:2181"
/>
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<dubbo:protocol port=
"8080"
name=
"hessian"
/>
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
protocol=
"hessian"
/><!--这里的protocol可以自己指定需要的协议-->
</beans>
|
Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的。
6. 启动检查机制
对于两个dubbo服务需要相互调用,但是在某一个服务未启动,另外的服务启动的时候从注册中心上获取不到该服务的信息就会报错,这里需要配置一下不启动检查机制:
1
2
3
4
|
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
check=
"false"
protocol=
"hessian"
/>
|
这里的 check="false" 就是取消启动检查,但是还是会提示一些服务未注册的错误信息。
7.集群的访问:
实现集群的方式这里也是同样的简单。我们只要发布同一个服务到两个地址,我这边先重新定义一个接口实现,便于辨别:
1
2
3
4
5
6
7
|
public
class
GpHelloImpl2
implements
IGpHello{
@Override
public
String sayHello(String msg) {
return
"Hello,i'm server 2:"
+msg;
}
}
|
然后我这边重新定义两个server.xml文件,这两个配置的server的ID必须要是一致的:dubbo-cluster1.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?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-server"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.155.136:2181"
/>
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
protocol=
"dubbo"
registry=
"zk1"
/>
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl"
/>
</beans>
|
dubbo-cluster2.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?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-server"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.155.135:2181"
/>
<dubbo:protocol port=
"20881"
name=
"dubbo"
/>
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
protocol=
"dubbo"
registry=
"zk1"
/>
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl2"
/>
</beans>
|
然后新建两个启动类:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
BootstrapCluster1 {
public
static
void
main(String[] args)
throws
IOException {
ClassPathXmlApplicationContext context=
new
ClassPathXmlApplicationContext
(
"META-INF/spring/dubbo-cluster1.xml"
);
context.start();
System.in.read();
//阻塞当前进程
}
}
|
1
2
3
4
5
6
7
8
9
10
11
|
public
class
BootstrapCluster2 {
public
static
void
main(String[] args)
throws
IOException {
ClassPathXmlApplicationContext context=
new
ClassPathXmlApplicationContext
(
"META-INF/spring/dubbo-cluster2.xml"
);
context.start();
System.in.read();
//阻塞当前进程
}
}
|
客户端的xml配置文件修改如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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-client"
owner=
"lf"
/>
<!--注册中心-->
<dubbo:registry address=
"zookeeper://192.168.155.135:2181"
/>
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
protocol=
"dubbo"
/>
</beans>
|
这里实现集群,使用的是默认负载的随机算法,我们使用客户端循环10此去调用该服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
class
App {
public
static
void
main(String[] args)
throws
IOException, InterruptedException {
ClassPathXmlApplicationContext context =
new
ClassPathXmlApplicationContext(
"dubbo-client.xml"
);
for
(
int
i=
0
;i<
10
;i++) {
// 得到IGpHello的远程代理对象
IGpHello iGpHello = (IGpHello) context.getBean(
"gpHelloService"
);
System.out.println(iGpHello.sayHello(
"lf"
));
Thread.sleep(
1000
);
}
System.in.read();
}
}
|
1
2
3
4
5
6
7
8
9
10
|
Hello:lf
Hello:lf
Hello:lf
Hello:lf
Hello,i'm server
2
:lf
Hello,i'm server
2
:lf
Hello,i'm server
2
:lf
Hello,i'm server
2
:lf
Hello,l ubbo作为一个分布式服务治理架构,所具备的功能远远不止这些,了解了dubbo所提供的一些功能,我要进行下一步更加深入的学习啦。下面的学习都基于这个demo
|
1. 为什么需要 Dubbo(摘自http://dubbo.apache.org/zh-cn/docs/user/quick-start.html)
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
2. Dubbo 的架构(摘自http://dubbo.apache.org/zh-cn/docs/user/quick-start.html)
节点角色说明
节点 | 角色说明 |
---|---|
Provider |
暴露服务的服务提供方 |
Consumer |
调用远程服务的服务消费方 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
Container |
服务运行容器 |
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
连通性
- 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
- 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
- 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
- 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
- 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
- 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
- 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
- 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
伸缩性
- 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
- 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
升级性
当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构:
节点角色说明
节点 | 角色说明 |
---|---|
Deployer |
自动部署服务的本地代理 |
Repository |
仓库用于存储服务应用发布包 |
Scheduler |
调度中心基于访问压力自动增减服务提供者 |
Admin |
统一管理控制台 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
3. Dubbo 的使用,快速启动 Dubbo 服务
我这里使用STS建立父子项目,具体的项目结构如下:
其中 dubbo-server项目引用了 api,provider 两个公共模块。pom文件如下:
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
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-server</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-provider</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
|
再来看一下dubbo-api的pom文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-api</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
|
dubbo-provider:
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-provider</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-api</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>
2.5
.
3
</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>
3.4
.
10
</version>
</dependency>
<dependency><!--注册中心-->
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>
0.10
</version>
</dependency>
<dependency><!--多协议-->
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>
4.0
.
38
</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>
2.5
</version>
</dependency>
<dependency><!--多容器启动的时候-->
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>
6.1
.
26
</version>
</dependency>
</dependencies>
</project>
|
最后来看一下dubbo-client的pom文件:
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<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>
<parent>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</parent>
<artifactId>dubbo-client</artifactId>
<properties>
<project.build.sourceEncoding>UTF-
8
</project.build.sourceEncoding>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.gupaoedu.dubbo</groupId>
<artifactId>dubbo-server</artifactId>
<version>
0.0
.
1
-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>
2.5
.
6
</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>
3.4
.
10
</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>
0.10
</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>
4.0
.
38
</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>
2.5
</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>
6.1
.
26
</version>
</dependency>
</dependencies>
</project>
|
好了,环境准备好接下去可以进入代码的编写,快速开始一个dubbo项目。先来编写服务提供方,之前我们学习过RPC远程过程调用,这里的机制差不多,同样需要一个接口,通过注册中心把这个服务发布出去:先再api 工程种定义好接口:
1
2
3
4
|
public
interface
IGpHello {
String sayHello(String msg);
}
|
在 provider 项目中对其进行实现:
1
2
3
4
5
6
7
|
public
class
GpHelloImpl
implements
IGpHello{
@Override
public
String sayHello(String msg) {
return
"Hello:"
+msg;
}
}
|
dubbo 是基于 spring 进行拓展的。这里相应的配置需要通过spring的配置文件的方式去加载,我们这里需要新增一个 xml 配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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<br> http://www.springframework.org/schema/beans/spring-beans.xsd<br> http://code.alibabatech.com/schema/dubbo<br> http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>
<!--提供方信息-->
<dubbo:application name=
"dubbo-server"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.254.135:2181"
file=
"d:/dubbo-server"
/>
<!--配置需要发布的协议及端口-->
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<!--需要发布的服务-->
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
/>
<!--需要发布的服务实现类-->
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl"
/>
</beans>
|
由于 dubbo 读取配置文件的默认路径是 classpath下的 META-INF/spring/ 这个路径下,所以我也是放在此路径下,下面启动服务:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
Bootstrap {
public
static
void
main(String[] args)
throws
IOException {
ClassPathXmlApplicationContext context=
new
ClassPathXmlApplicationContext
(
"META-INF/spring/dubbo-server.xml"
);
context.start();
System.in.read();
//阻塞当前进程
}
}
|
对于启动还有另外一种方式:
1
2
3
4
5
6
7
8
|
public
class
Main {
public
static
void
main(String[] args)
throws
IOException {
//默认情况下会使用spring容器来启动服务
com.alibaba.dubbo.container.Main.main(
new
String[]{
"spring"
,
"log4j"
});
}
}
|
这种方式可以指定启动的容器等信息。
接下去会在 zk 服务器上面看到如下节点:/dubbo/com.gupaoedu.dubbo.IGpHello/providers/dubbo下又一个服务注册信息:
%3A%2F%2F192.168.254.1%3A20880%2Fcom.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbosedubbo%3A%2F%2F192.168.254.1%3A20880%2F
com.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubboserver%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello
%26methods%3DsayHello%26owner%3Dwuzz%26pid%3D15704%26side%3Dprovider%26timestamp%3D1543199821689
翻译过来就是
dubbo://192.168.254.1:20880/com.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbosedubbo%3A%2F%2F192.168.254.1%3A20880%2F
com.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubboserver%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello
%26methods%3DsayHello%26owner%3Dwuzz%26pid%3D15704%26side%3Dprovider%26timestamp%3D1543199821689
红色部分后面就是请求的一些参数,版本信息等等的请求参数。这样就把服务注册好了。现在我们需要来看看服务调用方,客户端调用也需要一个配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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-client"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry address=
"zookeeper://192.168.254.135:2181"
/>
<!--调用的服务名称,协议-->
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
protocol=
"dubbo"
/>
</beans>
|
然后启动服务进行调用,控制台输出Hello:WUZZ 完成服务调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
App {
public
static
void
main(String[] args)
throws
IOException, InterruptedException {
ClassPathXmlApplicationContext context =
new
ClassPathXmlApplicationContext(
"dubbo-client.xml"
);
// 得到IGpHello的远程代理对象
IGpHello iGpHello = (IGpHello) context.getBean(
"gpHelloService"
);
System.out.println(iGpHello.sayHello(
"WUZZ"
));
Thread.sleep(
1000
);
System.in.read();
}
}
|
4. Dubbo 注册中心原理
注册中心原理在之前我们RPC集成ZK注册中心我们就说过,这里简单重复一下,就是利用zookeeper的节点特性,在一个服务根节点永久节点下创建一个带有协议地址和参数的临时节点,同时客户端获取服务节点集合并且注册事件,在服务注册及服务宕机的时候引发watch事件来监控服务的上下线。
5. 多协议支持
多协议支持的演示,我这里把刚刚哪个服务换成dubbo跟hessian协议,两种协议支持,需要在provider项目的 dubbo-server.xml种配置如下信息:
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
|
<?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-server"
owner=
"mic"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.254.135:2181"
/>
<dubbo:registry id=
"zk2"
address=
"zookeeper://192.168.254.135:2181"
/>
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<dubbo:protocol port=
"8080"
name=
"hessian"
/>
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
protocol=
"dubbo,hessian"
registry=
"zk1"
/>
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl"
/>
</beans>
|
启动项目后我们会发现zookeeper节点下出现2条注册信息的节点,这样就配置好了多协议服务支持:
hessian%3A%2F%2F192.168.254.1%3A8080%2Fcom.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbo-server%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello%26methods%3DsayHello%26owner%3Dmic%26pid%3D24084%26side%3Dprovider%26timestamp%3D1543201939061, dubbo%3A%2F%2F192.168.254.1%3A20880%2Fcom.gupaoedu.dubbo.IGpHello%3Fanyhost%3Dtrue%26application%3Ddubbo-server%26dubbo%3D2.5.3%26interface%3Dcom.gupaoedu.dubbo.IGpHello%26methods%3DsayHello%26owner%3Dmic%26pid%3D24084%26side%3Dprovider%26timestamp%3D1543201933970
客户端调用也需要相应的配置,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?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-client"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry address=
"zookeeper://192.168.254.135:2181"
/>
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<dubbo:protocol port=
"8080"
name=
"hessian"
/>
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
protocol=
"hessian"
/><!--这里的protocol可以自己指定需要的协议-->
</beans>
|
Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的。
6. 启动检查机制
对于两个dubbo服务需要相互调用,但是在某一个服务未启动,另外的服务启动的时候从注册中心上获取不到该服务的信息就会报错,这里需要配置一下不启动检查机制:
1
2
3
4
|
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
check=
"false"
protocol=
"hessian"
/>
|
这里的 check="false" 就是取消启动检查,但是还是会提示一些服务未注册的错误信息。
7.集群的访问:
实现集群的方式这里也是同样的简单。我们只要发布同一个服务到两个地址,我这边先重新定义一个接口实现,便于辨别:
1
2
3
4
5
6
7
|
public
class
GpHelloImpl2
implements
IGpHello{
@Override
public
String sayHello(String msg) {
return
"Hello,i'm server 2:"
+msg;
}
}
|
然后我这边重新定义两个server.xml文件,这两个配置的server的ID必须要是一致的:dubbo-cluster1.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?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-server"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.11.156:2181"
/>
<dubbo:protocol port=
"20880"
name=
"dubbo"
/>
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
protocol=
"dubbo"
registry=
"zk1"
/>
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl"
/>
</beans>
|
dubbo-cluster2.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?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-server"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry id=
"zk1"
address=
"zookeeper://192.168.254.135:2181"
/>
<dubbo:protocol port=
"20881"
name=
"dubbo"
/>
<dubbo:service
interface
=
"com.gupaoedu.dubbo.IGpHello"
ref=
"gpHelloService"
protocol=
"dubbo"
registry=
"zk1"
/>
<bean id=
"gpHelloService"
class
=
"com.gupaoedu.dubbo.GpHelloImpl2"
/>
</beans>
|
然后新建两个启动类:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
BootstrapCluster1 {
public
static
void
main(String[] args)
throws
IOException {
ClassPathXmlApplicationContext context=
new
ClassPathXmlApplicationContext
(
"META-INF/spring/dubbo-cluster1.xml"
);
context.start();
System.in.read();
//阻塞当前进程
}
}
|
1
2
3
4
5
6
7
8
9
10
11
|
public
class
BootstrapCluster2 {
public
static
void
main(String[] args)
throws
IOException {
ClassPathXmlApplicationContext context=
new
ClassPathXmlApplicationContext
(
"META-INF/spring/dubbo-cluster2.xml"
);
context.start();
System.in.read();
//阻塞当前进程
}
}
|
客户端的xml配置文件修改如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?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-client"
owner=
"wuzz"
/>
<!--注册中心-->
<dubbo:registry address=
"zookeeper://192.168.254.135:2181"
/>
<dubbo:reference id=
"gpHelloService"
interface
=
"com.gupaoedu.dubbo.IGpHello"
protocol=
"dubbo"
/>
</beans>
|
这里实现集群,使用的是默认负载的随机算法,我们使用客户端循环10此去调用该服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
class
App {
public
static
void
main(String[] args)
throws
IOException, InterruptedException {
ClassPathXmlApplicationContext context =
new
ClassPathXmlApplicationContext(
"dubbo-client.xml"
);
for
(
int
i=
0
;i<
10
;i++) {
// 得到IGpHello的远程代理对象
IGpHello iGpHello = (IGpHello) context.getBean(
"gpHelloService"
);
System.out.println(iGpHello.sayHello(
"WUZZ"
));
Thread.sleep(
1000
);
}
System.in.read();
}
}
|
启动后我们会发现控制台大致如下:由于是随机的算法,多次实验下来还是差不多的
1
2
3
4
5
6
7
8
9
10
|
Hello:WUZZ
Hello:WUZZ
Hello:WUZZ
Hello:WUZZ
Hello,i'm server
2
:WUZZ
Hello,i'm server
2
:WUZZ
Hello,i'm server
2
:WUZZ
Hello,i'm server
2
:WUZZ
Hello,i'm server
2
:WUZZ
Hello:WUZZ
|
当然,dubbo作为一个分布式服务治理架构,所具备的功能远远不止这些,了解了dubbo所提供的一些功能,我要进行下一步更加深入的学习啦。下面的学习都基于这个demo