简易Dubbo核心源码剖析(架构流程 环境搭建 springboot集成整合 高阶配置运用)
Dubbo核心源码剖析
1. Dubbo架构体系
1.1 框架介绍
1.1.1 概述
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
1.1.2 运行架构
节点角色说明
节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
关于dubbo 的特点分别有连通性、健壮性、伸缩性、以及向未来架构的升级性。特点的详细介绍也可
以参考官方文档
1.1.3 整体设计
图例说明
- 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于 中轴线上的为双方都用到的接口。
- 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可 以剥离上层被复用,其中,Service和Confifig 层为 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
1.2 环境搭建
接下来逐步对dubbo各个模块的源码以及原理进行解析,目前dubbo框架已经交由Apache基金会进行孵化,被在github开源。
Dubbo 社区目前主力维护的有 2.6.x 和 2.7.x 两大版本,其中,
- 2.6.x 主要以 bugfix 和少量 enhancements 为主,因此能完全保证稳定性
- 2.7.x 作为社区的主要开发版本,得到持续更新并增加了大量新 feature 和优化,同时也带来了一 些稳定性挑战
1.2.1 源码拉取
通过以下的这个命令签出最新的dubbo项目源码,并导入到IDEA中
git clone https://github.com/apache/dubbo.git dubbo
1.2.2 源码结构
通过如下图形可以大致的了解到,dubbo源码各个模块的相关作用:
模块说明:
- dubbo-common 公共逻辑模块:包括 Util 类和通用模型。
- dubbo-remoting 远程通讯模块:相当于 Dubbo 协议的实现,如果RPC 用 RMI协议则不需要使用此包。
- dubbo-rpc 远程调用模块:抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。
- dubbo-cluster 集群模块:将多个服务提供方伪装为一个提供方,包括:负载均衡, 容错,路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。
- dubbo-registry 注册中心模块:基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。
- dubbo-monitor 监控模块:统计服务调用次数,调用时间的,调用链跟踪的服务。
- dubbo-config 配置模块:是 Dubbo 对外的 API,用户通过 Config 使用Dubbo,隐藏 Dubbo 所有细节。
- dubbo-container 容器模块:是一个 Standlone 的容器,以简单的 Main 加载 Spring启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。
1.2.3 管理控制台
- 下载管理控制台, GITHUB地址
- 进入源码目录, 进行打包编译
mvn clean package -Dmaven.test.skip=true
构建成功提示:
如果构建过程中出现nodejs安装包下载错误, 可以将安装包直接放置maven仓库内(资料中已提供安装包)。
3. 启动后台管理服务
java -jar dubbo-admin-0.2.0-SNAPSHOT.jar
4. 管理后台
地址: http://127.0.0.1:8080/
默认账户名和密码都为root
进入管理后台, 可以看到所启动的服务端与消费端。
2. Dubbo实战运用
2.1 Dubbo与SpringBoot的整合
基于Zookeeper实现Dubbo与Spring Boot的集成整合。
2.1.1工程POM依赖
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<dubbo-version>2.7.8</dubbo-version>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo-version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-version}</version>
</dependency>
<!-- Dubbo核心组件 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!--Spring Boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Zookeeper客户端框架 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<!-- Zookeeper dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo-version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Dubbo采用2.7.8版本, Spring Boot采用的是2.3.0.RELEASE版本。
如果依赖下载出现问题, 可以指定具体的仓库:
<repositories>
<repository>
<id>apache.snapshots.https</id>
<name>Apache Development Snapshot Repository</name>
<url>https://repository.apache.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
2.1.2 公用RPC接口工程
public interface OrderService {
/**
* 获取订单详情
* @param orderId
* @return
*/
String getOrder(Long orderId);
}
2.1.3. 服务端工程
pom
<dependencies>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-version}</version>
</dependency>
<!-- Dubbo 核心依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- 公用RPC接口依赖 -->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>spring-dubbo-interface</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
实现类
通过DubboService注解, 声明为RPC服务,version可以标识具体的版本号, 消费端需匹配保持
一致。
import com.itheima.dubbo.spring.api.OrderService;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Method;
import org.springframework.beans.factory.annotation.Value;
import java.util.concurrent.TimeUnit;
//@DubboService(version = "${dubbo.spring.provider.version}")
//@DubboService(
// version = "${dubbo.spring.provider.version}"
// ,timeout = 1000
// ,methods = {
// //某个方法超时配置
// @Method(name = "getOrder",timeout = 2000)
// }
//)
@DubboService(
version = "${dubbo.spring.provider.version}",
executes = 10,
methods = {
//指定某个方法并发数量
@Method(name = "getOrder",executes = 3)
}
)
public class OrderServiceImpl implements OrderService {
/**
* 服务端口
*/
@Value("${server.port}")
private String serverPort;
/**
* 获取订单详情
* @param orderId
* @return
*/
public String getOrder(Long orderId) {
if(orderId==4){
try {
//TimeUnit.SECONDS.sleep(1500);
Thread.sleep(900);
} catch (Exception e) {
}
}else if(orderId==5){
throw new RuntimeException("哈哈哈");
}
System.out.println("Service:"+serverPort);
return "Get Order Detail, Id: " + orderId + ", serverPort: " + serverPort;
}
}
工程配置
# 服务端口
server.port=18081
# 应用程序名称
spring.application.name=dubbo-spring-provider
# Dubbo服务扫描路径
dubbo.scan.base-packages=com.xxx
# Dubbo 通讯协议
dubbo.protocol.name=dubbo
# Dubbo服务提供的端口, 配置为-1,代表为随机端口
dubbo.protocol.port=-1
## Dubbo 注册器配置信息
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.registry.file = ${user.home}/dubbo-
cache/${spring.application.name}/dubbo.cache
dubbo.spring.provider.version = 1.0.0
Spring Boot启动程序
@SpringBootApplication
@ComponentScan(basePackages = {"com.xxx"})
public class DubboSpringProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboSpringProviderApplication.class, args);
}
}
2.1.4. 消费端工程
pom
<dependencies>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-version}</version>
</dependency>
<!-- 公用RPC接口依赖 -->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>spring-dubbo-interface</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
消费端调用
@Controller
public class OrderController {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 订单服务接口
*/
//@DubboReference(version = "${dubbo.spring.provider.version}")
//本地存根使用
@DubboReference(
version = "${dubbo.spring.provider.version}",
//指定本地存根
stub = "com.itheima.dubbo.spring.stub.OrderServiceStub",
lazy = true
)
//@DubboReference(version = "2.0.0")
//@DubboReference(
// version = "${dubbo.spring.provider.version}"
// //随机,具有权重随机
// ,loadbalance = "random"
//)
//@DubboReference(
// version = "${dubbo.spring.provider.version}",
// //重试次数
// retries = 3
//)
//@DubboReference(
// version = "${dubbo.spring.provider.version}"
// ,methods = {
// @Method(name = "getOrder",timeout = 1000)
// }
//)
private OrderService orderService;
/**
* 获取订单详情接口
* @param orderId
* @return
*/
@RequestMapping("/getOrder")
@ResponseBody
public String getOrder(Long orderId) {
String result = orderService.getOrder(orderId);
return result;
}
}
工程配置
# 服务端口
server.port=18082
#服务名称
spring.application.name=dubbo-spring-consumer
#服务版本号
dubbo.spring.provider.version = 1.0.0
#消费端注册器配置信息
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.registry.file = ${user.home}/dubbo-
cache/${spring.application.name}/dubbo.cache
Spring Boot启动程序
@SpringBootApplication
@ComponentScan(basePackages = {"com.xxx"})
public class DubboSpringConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboSpringConsumerApplication.class, args);
}
}
2.1.5. 工程调用验证
- 启动ZK注册中心
- 启动服务端, 运行DubboSpringProviderApplication
- 启动消费端, 运行DubboSpringConsumerApplication
- 请求获取订单接口, 地址: http://127.0.0.1:18082/getOrder?orderId=1001
2.2 Dubbo高阶配置运用
2.2.1 不同配置覆盖关系
-
覆盖规则:
配置规则:
方法级优先,接口级次之,全局配置再次之。
如果级别一样,则消费方优先,提供方次之。 -
服务端超时设定
增加配置类:
@Configuration
public class DubboConfig {
/***
* 服务端全局配置
*/
@Bean
public ProviderConfig registryConfig(){
ProviderConfig config = new ProviderConfig();
//全局超时时间 1s
config.setTimeout(800);
//config.setWeight(100); //权重设置,不建议
//config.setLoadbalance("random");
//全局并发数量
//config.setExecutes(100);
return config;
}
}
修改服务接口实现:
设定模拟睡眠时间
/**
* 获取订单详情
* @param orderId
* @return
*/
public String getOrder(Long orderId) {
try {
// 休眠1.5秒
Thread.sleep(1500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Get Order Detail, Id: " + orderId + ", serverPort: " +
serverPort;
}
- 客户端调用验证
服务端全局超时设为2秒(不触发超时), 消费端设定超时时间为1秒(触发超时)。
修改调用代码:
/**
* 订单服务接口
*/
@DubboReference(version = "${dubbo.spring.provider.version}",
timeout = 1000)
private OrderService orderService;
调用结果, 触发超时:
表明消费端配置优先
触发超时, 表明服务提供方优先级次之。
2.2.2 属性配置优先级
优先级从高到低:
-
JVM -D 参数;
-
XML配置会重写 dubbo.properties 中的;
-
Properties默认配置,仅仅作用于以上两者没有配置时。
-
JVM参数优先级验证
application.properties里面配置了dubbo.protocol.port端口10888
JVM运行参数端口设定为-Ddubbo.protocol.port=10889
启动服务
服务启动完成, 可以看到端口优先以JVM参数为准 -
Properties配置文件验证
1注释掉application.properties里面配置的dubbo.protocol.name和dubbo.protocol.port配置
2dubbo.properties里面配置dubbo.protocol.name和dubbo.protocol.port
3在启动参数里, 添加-Ddubbo.properties.file=dubbo.properties
启动服务
查看dubbo.properties配置的端口, 可以看到正常生效:
C:\Users\hxx68>netstat -ano |findstr 30889
TCP 0.0.0.0:30889 0.0.0.0:0 LISTENING
49816
TCP [::]:30889 [::]:0 LISTENING
49816
2.2.3 重试与容错处理机制
. 容错机制:
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
- 调整客户端重试次数
/**
* 订单服务接口
*/
@DubboReference(version = "${dubbo.spring.provider.version}",retries =
3)
private OrderService orderService;
这里的重试次数设定为3次。
3. 修改服务端超时时间
模拟超时, 让客户端触发重试。
/**
* 服务端全局配置
* @return
*/
@Bean
public ProviderConfig registryConfig() {
ProviderConfig providerConfig = new ProviderConfig();
providerConfig.setTimeout(1000);
return providerConfig;
}
将超时时间设小一些为1秒。
-
客户端调用(单个服务)
http://127.0.0.1:18082/getOrder?orderId=123
查看服务端控制台,可以看到触发重试机制:
加上第一次的调用和3次重试, 共4次。 -
客户端调用(多个)
允许多个实例运行, 开启多个服务
访问接口, http://127.0.0.1:18082/getOrder?orderId=123
第一个服务实例,访问两次, 其他每个服务访问一次。
2.2.4 多版本控制
- 启动三个服务端
第一个服务端版本为1.0.0, 第二、三个服务端版本为2.0.0。
修改application.properties配置:
#服务版本号
dubbo.spring.provider.version = 2.0.0
- 消费端指定版本号为2.0.0
修改application.properties配置:
#服务版本号
dubbo.spring.provider.version = 2.0.0
- 仍是采用超时配置, 通过重试测试验证
测试验证结果:
请求只会访问至版本号为2.0.0的服务节点上面
2.2.5 本地存根调用
- 实现流程
把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
- 客户端存根实现:
增加service接口
public class OrderServiceStub implements OrderService {
//代理对象->Proxy->Remote($Proxy)
private final OrderService orderService;
public OrderServiceStub(OrderService orderService) {
this.orderService = orderService;
}
/***
* 订单查询
* @param orderId
* @return
*/
@Override
public String getOrder(Long orderId) {
if(orderId!=null){
//远程调用
return orderService.getOrder(orderId);
}
return "本地校验不合法....";
}
}
- 修改客户端调用配置
@DubboReference(
version = "${dubbo.spring.provider.version}",
//指定本地存根
stub = "com.itheima.dubbo.spring.stub.OrderServiceStub",
lazy = true
)
private OrderService orderService;
stub要配置存根接口的完整路径。
- 测试调用
访问不带参数的地址: http://127.0.0.1:18082/getOrder
会进入存根接口的处理逻辑, 提示校验异常。
2.2.6 负载均衡机制
-
默认负载策略
Dubbo默认采用的是随机负载策略。
开启三个服务节点,通过消费端访问验证: http://127.0.0.1:18082/getOrder?orderId=123
通过控制后台日志输出, 可以看到每个服务节点呈现不规则的调用。 -
Dubbo 支持的负载均衡策略
Random LoadBalance
随机,按权重设置随机概率。 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
轮询,按公约后的权重设置轮询比率。 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。 使慢的提供者收到
更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
一致性 Hash,相同参数的请求总是发到同一提供者。 当某一台提供者挂时,原本发往
该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
源码实现: org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance
Dubbo提供了四种实现:
- 四种配置方式:
优先级从下至上: - 服务端的服务级别:
<dubbo:service interface="..." loadbalance="roundrobin" />
- 客户端的服务级别:
<dubbo:reference interface="..." loadbalance="roundrobin" />
服务端方法级别:
<dubbo:service interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
客户端方法级别:
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
- 调用验证
修改客户端的负载策略, 改为轮询策略
@DubboReference(
version = "${dubbo.spring.provider.version}",
//指定本地存根
stub = "com.itheima.dubbo.spring.stub.OrderServiceStub",
lazy = true,
loadbalance = "roundrobin"
)
开启三个服务节点, 进行访问验证: http://127.0.0.1:18082/getOrder?orderId=123
会依次轮询进行调用
- 动态权重调整验证
管理后台地址: http://127.0.0.1:8080/#
通过管理后台修改服务的权重配置:
将两台节点的权重降低至20:
调整后可以看到权重配置已经生效:
通过消费者接口访问, 会发现第一台权重较大的节点, 访问次数会明显增多。
2.2.7 服务降级运用
- 服务动态禁用
启动单个服务节点,进入Dubbo Admin, 创建动态配置规则
configVersion: v2.7
enabled: true
configs:
- side: provider
addresses:
- '0.0.0.0:20880'
parameters:
timeout: 3000
disabled: true
将disabled属性设为true, 服务禁用, 可以错误提示:
将disabled属性改为false,
configVersion: v2.7
enabled: true
configs:
- side: provider
addresses:
- '0.0.0.0:20880'
parameters:
timeout: 3000
disabled: false
恢复正常访问:
- 服务降级
配置规则
RegistryFactory registryFactory =
ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveEx
tension();
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"));
- k=force:return+null 表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
- 还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
降级测试(force方式)
进入Dubbo Admin进行配置:
configVersion: v2.7
enabled: true
configs:
- side: consumer
addresses:
- '0.0.0.0'
parameters:
timeout: 3000
mock: 'force:return null'
客户端调用, 会直接屏蔽, 并且服务端控制台不会有任何调用记录:
降级测试(fail方式)
进入Dubbo Admin配置:
configVersion: v2.7
enabled: true
configs:
- side: consumer
addresses:
- '0.0.0.0'
parameters:
timeout: 3000
mock: 'fail:return null'
这里为了触发调用异常, 超时时间缩短为1秒。
客户端调用, 会出现降级显示为空:
同时服务端会有调用记录显示(请求会进入服务端,但由于超时, 调用是失败):
2.2.8 并发与连接控制
实际运用, 会碰到高并发与峰值场景, Dubbo是可以做到并发与连接数控制。
并发数控制
- 服务端控制
服务级别
<dubbo:service interface="com.foo.BarService" executes="10" />
服务器端并发执行(或占用线程池线程数)不能超过 10 个。
方法级别
<dubbo:service interface="com.foo.BarService">
<dubbo:method name="sayHello" executes="3" />
</dubbo:service>
限制具体的方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个。
- 客户端控制
调用的服务控制
<dubbo:reference interface="com.foo.BarService" actives="10" />
每客户端并发执行(或占用连接的请求数)不能超过 10 个。
调用的服务方法控制
<dubbo:reference interface="com.foo.BarService">
<dubbo:method name="sayHello" actives="10" />
</dubbo:service>
dubbo:reference比dubbo:service优先。
- 客户端负载配置
<dubbo:reference interface="com.foo.BarService" loadbalance="leastactive" />
负载策略为最小连接数时, Loadbalance 会调用并发数最小的 Provider。
连接数控制
- 服务端连接控制
<dubbo:provider protocol="dubbo" accepts="10" />
限制服务器端接受的连接不能超过 10 个
- 客户端连接控制
<dubbo:reference interface="com.foo.BarService" connections="10" />
限制客户端服务使用连接不能超过 10 个
如果 dubbo:service 和 dubbo:reference 都配了 connections,dubbo:reference 优先