📖 Dubbo 学习教程
📑 Dubbo 基础知识
⭐ 1.1 分布式基础理论
什么是分布式系统?
《分布式系统原理与泛型》定义:
1️⃣ “分布式系统是若干个独立的计算机的集合,这些计算机对于用户来说就像单个相关系统”
2️⃣ 分布式系统(distributed system) 是建立在网络之上的软件系统。
为什么需要分布式系统?
随着互联网的飞速发展,网站应用规模的不断扩大,常规的垂直应用已经无法应对分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
⭐ 1.3 RPC
什么是 RPC ?
RPC 【Remote Procedure Call】是指的远程过程调用,是一种进程间通信方式,它是一种技术的思想,而不是规范,它允许程序调用另一个地址空间(通常是共享网络上的另一台机器上)的过程或者函数,而不用程序猿显示编码这个远程调用的调节。即程序猿无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
⭐1.4 dubbo - admin 控制台
链接:https://pan.baidu.com/s/1XWuselAC6iYcf-LcUeHb6w?pwd=HHXF
提取码:HHXF
–来自百度网盘超级会员V4的分享代码资料 dubbo - admin 的源码在其中哦~
1️⃣ 下载并解压安装对应的 学习环境
我们需要下载一个名为 incubator-dubbo-ops-master.zip
的代码压缩包并且进行解压到你对应的 dubbo 学习测试目录之下
2️⃣ 修改 dubbo-admin 中的 zookeeper 服务注册中心机器配置
resources/application.properties
dubbo.registry.address=zookeeper://192.168.56.103:2181
3️⃣ 打包 当前 dubbo - admin 为 可运行的 jar 文件 并启动
# 需要进入到 dubbo-admin 的资源目录下
mvn clean package
4️⃣ 通过命令行启动对应的 dubbo-admin.jar
http://localhost:7001/
默认用户名称:root
默认用户密码:root
📚 大功告成~
⭐ 1.5 dubbo-helloworld
提出需求
某个 电商系统 ,订单服务需要调用用户服务获取某个用户的所有地址;
我们现在 需要创建两个服务模块进行测试
模块 | 功能 |
---|---|
订单服务 web 模块 | 创建订单等 |
用户服务 service 模块 | 查询用户地址等 |
测试预期结果:
订单服务 web 模块在 A 服务器,用户服务模块在 B 服务器,A 可以远程调用 B 功能
工程架构
创建模块
1️⃣ user-service-provider
2️⃣ user-service-consumer
3️⃣ gmall-interface
使用 dubbo 改造
1️⃣ 导入对应的 dubbo(2.6.2) 所需要的相关依赖 以及操作ZooKeeper的客户端的(curator)
<?xml version="1.0" encoding="UTF-8"?>
<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.alascanfu</groupId>
<artifactId>user-service-consumer</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.alascanfu</groupId>
<artifactId>gmall-interface</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 导入 Dubbo 相关依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!-- 注册中心使用的是 ZooKeeper ,引入操作 ZooKeeper 的客户端 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
</project>
2️⃣ 配置服务提供者的配置文件
resources/provider.xml
-
1️⃣ 导入 dubbo 对应的命名空间配置
<?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 ">
-
2️⃣ 指定当前 服务 / 应用的名字(同样的服务名称相同,不要和别的服务同名)
<!-- 指定当前服务/应用的名字(同样的服务名称相同, 不要和别的服务同名) --> <dubbo:application name="user-service-provider"></dubbo:application>
-
3️⃣ 指定配置中心的位置
<!-- 指定注册中心的位置 --> <!-- <dubbo:registry address="zookeeper://192.168.56.103:2181"></dubbo:registry> --> <dubbo:registry protocol="zookeeper" address="192.168.56.103:2181"></dubbo:registry>
-
4️⃣ 指定通信协议 以及 对应的通信端口
<!-- 指定通信协议 以及 通信端口 --> <dubbo:protocol name="dubbo" port="20080" ></dubbo:protocol>
-
5️⃣ 服务暴露 ref 是用来引用具体的服务实现类
<!-- 服务暴露 ref 是来指向服务的真正的实现对象 --> <dubbo:service interface="com.alascanfu.gmall.service.UserService" ref="userServiceImpl"></dubbo:service> <!-- 服务的具体实现类 --> <bean class="com.alascanfu.gmall.service.impl.UserServiceImpl" id="userServiceImpl"></bean>
3️⃣ 创建应用 主 启动类 启动我们的对应配置文件
com.alascanfu.MainApplication
/***
* @author: Alascanfu
* @date : Created in 2022/7/17 11:49
* @description: 程序应用的 主启动类
* @modified By: Alascanfu
**/
public class MainApplication {
public static void main(String[] args) throws IOException {
// 读取配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
// 启动当前 IOC 容器
context.start();
// 读取字符 阻塞 等待结束
System.in.read();
}
}
4️⃣ 启动主程序之后打开我们的 Dubbo-admin 控制台 进行对应的查看 服务是否注册成功
http://localhost:7001/
5️⃣ 配置 consumer 中的 dubbo 相关配置
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:context="http://www.springframework.org/schema/context"
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://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<!-- 配置当前消费服务名称 -->
<dubbo:application name="order-service-consumer"></dubbo:application>
<!--配置当前服务注册中心位置-->
<dubbo:registry protocol="zookeeper" address="192.168.56.103:2181" ></dubbo:registry>
<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService" interface="com.alascanfu.gmall.service.UserService"></dubbo:reference>
</beans>
6️⃣ 将我们刚才需要远程调用的服务接口 进行注入到我们 IOC 容器当中 并在 Impl 实现类中自动注入 该对应的实例对象 并且进行调用 通过注解方式
-
配置对应的 consumer 中的对应的扫描自动注入注解的包路径
<context:component-scan base-package="com.alascanfu.gmall.service.impl"></context:component-scan>
-
修改 OrderServiceImpl的具体实现类
@Service public class OrderServiceImpl implements OrderService { @Autowired UserService userService ; @Override public void initOrder(String userId) { List<UserAddress> userAddressList = userService.getUserAddressList(userId); System.out.println(userAddressList); } }
7️⃣ 编写对应 consumer 的主启动类 并且加载对应的 consumer.xml 的配置文件 进行对应的测试
/***
* @author: Alascanfu
* @date : Created in 2022/7/17 12:43
* @description: MainApplication Consumer 的主启动类 MainApplication
* @modified By: Alascanfu
**/
public class MainApplication {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
OrderService orderService = context.getBean(OrderService.class);
orderService.initOrder("1");
System.in.read();
}
}
8️⃣ 启动 consumer 的主应用启动程序 查看控制台是否有对应数据的输出
📚 远程服务调用成功~
⭐ 1.6 监控中心配置
1️⃣ 首先先将我们下载好的对应 dubbo - monitor 进行解压到本地
2️⃣ 将对应的 dubbo-monitor 的文件配置进行对应的修改
dubbo.registry.address=zookeeper://192.168.56.103:2181
3️⃣ 然后通过 Maven 工具进行对应的 打包 mvn clean package -Dmaven.test.skip=true
4️⃣ 找到打包好后的文件夹中的 dubbo-monitor-simple-2.0.0-assembly.tar.gz
进行解压到当前目录
5️⃣ 将解压后的文件目录 放入到对应的学习目录下 进入对应的目录之中找到 bin 目录并且启动 start.bat 程序 即可。
6️⃣ 通过浏览器查看监控中心
http://localhost:8080/
7️⃣ 进行文件配置当前 dubbo 的监控中心
<!-- 标注当前 dubbo 的监控中心是从注册中心中去发现 -->
<dubbo:monitor protocol="registry"></dubbo:monitor>
<!-- <dubbo:monitor address="192.168.137.1:7070"></dubbo:monitor>-->
8️⃣ 随后重启我们的 dubbo-consumer 然后观察 Dubbo 监控中心面板数据
⭐ 1.7 使用 SpringBoot 整合 Dubbo
1️⃣ 导入对应的 dubbo - starter 依赖整合对应的 SpringBoot
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
2️⃣ 编写 dubbo 对应的配置 于 application.yaml中进行添加
dubbo:
application:
name: user-service-provider
registry:
protocol: zookeeper
address: 192.168.56.103:2181
protocol:
name: dubbo
port: 20080
monitor:
protocol: registry
3️⃣ 通过注解标注哪些 接口 会被作为远程调用服务
/***
* @author: Alascanfu
* @date : Created in 2022/7/16 23:54
* @description: UserServiceImpl
* @modified By: Alascanfu
**/
@Service
@com.alibaba.dubbo.config.annotation.Service // 暴露当前类的服务
public class UserServiceImpl implements UserService {
/**
* 模拟数据库 返回用户数据
* */
@Override
public List<UserAddress> getUserAddressList(String userId) {
UserAddress userAddress1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
UserAddress userAddress2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "2", "王老师", "010-56789225", "Y");
return Arrays.asList(userAddress1 , userAddress2);
}
}
📚 注意点:值得注意的是 需要在SpringBootApplication主运行类上标注 @EnableDubbo 开启基于注解的 Dubbo 功能
4️⃣ 启动 SpringBoot 的应用程序查看 dubbo-admin 中的服务提供者数是否对应增加
5️⃣ 进行配置 boot-order-service-consumer 并且在需要远程调用引用的服务上设置对应的注解 @Reference ,添加完成之后需要回到我们的 SpringBoot Application 的主启动类中添加对应的注解 @EnableDubbo
dubbo:
application:
name: order-service-consumer
registry:
protocol: zookeeper
address: 192.168.56.103:2181
monitor:
protocol: registry
# 防止端口冲突
server:
port: 8081
📚 启动对应的应用主程序
http://localhost:8081/initOrder?uid=1
📚 小结
@Reference 是远程引用对应的服务
@Service 是暴露当前服务到注册中心
📑 Dubbo 配置
⭐ 2.1 启动检查
启动检查调用
❓ 所遇到的问题,当我们注册服务期间并没有开启我们的 provider 时 直接进行远程调用consumer 就会发生报错信息,Faild to check …
在对应的声明引用时
<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService"
check="false"
interface="com.alascanfu.gmall.service.UserService"></dubbo:reference>
📚 当然我们也可以使用 dubbo:consumer 来配置当前消费者的统一规则
<dubbo:consumer check="false"></dubbo:consumer>
关闭注册中心启动时检查(注册订阅失败时报错)
<dubbo:registry check="false"/>
⭐ 2.2 超时 & 配置覆盖
dubbo:consumer
其中一个属性为 => timeout 默认的值为 1000 ms
<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService"
check="false"
timeout="3000"
interface="com.alascanfu.gmall.service.UserService"></dubbo:reference>
📚 当然也可以配置引用远程调用服务的指定方法的超时时间
<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService"
check="false"
timeout="3000"
interface="com.alascanfu.gmall.service.UserService">
<dubbo:method name="getUserAddressList" timeout="5000"></dubbo:method>
</dubbo:reference>
配置生效优先覆盖
1️⃣ 精确优先配置——方法级优先,接口级次之,全局配置再次之
2️⃣ 消费者设置优先 —— 如果级别一样,则消费方优先,提供方次之
⭐ 2.3 重试次数
retries=‘3’
重试次数,不包含第一次调用
幂等(设置重试次数)——方法不管用多少次都是同样结果【查询、删除、修改】
非幂等(不能设置重试次数)【新增】
⭐ 2.4 多版本 —— 灰度发布
有点像版本的灰度发布
1️⃣ 当一个接口实现,出现不兼容升级时,可以用版本号国都,版本号不同的服务相互间不引用。
2️⃣ 可以按照以下的步骤进行版本迁移:
- 在低压力时间段,先升级一半提供者为新版本
- 再将所有消费者升级为新版本
- 然后将剩下的一半提供者升级为新版本
老版本服务提供者配置
<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="*" />
⭐ 2.5 本地存根
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService"
check="false"
timeout="3000"
stub="com.alascanfu.gmall.service.impl.UserServiceStub"
interface="com.alascanfu.gmall.service.UserService">
<dubbo:method name="getUserAddressList" timeout="5000"></dubbo:method>
</dubbo:reference>
代码
/***
* @author: Alascanfu
* @date : Created in 2022/7/17 23:03
* @description: UserServiceStub
* @modified By: Alascanfu
**/
public class UserServiceStub implements UserService {
private final UserService userService ;
public UserServiceStub(UserService userService) {
this.userService = userService;
}
@Override
public List<UserAddress> getUserAddressList(String userId) {
if (!StringUtils.isBlank(userId)){
return userService.getUserAddressList(userId);
}
return null;
}
}
⭐ 2.6 SpringBoot整合的三种方式
当SpringBoot 整合需要进行详细配置时——方法的使用
1️⃣ 导入 dubbo - starter ,在 application.properties 配置属性,使用 @Service
【暴露服务】,使用@Reference
【发现服务】,并且需要在主启动类上标注 @EnableDubbo
2️⃣ 保留 dubbo.xml 配置文件 然后在 主启动类上标注 @ImportResource(locations="classpath:xxx.xml")
3️⃣ 注解配置 | Apache Dubbo 使用注解 API 手动创建加入到对应的IOC容器中
📑 Dubbo 高可用
⭐ 3.1 ZooKeeper 宕机 与 Dubbo 直连 —— 面试题
❓ 问题现象 => ZooKeeper 注册中心宕机,还可以消费 dubbo 暴露的服务
🌰 原因
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据。
- 数据库宕机后,注册中心仍然能通过缓存提供服务列表查询,但不能注册新的服务
- 注册中心对等集群,任意一台宕机后,将自动切换到另一台。
- 注册中心全部宕机后,服务提供者与服务消费者仍能通过本地缓存通讯
- 服务提供无状态,任意一台宕机后,不影响使用。
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复。
📚 高可用通过设计,减少系统不能提供服务的时间。
小结:通常会使用 @Reference(url='xxx.xxx.xxx.xxx:xxxxx')
进行直连
⭐ 3.2 集群下 Dubbo 负载均衡配置
在集群负载均衡时,Dubbo 提供了多种的均衡策略,默认方式为 random 随机调用
🌰 负载均衡策略
1️⃣ Random LoadBalance
- 随机,按照权重设置随机概率。
- 在一个戴面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后比较均匀,有利于动态调整提供者的权重。
2️⃣ RoundRobin LoadBalance
- 轮询,按照公约后的权重设置轮询比率。
- 存在慢的提供者累积请求的问题,比如,第二台机器很慢,但是没挂,当请求调到第二台时就卡住了,久而久之,所有请求都卡在调到第二台上了.
3️⃣ LeastActive LoadBalance
- 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- 使慢的提供者收到更少的请求,因为越慢的提供者调用前后计数差会更大。
4️⃣ ConsistentHash LoadBalance
- 一致性 Hash ,相同参数的请求总是发到同一提供者。
- 当某一台提供者挂掉后,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动。
- 默认的话只会对第一个参数进行 Hash 计算,可以通过修改
<dubbo:parameter key="hash.arguments" value="0,1" />
- 默认用 160 个虚拟节点进行 hash 分配
修改与配置
⭐ 3.3 服务降级
什么是服务降级?
1️⃣ 当服务器压力剧增的情况下,根据实际业务情况以及流量,对一些服务和页面有策略的不处理或换成简单的方式处理,从而释放掉服务器资源以保证核心交易正常运行或者高效运作。
- 这里可以通过服务降级功能临时屏蔽某个出错的非关键服务,并且定义降级后的返回策略。
- 向注册中心写入动态覆盖规则。
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
其中:
mock=force:return+null
表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。- 还可以改为
mock=fail:return+null
表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
⭐ 3.4 集群服务容错 & 整合 hystrix
集群调用失败时,Dubbo 提供的容错方案
在集群调用失败时,Dubbo 提供了多种容错方案,默认为 failover 重试。
各节点关系:
- 这里的
Invoker
是Provider
的一个可调用Service
的抽象,Invoker
封装了Provider
地址及Service
接口信息 Directory
代表多个Invoker
,可以把它看成List<Invoker>
,但与List
不同的是,它的值可能是动态变化的,比如注册中心推送变更Cluster
将Directory
中的多个Invoker
伪装成一个Invoker
,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个Router
负责从多个Invoker
中按路由规则选出子集,比如读写分离,应用隔离等LoadBalance
负责从多个Invoker
中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选
集群容错策略
1️⃣ Failover Cluster
- 失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过
retries="2"
来设置重试次数(不含第一次)。
2️⃣ Failfast Cluster
- 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
3️⃣ Failsafe Cluster
- 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
4️⃣ Failback Cluster
- 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
5️⃣ Forking Cluster
- 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过
forks="2"
来设置最大并行数。
6️⃣ Broadcast Cluster
-
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
📚 现在广播调用中,可以通过 broadcast.fail.percent 配置节点调用失败的比例,当达到这个比例后,BroadcastClusterInvoker 将不再调用其他节点,直接抛出异常。 broadcast.fail.percent 取值在 0~100 范围内。默认情况下当全部调用失败后,才会抛出异常。 broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点,并不改变结果(任意一台报错则报错)。broadcast.fail.percent 参数 在 dubbo2.7.10 及以上版本生效。
Broadcast Cluster 配置 broadcast.fail.percent。
broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点。
整合 hystrix
Hystrix 旨在通过控制那些远程系统、服务和第三方库的节点,从而对延迟和故障提供了更为强大的容错能力,Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。
步骤一:配置 Spring-cloud-starter-netflix-hystrix
Springboot 官方提供了对 Hystrix 的集成,只需要导入对应的pom.xml 文件中导入即可。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
步骤二:使用注解 @EnableHystrix 标注在主启动类上使得当前应用支持 服务容错
@EnableDubbo
@EnableHystrix // 开启服务容错
@SpringBootApplication
public class UserInfoproviderApplication {
public static void main(String[] args) {
SpringApplication.run(UserInfoproviderApplication.class, args);
}
}
步骤三:在可能会出现服务提供出错情况的接口上标注好 @HystrixCommand 注解
/***
* @author: Alascanfu
* @date : Created in 2022/7/19 20:23
* @description: service.impl.UserServiceImpl
* @modified By: Alascanfu
**/
@Component
@Service
public class UserServiceImpl implements UserService {
@HystrixCommand
@Override
public List<UserAddress> getUserAddress(int uid) {
System.out.println("当前用户访问 ID : " + uid);
UserAddress userAddress = new UserAddress("四川", "资阳",
"雁江", "娇子大道-皇龙路-优品上城B3一单元1801");
return Arrays.asList(userAddress);
}
}
步骤四:出现错误时 即 远程调用的情况下,在调用方也导入对应的 Hystrix 依赖,同时在主程序上标注好对应的 @EnableHystrix 注解开启服务容错,之后在调用的时候 @HystrixCommand(fallbackMethod=“方法”) => 对应方法进行容错处理调用的回调函数
/***
* @author: Alascanfu
* @date : Created in 2022/7/19 20:23
* @description: service.impl.UserServiceImpl
* @modified By: Alascanfu
**/
@Component
@Service
public class UserServiceImpl implements UserService {
@HystrixCommand(fallbackMethod = "getUserAddressErrorFallBackMethod")
@Override
public List<UserAddress> getUserAddress(int uid) {
System.out.println("当前用户访问 ID : " + uid);
UserAddress userAddress = new UserAddress("四川", "资阳",
"雁江", "娇子大道-皇龙路-优品上城B3一单元1801");
return Arrays.asList(userAddress);
}
public List<UserAddress> getUserAddressErrorFallBackMethod(int uid) {
System.out.println("当前用户访问 ID : " + uid);
UserAddress userAddress = new UserAddress("未知", "未知",
"未知", "未知-default-detailsPosition");
return Arrays.asList(userAddress);
}
}
📑 Dubbo 原理
⭐ 4.1 RPC 原理
一次完整的 RPC 调用流程(同步调用,异步另说)如下:
1️⃣ 服务消费方(Client) 调用以本地调用方式调用服务;
2️⃣ client stub 接收到调用后服务将方法、参数等组装成能够进行网络通信的消费体。
3️⃣ client stub 找到服务地址,并将消息发送到服务端
4️⃣ server stub 收到消息之后会进行解码;
5️⃣ server stub 根据解码结果调用本地的服务;
6️⃣ 本地服务执行并将结果打包成消息并且发送至消费方;
7️⃣ server stub 将返回结果打包成消息并发送给消费方
8️⃣ client stub 接收消息,并进行解码
9️⃣ 服务消费方得到最终结果。
⭐ 4.2 netty 通信原理
BIO(Blocking IO)
NIO(Non-Blocking IO)
**Selector 一般称之为选择器,也可以被称之为 多路复用器 **
- Connect(连接就绪)
- Accept(接受就绪)
- Read(读就绪)
- Write(写就绪)
Netty 原理
⭐ dubbo 原理 —— 框架设计
图例说明:
- 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。
- 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。
- 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。
- 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。
各个层次之间的说明
- config 配置层:对外配置接口,以
ServiceConfig
,ReferenceConfig
为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类 - proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以
ServiceProxy
为中心,扩展接口为ProxyFactory
- registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为
RegistryFactory
,Registry
,RegistryService
- cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以
Invoker
为中心,扩展接口为Cluster
,Directory
,Router
,LoadBalance
- monitor 监控层:RPC 调用次数和调用时间监控,以
Statistics
为中心,扩展接口为MonitorFactory
,Monitor
,MonitorService
- protocol 远程调用层:封装 RPC 调用,以
Invocation
,Result
为中心,扩展接口为Protocol
,Invoker
,Exporter
- exchange 信息交换层:封装请求响应模式,同步转异步,以
Request
,Response
为中心,扩展接口为Exchanger
,ExchangeChannel
,ExchangeClient
,ExchangeServer
- transport 网络传输层:抽象 mina 和 netty 为统一接口,以
Message
为中心,扩展接口为Channel
,Transporter
,Client
,Server
,Codec
- serialize 数据序列化层:可复用的一些工具,扩展接口为
Serialization
,ObjectInput
,ObjectOutput
,ThreadPool
⭐ dubbo 原理 —— 启动解析、加载配置信息
⭐ dubbo 原理 —— 服务暴露
⭐ dubbo 原理 —— 服务引用
⭐ dubbo 原理 —— 服务调用
📑 新版 Dubbo-Admin 使用
【参考资料】: 2021最新版Dubbo-admin+Zookeeper安装教程