扩展知识
什么是分布式系统
分布式系统原理与泛型中定义:
分布式系统是n多个计算机的集合,这些计算机对用户来说就像单个相关系统
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应用,分布式服务架构以及流动计算架构势在必行,需要一个治理系统确保架构有条不紊的演进。
发展演变

单一应用架构:
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。
垂直应用架构:
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。
此时,用于加速前端页面开发的 Web框架(MVC) 是关键。
分布式服务架构:
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。
此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键。
流动计算架构:
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。
此时,用于 提高机器利用率的资源调度和治理中心(SOA) 是关键。
Dubbo入门
简介
Dubbo 是一款高性能、轻量级的开源Java RPC框架。
Dubbo 是分布式服务治理框架。
提供了三大核心能力:
面向接口的远程方法调用
集群容错(容错与负债均衡)
服务自动注册与发现
官网:http://dubbo.apache.org/
Dubbo能做什么
问题:
服务的URL管理非常困难(rmi://、http:*、)、F5负载均衡器的单点压力(硬件成本)
各个服务之间依赖管理非常复杂
各个服务之间如何进行监控
(1)面向接口的远程方法调用:
就像调用本地方法一样调用远程方法,只需简单 配置,没有任何API侵入。
(2)智能容错与负债均衡:
可在内网替代F5等硬件负鞭均衡器,降低成本,减少单点。
(3)服务自动注册与发现:
不再需要写死服务提供方地址,基于注册中心查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
(4)服务监控:
监控消费者与提供者的累计调用次数和调用时间,提供数据可以分析瓶颈。
Dubbo架构
节点角色说明
服务提供者(Provider):
暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):
调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):
注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
调用关系说明
(1)服务容器负责启动,加载,运行服务提供者。
(2)服务提供者在启动时,向注册中心注册自己提供的服务。
(3)服务消费者在启动时,向注册中心订阅自己所需的服务。
(4)注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
(5)服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
(6)服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
特点
Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
连通性
- 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
- 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
- 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
- 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
- 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
- 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
- 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
- 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
伸缩性
- 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
- 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
升级性
当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。
下图是未来可能的一种架构:

Hello world
环境准备
Dubbo学习前必须掌握以下内容:
Zookeeper的使用经验
Spring框架的使用经验
熟悉使用Maven进行项目构建和依赖管理
熟练使用eclipse或Idea开发工具
环境约束:
Jdk8
Maven3.x
Idea2019
Dubbo 2.7.7
Zookeeper 3.4.11
注册中心选型,我们使用zookeeper当注册中心,需要提前安装好,这里就不演示了。
提出需求
某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址;
我们现在需要创建两个服务模块进行测试:
订单服务模块在A服务器,用户服务模块在B服务器,A可以远程调用B的功能。
order-web(订单模块,web,服务消费者)
user-service(用户模块,service,服务提供者)
工程架构
根据 dubbo《服务化最佳实践》
分包
建议将服务接口,服务模型,服务异常等均放在 API 包中,因为服务模型及异常也是 API 的一部分,同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。
如果需要,也可以考虑在 API 包中放置一份 spring 的引用配置,这样使用方,只需在 spring 加载过程中引用此配置即可,配置建议放在模块的包目录下,以免冲突,如:com/alibaba/china/xxx/dubbo-reference.xml。
粒度
服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持。
服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。
不建议使用过于抽象的通用接口,如:Map query(Map),这样的接口没有明确语义,会给后期维护带来不便。
结构
user模块:
user-api 提供接口
user-impl 接口实现层,服务提供者
order模块:
order-web:服务消费者
服务提供者
user项目总览:
创建user项目,这是一个聚合工程。
创建user-api,这是user公共接口层(提供接口)。
创建user-imp,这是user接口的实现层(服务提供者)。
user-api(提供user公共接口)
(1)用户地址DTO:
1 2 3 4 5 6 7 8 9
| public class UserAddressDto implements Serializable {
private Integer id; private String userId; private String userAddress; private String consignee; private String phone; private String isDefault; }
|
(2)用户地址接口定义
1 2 3
| public interface UserService { List<UserAddressDto> getUserAddress(String userId); }
|
user-impl(接口实现,服务提供者)
(1)pom.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
| <dependencies> <dependency> <groupId>com.oyr</groupId> <artifactId>user-api</artifactId> <version>${parent.version}</version> </dependency>
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>2.7.7</version> </dependency>
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency> </dependencies>
|
(2)实现用户地址接口:
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
| public class UserServiceImpl implements UserService {
public final static Map<String, List<UserAddressDto>> map;
static { List<UserAddressDto> list1 = Stream.of(new UserAddressDto(1, "1", "江西赣州", "欧阳", "152*****", false), new UserAddressDto(2, "1", "广东深圳", "欧阳", "152*****", true), new UserAddressDto(1, "1", "浙江上海", "欧阳", "152*****", false)) .collect(Collectors.toList()); List<UserAddressDto> list2 = Stream.of(new UserAddressDto(3, "2", "江西赣州", "东华", "152*****", false), new UserAddressDto(4, "2", "广东深圳", "东华", "152*****", true), new UserAddressDto(5, "2", "浙江上海", "东华", "152*****", false)) .collect(Collectors.toList());
map = new HashMap<>(); map.put("1", list1); map.put("2", list2); }
@Override public List<UserAddressDto> getUserAddress(String userId) { return map.get(userId); }
}
|
(3)服务提供者配置:
新增provider.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
| <?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="user-provider" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:service interface="com.oyr.user.service.UserService" ref="userServiceImpl" />
<bean id="userServiceImpl" class="com.oyr.user.service.impl.UserServiceImpl" /> </beans>
|
(4)启动服务提供者
1 2 3 4 5 6 7 8 9
| public class Provider {
public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:provider.xml"); System.in.read(); }
}
|
注意:服务提供者不要关闭,服务消费者需要调用服务提供者,如果服务提供者不存在,那么服务消费者会报错。
服务消费者
(1)pom.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
| <dependency> <groupId>com.oyr</groupId> <artifactId>user-api</artifactId> <version>${parent.version}</version> </dependency>
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>2.7.7</version> </dependency>
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency>
|
(2)服务消费者配置
新增consumer.xml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <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="order-consumer" />
<dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" />
<dubbo:reference id="userService" interface="com.oyr.user.service.UserService" />
</beans>
|
(3)启动消费者,尝试调用服务提供者
1 2 3 4 5 6 7 8 9 10 11
| public class Consumer {
public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml"); UserService userService = context.getBean(UserService.class); List<UserAddressDto> result = userService.getUserAddress("1"); result.forEach(System.out::println); }
}
|
在order-web(服务消费者),调用user(服务提供者)的UserService.getUserAddress方法,成功打印出用户地址列表信息,调用成功。
说明服务提供者(order-web)成功消费服务提供者(user),远程调用成功。
注解版
@DubboComponentScan
使用dubbo提供的DubboComponentScan注解,指定扫描的包。
会扫描当前包和子包下的@DubboService & @DubboReference并让其生效。
@DubboService
使用dubbo提供的DubboService注解,指定服务提供者暴露该服务
@DubboReference
使用dubbo提供的DubboReference注解,指定服务消费者引用远程服务
整合Spring Boot
基于hello world项目改造成spring boot项目。
环境准备
环境约束:
Jdk8
Maven3.x
Idea2019
Dubbo 2.7.7
Zookeeper 3.4.11
Spring Boot 2.2.4.RELEASE
服务提供者改造
user-api不改动,改动user-impl,以下改动都是user-impl的。
(1)pom.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 27 28 29 30 31 32 33 34 35 36 37 38 39
| <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.4.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<dependencies> <dependency> <groupId>com.oyr</groupId> <artifactId>user-api</artifactId> <version>${parent.version}</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.7</version> </dependency>
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency> </dependencies>
|
(2)修改接口实现UserServiceImpl (类上加入DubboService)
1 2 3
| @DubboService public class UserServiceImpl implements UserService { }
|
(3)application.properties新增配置文件
1 2 3 4 5 6
| dubbo.application.name=user-provider dubbo.registry.protocol=zookeeper dubbo.registry.address=127.0.0.1:2181 dubbo.protocol.name=dubbo dubbo.protocol.port=20888
|
(4)修改启动类,并且启动服务提供者
1 2 3 4 5 6 7 8 9 10
| @EnableDubbo @SpringBootApplication public class Provider {
public static void main(String[] args) { SpringApplication.run(Provider.class, args); }
}
|
修改后,启动成功!!!
服务消费者改造
改动order-web(服务消费者)
(1)pom.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 27 28 29 30 31 32 33 34 35 36 37 38
| <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.4.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<dependencies> <dependency> <groupId>com.oyr</groupId> <artifactId>user-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.7</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency> </dependencies>
|
(2)新增controller
1 2 3 4 5 6 7 8 9 10 11 12 13
| @RestController public class DubboController {
@DubboReference private UserService userService;
@GetMapping("/dubbo") public void dubbo() { List<UserAddressDto> result = userService.getUserAddress("1"); result.forEach(System.out::println); }
}
|
(3)application.properties新增配置文件
1 2 3 4 5 6 7
| dubbo.application.name=cms-wms dubbo.registry.protocol=zookeeper dubbo.registry.address=127.0.0.1:2181 dubbo.protocol.name=dubbo dubbo.consumer.client=netty dubbo.consumer.check=false
|
(4)修改启动类
1 2 3 4 5 6 7 8 9
| @EnableDubbo @SpringBootApplication public class Consumer {
public static void main(String[] args) { SpringApplication.run(Consumer.class, args); }
}
|
(5)测试,尝试远程调用是否成功
访问http://localhost:8080/dubbo
后台成功打印出客户地址列表
远程调用成功!!!!
配置解释
@EnableDubbo(组合型注解)
开启dubbo,扫描dubbo注解。
里面有dubbo提供的DubboComponentScan注解,指定扫描的包。
会扫描当前包和子包下的@DubboService & @DubboReference并让其生效。
@DubboService
使用dubbo提供的DubboService注解,指定服务提供者暴露该服务
@DubboReference
使用dubbo提供的DubboReference注解,指定服务消费者引用远程服务
服务提供者配置:
1 2 3 4 5 6
| dubbo.application.name=user-provider dubbo.registry.protocol=zookeeper dubbo.registry.address=127.0.0.1:2181 dubbo.protocol.name=dubbo dubbo.protocol.port=20888
|
服务消费者配置:
1 2 3 4 5
| dubbo.application.name=order-consumer dubbo.registry.protocol=zookeeper dubbo.registry.address=127.0.0.1:2181 dubbo.protocol.name=dubbo
|
配置解释:
dubbo.application.nam:就是服务名,不能和其他服务提供者重复
dubbo.registry.protocol:指定注册中心协议
dubbo.registry.address:指定注册中心访问地址(地址加端口号)
dubbo.protocol.name:指定使用协议,默认是dubbo
dubbo.protocol.port:指定服务提供者暴露的端口
Dubbo 配置详解
注意:以下针对xml配置讲解,注解版差不多一致。
重试次数
失败自动重试:
当出现失败,重试其他服务提供者服务器,重试会带来更长的延迟,可通过’retries=2’来设置重试次数(不含第一次),’retries=-1’表示不进行重试。
服务提供者
1 2 3 4 5 6 7 8 9 10
| <dubbo:provider retries="2" />
<dubbo:service retries="2" />
<dubbo:service interface="com.oyr.user.service.UserService" ref="userServiceImpl" > <dubbo:method name="getUserAddress" retries="2" /> </dubbo:service>
|
服务消费者
1 2 3 4 5
| <dubbo:consumer retries="2" />
<dubbo:reference id="userService" interface="com.oyr.user.service.UserService" retries="2"/>
|
超时时间
由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间。
服务提供者
1 2 3 4 5 6 7
| <dubbo:provider timeout="5000" />
<dubbo:service interface="com.oyr.user.service.UserService" ref="userServiceImpl" timeout="5000" > <dubbo:method name="getUserAddress" timeout="10000" /> </dubbo:service>
|
服务消费者
1 2 3 4 5 6 7
| <dubbo:consumer timeout="3000"/>
<dubbo:reference id="userService" interface="com.oyr.user.service.UserService" timeout="5000"> <dubbo:method name="getUserAddress" timeout="10000"/> </dubbo:reference>
|
版本号
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
在低压力时间段,先升级一半提供者为新版本
再将所有消费者升级为新版本
然后将剩下的一半提供者升级为新版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 老版本服务提供者配置: <dubbo:service interface="com.foo.BarService" version="1.0.0" />
新版本服务提供者配置: <dubbo:service interface="com.foo.BarService" version="2.0.0" />
老版本服务消费者配置: <dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
新版本服务消费者配置: <dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />
如果不需要区分版本,可以按照以下的方式配置: <dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
|
配置原则
Dubbo推荐在Provider上尽量多配置Consumer端属性。
1)作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
2)在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的
属性配置优先级

1)方法级配置别优于接口级别,接口级别优于全局配置,即小Scope优先
2)Consumer端配置优于 Provider配置
3)最后是Dubbo Hard Code的配置值(见配置文档)
配置文件优先级

1)JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
2)XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。
3)Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。
Dubbo-Admin监控中心
监控中心简介
监控中心:
图形化的访问管理页面,安装时需要指定注册中心的地址,即可从注册中心中获取到所以的提供者和消费者进行配置管理,并且可以监控与分析提供者与消费者中的远程调用。
监控中心:
是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控测试程序,不过这个监控即使不装也不影响使用。
搭建监控中心
注意:dubbo-admin有多种启动方式
通过jar包方式启动,jar包形式。
通过war包方式启动,依赖tomcat容器。
通过导入eclipse或idea启动
最新的dubbo-admin是前后端分离的(新版本),可以看教程:
https://blog.csdn.net/muriyue6/article/details/109304584
注意:当前讲解的是前后端不分离的dubbo-admin搭建方式(老版本)
下载dubbo-admin项目:https://github.com/apache/incubator-dubbo-ops

war包启动
1)先准备好dubbo-admin项目
2)准备好tomcat,将dubbo-admin放到webapps目录下
3)修改dubbo.properties文件内容
1 2 3 4 5 6
| dubbo.registry.address=zookeeper://120.25.217.122:2181
dubbo.admin.root.password=root123
dubbo.admin.guest.password=guest123
|
4)启动tomcat测试,尝试访问监控中心
在tomcat下,bin目录,通过startup.bat启动tomcat。
访问http://localhost:8080/dubbo-admin

注意:登录时遇到需要密码来登录,密码设置在dubbo.properties文件中设置。

最后成功进入监控中心界面!!!
jar包启动
1)先准备好dubbo-admin项目
2)修改application.properties配置
1 2 3 4 5 6
| dubbo.registry.address=zookeeper://120.25.217.122:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
|
3)打包dubbo-admin
mvn clean package -Dmaven.test.skip=true
4)运行dubbo-admin.jar,尝试访问监控中心
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
使用root/root登录

通讯协议
Dubbo支持哪些协议
Dubbo协议
Dubbo协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。Dubbo缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
Dubbo默认使用Dubbo协议;
基于Dubbo的远程调用协议:
连接个数:单连接
连接方式:长连接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用
Hessian协议
Hessian协议用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务,Dubbo缺省内嵌Jetty作为服务器实现。
Hessian是Caucho开源的一个RPC框架:http://hessian.caucho.com,其通讯效率高于WebService和Java自带的序列化。
基于Hessian的远程调用协议:
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件。
适用场景:页面传输,文件传输,或与原生hessian服务互操作
RMI协议
Java标准的远程调用协议,采用JDK标准的java.rmi.*实现,阻塞式短连接和JDK标准序列化方式
基于RMI协议的远程调用协议:
连接个数:多连接
连接方式:短连接
传输协议:TCP
传输方式:同步传输
序列化:Java标准二进制序列化
适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。
适用场景:常规远程服务方法调用,与原生RMI服务互操作
HTTP协议
此协议采用 spring 的HttpInvoker的功能实现,
基于HTTP的远程调用协议:
连接个数:多连接
连接方式:长连接
连接协议:http
传输方式:同步传输
序列化:表单序列化(JSON)
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
多协议
Dubbo 允许配置多协议,在不同服务上支持不同协议 或者 同一服务上同时支持多种协议。
不同服务上不同协议
不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议;
1 2 3 4 5 6 7 8 9 10 11 12
| <dubbo:application name="world" /> <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
<dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="rmi" port="1099" />
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" />
|
同一服务上不同协议
同一服务上同时支持多种协议;
1 2 3 4 5 6 7 8 9
| <dubbo:application name="world" /> <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
<dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="hessian" port="8080" />
<dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
|
序列化
Dubbo支持哪些序列化

Dubbo 支持 Hession,Dubbo,Json、Java 多种序列化方式。但是 Hessian 是其默认的序列化方式。
Hessian 的数据结构
Hessian 的对象序列化机制有 8 种原始类型:
- 原始二进制数据
- boolean
- 64-bit date(64 位毫秒值的日期)
- 64-bit double
- 32-bit int
- 64-bit long
- null
- UTF-8 编码的 string
另外还包括 3 种递归类型:
- list for lists and arrays
- map for maps and dictionaries
- object for objects
还有一种特殊的类型:
通讯框架
Dubbo支持哪些通讯框架

Dubbo 支持 Netty、Mina、Grizzly 多种通讯框架,Dubbo推荐并默认使用 Netty。
注册中心
Dubbo支持哪些注册中心

Zookeeper、Redis、Multicast、Simple 都可以作为Dubbo的注册中心,Dubbo官方推荐使用 Zookeeper。
多注册中心
Dubbo 支持同一服务向多注册中心同时注册,或者不同服务分别注册到不同的注册中心上去,甚至可以同时引用注册在不同注册中心上的同名服务。
另外,注册中心是支持自定义扩展的。
多注册中心注册
案例:中文站有些服务来不及在青岛部署,只在杭州部署,而青岛的其它应用需要引用此服务,就可以将服务同时注册到两个注册中心。
1 2 3 4 5 6 7 8
| <dubbo:application name="world" />
<dubbo:registry id="hangzhouRegistry" address="10.20.141.150:9090" /> <dubbo:registry id="qingdaoRegistry" address="10.20.141.151:9010" default="false" />
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="hangzhouRegistry,qingdaoRegistry" />
|
不同服务使用不同注册中心
CRM 有些服务是专门为国际站设计的,有些服务是专门为中文站设计的。
1 2 3 4 5 6 7 8 9 10
| <dubbo:application name="world" />
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" /> <dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" />
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />
|
多注册中心引用
案例:CRM 需同时调用中文站和国际站的 PC2 服务,PC2 在中文站和国际站均有部署,接口及版本号都一样,但连的数据库不一样。
1 2 3 4 5 6 7 8 9 10
| <dubbo:application name="world" />
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" /> <dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />
<dubbo:reference id="intlHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="intlRegistry" />
|
如果只是测试环境临时需要连接两个不同注册中心,使用竖号分隔多个不同注册中心地址:
1 2 3 4 5 6
| <dubbo:application name="world" />
<dubbo:registry address="10.20.141.150:9090|10.20.154.177:9010" />
<dubbo:reference id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" />
|
注册中心宕机与Dubbo直连
注册中心宕机问题
在实际生产中,假如zookeeper注册中心宕掉,一段时间内服务消费方还是能够调用提供方的服务的,实际上它使用的本地缓存进行通讯,这只是dubbo健壮性的一种。
健壮性
监控中心宕掉不影响使用,只是丢失部分采样数据
数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
注册中心对等集群,任意一台宕掉后,将自动切换到另一台
注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
服务提供者无状态,任意一台宕掉后,不影响使用
服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
直连模式
注册中心的作用在于保存服务提供者的位置信息,我们可以完全可以绕过注册中心——采用dubbo直连,即在服务消费方配置服务提供方的位置信息。
点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。
xml配置方式:
1 2
| <dubbo:reference id="userService" interface="com.zang.gmall.service.UserService" url="dubbo://localhost:20880" />
|
注解方式:
1 2
| @Reference(url = "127.0.0.1:20880") UserService userService;
|