??Apach Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程调用、智能容错和负载均衡、服务自动注册和发现。
- 面向接口代理的高性能RPC调用: 提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节
- 智能负载均衡: 内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量
- 服务自动注册与发现: 支持多种注册中心服务,服务实例上下线实时感知
- 高度可扩展能力: 遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三方实现
- 运行期流量调度: 内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能
- 可视化的服务治理与运维: 提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数
Dubbo 设计架构
??服务发现的一个核心组件是注册中心,Provider 注册地址到注册中心,Consumer 从注册中心读取和订阅 Provider 地址列表。
Dubbo注册中心 Zookeeper
??Dubbo目前支持的注册中心有nacos、zookeeper、multicast、redis、simple,当然官方还是推荐使用zookeeper作为注册中心,所以本文使用zookeeper进行演示。相关的安装教程可以参考 服务注册与发现-Zookeeper(二)
Dubbo 监控中心
Dubbo Admin
??监控中心可以帮助用户通过可视化界面管理和维护众多的服务,可以通过可视化界面很直观的查看各个服务的情况,下载地址:https://github.com/apache/dubbo-admin,目前支持docker快速部署,或者你也可以通过运行源码或手动打包部署,本文演示手动打包部署到Linux系统中。注意:监控中心目前不兼容3.0+版本,本文仅做演示,可能后期会出兼容的版本 ??1. 从github 上下载源码
git clone https://github.com/apache/dubbo-admin.git
??2. 在 \dubbo-admin\dubbo-admin-server\src\main\resources 目录下修改配置文件指定注册中心地址
# 配置zookeeper地址
admin.registry.address=zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
admin.config-center=zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
admin.metadata-report.address=zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
??3. 在dubbo-admin 根目录进行打包
mvn clean package -Dmaven.test.skip=true
??4. 运行,监控中心可以通过源码启动,也可以通过打包后的jar启动 方式1:源码启动 ??监控中心是前后端分离开发的,所以源码启动时需要前后端分开启动
npm install
npm run dev
mvn spring-boot:run
??启动后访问8082端口:http://localhost:8082/,默认用户名和密码都为 root
方式2:打包部署 ??将步骤三打包后的jar包上传到服务器进行启动,打包后的文件已经默认集成了UI
java -jar dubbo-admin-server-0.4.0.jar
??启动后访问8080端口,默认用户名和密码都为 root
Dubbo Monitor Simple
??Dubbo Monitor Simple主要用户监控服务调用,例如进行统计等操作查询。下载地址:https://github.com/apache/dubbo/tree/2.5.x/dubbo-simple,注意是2.5.x分支,其他分支已经没有这个项目了,不知道新版本能不能支持它。 ??1. 将整个dubbo克隆到本地
git clone https://github.com/apache/dubbo.git
git checkout 2.5.x
??2. 在 \dubbo\dubbo-simple\dubbo-monitor-simple 目录下将项目进行打包,打包之前,也可以先进行修改配置:\dubbo\dubbo-simple\dubbo-monitor-simple\src\main\assembly\conf\dubbo.properties
mvn clean package -Dmaven.test.skip=true
??3. 打包完成,在target目录,注意,打包后的文件是dubbo-monitor-simple-2.5.10-assembly.tar.gz 而不是jar,直接运行jar是跑不起来的,接下来就将压缩包进行解压,如果你在上一步没有修改配置,需要在此修改配置,在conf目录下修改dubbo.properties
dubbo.registry.address=zookeeper://192.168.0.132:2181?backup=192.168.0.133:2181,192.168.0.134:2181
dubbo.protocol.port=7070
dubbo.jetty.port=8081
??4. 启动,在bin目录下已经写好的了启动脚本 ??5. 服务配置,需要在服务中配置 dubbo:monitor 节点,具体的参考下一节
<dubbo:monitor protocol="registry"/>
??6. 访问web页面,启动后在浏览器中进行访问:http://localhost:8081/
Dubbo 入门案例
服务提供者
??1. 导入jar包
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>3.0.7</version>
<type>pom</type>
</dependency>
??2. 配置服务提供者,在资源目录下创建 provider.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-provider-demo"/>
<dubbo:registry protocol="zookeeper" address="192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<dubbo:service interface="com.hxz.dubbo.service.IProviderDemoService" ref="prodiverDemoService"/>
<bean id="prodiverDemoService" class="com.hxz.dubbo.service.ProdiverDemoService"/>
<dubbo:monitor protocol="registry"/>
</beans>
??3. 启动,由于使用的是普通maven项目,需要使用上下文进行启动
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
context.start();
System.in.read();
}
??4. 测试服务提供者,在监控中心的控制页面,可以看到服务提供者已经注册到dubbo里面了
服务消费者
??1. 导入jar包
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>3.0.7</version>
<type>pom</type>
</dependency>
??2. 配置服务消费者,在资源目录下创建 consumer.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"
xmlns:context="http://www.springframework.org/schema/context"
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 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hxz.dubbo.service"/>
<dubbo:application name="dubbo-consumer-demo"/>
<dubbo:registry address="zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181"/>
<dubbo:consumer timeout="3000"/>
<dubbo:reference id="providerService" interface="com.hxz.dubbo.service.IProviderDemoService"/>
<dubbo:monitor protocol="registry"/>
</beans>
??3. 测试,消费者去远程调用服务提供者,相关的接口代码请查看Gitee源码
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
context.start();
ConsumerDemoService service = context.getBean(ConsumerDemoService.class);
List<DemoEntity> list = service.list();
list.forEach(System.out::println);
System.in.read();
}
SpringBoot 整合 Dubbo
服务提供者
??1. 导入jar,我是用的是apache的整合包而不是alibaba的整合包,注意两者区别还是挺大的,alibaba的整合包网上的教程还是挺多,但是apache的整合包教程就很少
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>3.0.7</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
??2. 配置dubbo
server:
port: 8001
spring:
application:
name: dubbo-provider-boot-demo
dubbo:
application:
name: ${spring.application.name}
registry:
protocol: zookeeper
address: 192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
register: true
protocol:
name: dubbo
port: 20881
monitor:
protocol: register
??3. 测试demo接口代码
@Service
@DubboService(group = "${spring.application.name}",version = "1.0.0")
public class ProdiverDemoService implements IProviderDemoService {
@Override
public List<DemoEntity> list() {
return Arrays.asList(new DemoEntity(UUID.randomUUID().toString().replace("-", ""), "张三", new Random().nextInt(100)),
new DemoEntity(UUID.randomUUID().toString().replace("-", ""), "李四", new Random().nextInt(100)),
new DemoEntity(UUID.randomUUID().toString().replace("-", ""), "王五", new Random().nextInt(100)));
}
}
??4. 开启dubbo功能并启动测试,使用 @EnableDubbo 注解开启,启动后在web控制中心可以看到注册的服务
@SpringBootApplication
@EnableDubbo
public class DubboProviderBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderBootDemoApplication.class, args);
}
}
服务消费者
??1. 导入jar包
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>3.0.7</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
??2. 配置dubbo
server:
port: 8002
spring:
application:
name: dubbo-consumer-boot-demo
dubbo:
application:
name: ${spring.application.name}
registry:
protocol: zookeeper
address: 192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
register: true
monitor:
protocol: register
??3. 通过 @DubboReference 调用远程,注意:调用远程接口的组和版本如果配置了就要保持一致
@Service
public class ConsumerDemoService implements IConsumerDemoService {
@DubboReference(group = "dubbo-provider-boot-demo",version = "1.0.0")
private IProviderDemoService providerService;
@Override
public List<DemoEntity> list() {
return providerService.list();
}
}
??4. 开启dubbo功能进行测试
@SpringBootApplication
@EnableDubbo
public class DubboConsumerBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DubboConsumerBootDemoApplication.class, args);
}
}
??通过postman调用controller接口,成功获取返回值
Dubbo 高可用
1. 注册中心宕机
??当注册中心宕机后,经过测试发现,还可以消费dubbo暴露的服务;服务提供者和消费者可以通过本地缓存通信,即当消费者调用了一次提供者,会在消费者本地缓存提供者的详细信息,因此注册中心宕机后可以跳过注册中直接调用提供者。除此之外,其他的如监控中心宕机也不影响
- 监控中心宕机不影响使用,只会丢失部分采样数据
- 数据库宕机后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心集群中任意宕机一台,会自动切换到另一台
- 注册中心全部宕机后,服务提供者和消费者可以通过本地缓存通信
- 服务提供者无状态,任意一台宕机后,不影响使用
- 服务提供者全部宕机后,服务消费者将无法使用,并无限次重连等待服务提供者恢复
Dubbo 直连
??Dubbo 直连可以绕过注册中心,即不使用注册中心直接调用dubbo的其他服务,通过 @DubboReference 的 url 属性直接连接服务提供者的通信地址 ??注意:使用dubbo直连时,需要将注册中心相关的配置注释掉,并且不建议在生产环境使用
@Service
public class ConsumerDemoService implements IConsumerDemoService {
@DubboReference(group = "dubbo-provider-boot-demo", version = "1.0.0",url = "127.0.0.1:20881")
private IProviderDemoService providerService;
@Override
public List<DemoEntity> list() {
return providerService.list();
}
}
Dubbo负载均衡
??集群模式下,Dubbo提供了多种负载均衡策略,默认为Random 随机调用。
算法 | 特性 | 备注 |
---|
RandomLoadBalance | 加权随机 | 默认算法,默认权重相同 | RoundRobinLoadBalance | 加权轮询 | 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同 | LeastActiveLoadBalance | 最少活跃优先 + 加权随机 | 背后是能者多劳的思想 | ShortestResponseLoadBalance | 最短响应优先 + 加权随机 | 更加关注响应速度 | ConsistentHashLoadBalance | 一致性 Hash | 确定的入参,确定的提供者,适用于有状态请求 |
Random
- 加权随机,按权重设置随机概率。
- 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
- 缺点:存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
RoundRobin
- 加权轮询,按公约后的权重设置轮询比率,循环调用节点
- 缺点:同样存在慢的提供者累积请求的问题。
LeastActive
- 加权最少活跃调用优先,活跃数越低,越优先调用,相同活跃数的进行加权随机。活跃数指调用前后计数差(针对特定提供者:请求发送数 - 响应返回数),表示特定提供者的任务堆积量,活跃数越低,代表该提供者处理能力越强。
- 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大;相对的,处理能力越强的节点,处理更多的请求。
ShortestResponse
- 加权最短响应优先,在最近一个滑动窗口中,响应时间越短,越优先调用。相同响应时间的进行加权随机。
- 使得响应时间越快的提供者,处理更多的请求。
- 缺点:可能会造成流量过于集中于高性能节点的问题。
ConsistentHash
- 一致性 Hash,相同参数的请求总是发到同一提供者。
- 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
- 算法参见:Consistent Hashing | WIKIPEDIA
- 缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key=“hash.arguments” value=“0,1” />
- 缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key=“hash.nodes” value=“320” />
??从源码中我们可以查到dubbo默认的负载均衡机制是随机(random),Apache 为我们提供了5种机制 示例:服务提供者
@DubboService(group = "${spring.application.name}",version = "1.0.0",loadbalance = "leastactive")
public class ProdiverDemoService implements IProviderDemoService {}
<!-- 暴露的接口服务,ref指向服务的实现 轮询值loadbalance :consistenthash leastactive random roundrobin shortestresponse -->
<dubbo:service interface="com.hxz.dubbo.service.IProviderDemoService" ref="prodiverDemoService" loadbalance="leastactive"/>
示例:服务消费者
@DubboReference(group = "dubbo-provider-boot-demo", version = "1.0.0",loadbalance = "roundrobin")
private IProviderDemoService providerService;
<!-- 声明需要调用的远程服务接口, 生成远程服务的代理 轮询值loadbalance :consistenthash leastactive random roundrobin shortestresponse -->
<dubbo:reference id="providerService" interface="com.hxz.dubbo.service.IProviderDemoService" loadbalance="consistenthash"/>
??关于更多的用法可以参考官方文档:https://dubbo.apache.org/zh/docs/advanced/ ??源码地址:https://gitee.com/peachtec/hxz-study
|