Dubbo核心源码剖析(架构流程 环境搭建 springboot集成整合 高阶配置运用)

Dubbo核心源码剖析

1. Dubbo架构体系

1.1 框架介绍

1.1.1 概述

Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

1.1.2 运行架构

在这里插入图片描述
节点角色说明

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

关于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 管理控制台

  1. 下载管理控制台, GITHUB地址
  2. 进入源码目录, 进行打包编译
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. 工程调用验证
  1. 启动ZK注册中心
  2. 启动服务端, 运行DubboSpringProviderApplication
  3. 启动消费端, 运行DubboSpringConsumerApplication
  4. 请求获取订单接口, 地址: http://127.0.0.1:18082/getOrder?orderId=1001
    在这里插入图片描述

2.2 Dubbo高阶配置运用

2.2.1 不同配置覆盖关系
  1. 覆盖规则:
    在这里插入图片描述
    配置规则:
    方法级优先,接口级次之,全局配置再次之。
    如果级别一样,则消费方优先,提供方次之。

  2. 服务端超时设定
    增加配置类:

@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; 
} 

  1. 客户端调用验证
    服务端全局超时设为2秒(不触发超时), 消费端设定超时时间为1秒(触发超时)。
    修改调用代码:
/**
* 订单服务接口 
*/ 
@DubboReference(version = "${dubbo.spring.provider.version}", 
timeout = 1000) 
private OrderService orderService;

调用结果, 触发超时:
在这里插入图片描述
表明消费端配置优先
在这里插入图片描述
触发超时, 表明服务提供方优先级次之。

2.2.2 属性配置优先级

在这里插入图片描述
优先级从高到低:

  1. JVM -D 参数;

  2. XML配置会重写 dubbo.properties 中的;

  3. Properties默认配置,仅仅作用于以上两者没有配置时。

  4. JVM参数优先级验证
    application.properties里面配置了dubbo.protocol.port端口10888
    JVM运行参数端口设定为-Ddubbo.protocol.port=10889
    在这里插入图片描述
    启动服务
    在这里插入图片描述
    服务启动完成, 可以看到端口优先以JVM参数为准

  5. 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
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

  1. 调整客户端重试次数
/**
* 订单服务接口 
*/ 
@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秒。

  1. 客户端调用(单个服务)
    http://127.0.0.1:18082/getOrder?orderId=123
    查看服务端控制台,可以看到触发重试机制:
    在这里插入图片描述
    加上第一次的调用和3次重试, 共4次。

  2. 客户端调用(多个)
    允许多个实例运行, 开启多个服务
    访问接口, http://127.0.0.1:18082/getOrder?orderId=123
    在这里插入图片描述
    第一个服务实例,访问两次, 其他每个服务访问一次。

2.2.4 多版本控制
  1. 启动三个服务端
    第一个服务端版本为1.0.0, 第二、三个服务端版本为2.0.0。
    修改application.properties配置:
#服务版本号 
dubbo.spring.provider.version = 2.0.0
  1. 消费端指定版本号为2.0.0
    修改application.properties配置:
#服务版本号 
dubbo.spring.provider.version = 2.0.0
  1. 仍是采用超时配置, 通过重试测试验证
    测试验证结果:
    请求只会访问至版本号为2.0.0的服务节点上面
2.2.5 本地存根调用
  1. 实现流程

在这里插入图片描述
把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。

  1. 客户端存根实现:
    增加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 "本地校验不合法....";
    }
}

  1. 修改客户端调用配置
    @DubboReference(
            version = "${dubbo.spring.provider.version}",
            //指定本地存根
            stub = "com.itheima.dubbo.spring.stub.OrderServiceStub",
            lazy = true

    )
    private OrderService orderService;

stub要配置存根接口的完整路径。

  1. 测试调用
    访问不带参数的地址: http://127.0.0.1:18082/getOrder
    在这里插入图片描述
    会进入存根接口的处理逻辑, 提示校验异常。
2.2.6 负载均衡机制
  1. 默认负载策略
    Dubbo默认采用的是随机负载策略
    开启三个服务节点,通过消费端访问验证: http://127.0.0.1:18082/getOrder?orderId=123
    通过控制后台日志输出, 可以看到每个服务节点呈现不规则的调用。

  2. 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>

  1. 调用验证
    修改客户端的负载策略, 改为轮询策略
 @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
会依次轮询进行调用

  1. 动态权重调整验证
    管理后台地址: http://127.0.0.1:8080/#
    通过管理后台修改服务的权重配置:
    在这里插入图片描述
    将两台节点的权重降低至20:
    在这里插入图片描述
    调整后可以看到权重配置已经生效:
    在这里插入图片描述
    通过消费者接口访问, 会发现第一台权重较大的节点, 访问次数会明显增多。
2.2.7 服务降级运用
  1. 服务动态禁用
    启动单个服务节点,进入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

恢复正常访问:
在这里插入图片描述

  1. 服务降级
    配置规则
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是可以做到并发与连接数控制。

并发数控制

  1. 服务端控制
    服务级别
<dubbo:service interface="com.foo.BarService" executes="10" />

服务器端并发执行(或占用线程池线程数)不能超过 10 个。

方法级别

<dubbo:service interface="com.foo.BarService"> 
<dubbo:method name="sayHello" executes="3" /> 
</dubbo:service> 

限制具体的方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个。

  1. 客户端控制
    调用的服务控制
<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优先。

  1. 客户端负载配置
<dubbo:reference interface="com.foo.BarService" loadbalance="leastactive" />

负载策略为最小连接数时, Loadbalance 会调用并发数最小的 Provider。

连接数控制

  1. 服务端连接控制
<dubbo:provider protocol="dubbo" accepts="10" />

限制服务器端接受的连接不能超过 10 个

  1. 客户端连接控制
<dubbo:reference interface="com.foo.BarService" connections="10" />

限制客户端服务使用连接不能超过 10 个
如果 dubbo:service 和 dubbo:reference 都配了 connections,dubbo:reference 优先

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot整合Dubbo配置步骤如下: 1. 引入DubboZookeeper的依赖 在pom.xml文件中添加DubboZookeeper的依赖: ``` <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2..</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.14</version> </dependency> ``` 2. 配置Dubbo的注册中心 在application.properties文件中添加Dubbo的注册中心配置: ``` # Dubbo Registry dubbo.registry.address=zookeeper://127...1:2181 ``` 3. 配置Dubbo的服务提供者 在Spring Boot的配置类中添加Dubbo的服务提供者配置: ``` @Configuration public class DubboProviderConfig { @Value("${dubbo.application.name}") private String applicationName; @Value("${dubbo.registry.address}") private String registryAddress; @Bean public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName(applicationName); return applicationConfig; } @Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress(registryAddress); return registryConfig; } @Bean public ProtocolConfig protocolConfig() { ProtocolConfig protocolConfig = new ProtocolConfig(); protocolConfig.setName("dubbo"); protocolConfig.setPort(20880); return protocolConfig; } @Bean public ServiceConfig<GreetingService> greetingServiceConfig(GreetingService greetingService) { ServiceConfig<GreetingService> serviceConfig = new ServiceConfig<>(); serviceConfig.setInterface(GreetingService.class); serviceConfig.setRef(greetingService); serviceConfig.setVersion("1.."); serviceConfig.setRegistry(registryConfig()); serviceConfig.setProtocol(protocolConfig()); return serviceConfig; } } ``` 4. 配置Dubbo的服务消费者 在Spring Boot的配置类中添加Dubbo的服务消费者配置: ``` @Configuration public class DubboConsumerConfig { @Value("${dubbo.registry.address}") private String registryAddress; @Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress(registryAddress); return registryConfig; } @Bean public ReferenceConfig<GreetingService> greetingServiceReferenceConfig() { ReferenceConfig<GreetingService> referenceConfig = new ReferenceConfig<>(); referenceConfig.setInterface(GreetingService.class); referenceConfig.setVersion("1.."); referenceConfig.setRegistry(registryConfig()); return referenceConfig; } } ``` 5. 调用Dubbo服务 在Spring Boot的Controller中注入Dubbo的服务消费者,并调用Dubbo服务: ``` @RestController public class GreetingController { @Autowired private GreetingService greetingService; @GetMapping("/greeting") public String greeting(@RequestParam String name) { return greetingService.greeting(name); } } ``` 以上就是Spring Boot整合Dubbo配置步骤。 ### 回答2: Spring Boot是一种非常流行的Java开发框架,Dubbo是阿里巴巴的分布式框架,用于提高服务的并发性和可扩展性。然而,将Spring Boot与Dubbo结合起来使用有点棘手。下面将讨论在Spring Boot应用程序中整合Dubbo配置过程。 1.首先,需要添加Dubbo和Spring Boot的依赖到pom.xml中。这里我将展示如何添加这些依赖。 ```xml <dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.0</version> </dependency> ``` ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 上述代码中的"dubbo-spring-boot-starter" jar文件提供了在Spring Boot环境中自动配置和启动Dubbo框架的功能,"spring-boot-starter-web" jar文件是Spring Boot开发常用的Web框架。 2.接下来,我们需要在Spring Boot应用程序的配置文件中添加Dubbo的相关配置。 ```properties # Dubbo application name spring.application.name=dubbo-consumer # Dubbo Registry address spring.dubbo.registry.address=zookeeper://localhost:2181 # Dubbo scan packages spring.dubbo.scan.base-packages=com.example.service # Dubbo Consumer timeout spring.dubbo.consumer.timeout=6000 # Dubbo Provider timeout spring.dubbo.provider.timeout=6000 # Dubbo Consumer retries spring.dubbo.consumer.retries=0 # Dubbo Provider retries spring.dubbo.provider.retries=0 ``` 在上述配置文件中,“spring.application.name”属性是应用程序的名称,用于在Dubbo注册中心上标识该服务。"spring.dubbo.registry.address"属性指定Dubbo注册中心的地址,Dubbo框架将使用该地址向注册中心注册和发现服务。"spring.dubbo.scan.base-packages"属性指定Dubbo扫描的服务包,所有符合条件的服务将被Dubbo管理。此外,其他Dubbo属性,如超时,重试次数等,也可以在此文件中配置。 3.接下来,我们需要向Spring Boot应用程序中添加Dubbo服务。我们可以通过以下步骤: ```java @Service public class UserServiceImpl implements UserService { @Override public UserDto getUserById(Long id) { UserDto userDto = new UserDto(); // do something return userDto; } } ``` 可以看到,上述代码中,我们使用"@Service"注解来标记服务实现类。我这里使用了一个简单的UserService接口和它的实现类UserServiceImpl,你可以根据自己的需求修改它们。 4.最后,我们创建一个Dubbo Consumer来调用这个服务: ```java @RestController public class UserController { @Reference UserService userService; @GetMapping("/users/{id}") public UserDto getUserById(@PathVariable Long id) { return userService.getUserById(id); } } ``` 上述代码中,我们使用"@Reference"注解将Dubbo服务注入到UserController中。我们可以使用@Reference注解在Spring Boot中编写Dubbo Consumer,该注解负责创建Dubbo服务的代理对象,从而简化应用程序的编写过程。 综上所述,将Spring Boot与Dubbo结合使用的配置步骤如下:添加Dubbo和Spring Boot的依赖,配置Dubbo属性,添加Dubbo服务以及创建Dubbo Consumer。这些步骤将帮助我们在Spring Boot应用程序中使用Dubbo框架,提高应用程序的性能和可扩展性。 ### 回答3: Spring Boot 是一种快速开发框架,适用于构建独立的,生产级别的应用程序,并且 Dubbo 是一种高性能,分布式服务框架,可以方便地实现RPC服务的注册,发现和调用。在开发现代化架构的企业级应用程序时,很常见使用Spring Boot 与 Dubbo 框架一起工作。 Spring Boot整合Dubbo,需要进行以下步骤: 1. 添加Dubbo依赖 在pom.xml中引入Dubbo的依赖,这些依赖包括Dubbo核心模块dubbo,以及ZooKeeper的客户端依赖curator。 2. 添加Dubbo配置 在application.properties文件中添加Dubbo配置。这些配置包括Dubbo应用程序的名称,协议,注册中心地址以及服务端口号等。 3. 配置Dubbo注册中心 配置Dubbo注册中心,我们可以使用ZooKeeper 或者 Redis。通常情况下,我们使用ZooKeeper作为Dubbo的注册中心。在Dubbo配置文件中指定zookeeper注册地址,它可以是一个单一的zookeer服务器,也可以是一个zookeeper集群。 4. 实现Dubbo服务 在实现Dubbo服务之前,我们需要定义一个接口供消费者调用。在该接口上使用Dubbo的@Service注解。使用Dubbo的@Service注解后,要使用Dubbo的@Service注解,需要使用Dubbo的@Reference注解。使用@Reference注解后,您就可以使用Dubbo的服务了。 总的来说,整合Spring Boot和Dubbo是比较简单的,只需要按照上述步骤进行相应的配置即可。这样就能使用Dubbo框架来快速构建高性能,分布式服务的系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值