Dubbo学习笔记

Duboo基础


1.相关概念

Dubbo是阿里巴巴公司开源的一个高性能、轻量级的Java RPC框架

致力于提供高性能和透明化的RPC(远程服务调用方案),以及SOA服务治理方案,

官网:http://dubbo.apache.org

dubbo架构:

在这里插入图片描述

节点角色说明:

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

2.Dubbo入门案例

注意:以下的项目中的springboot版本不要选择过高,选择过高会报错,选择2.7.8即可

(1)编写原始项目

编写两个模块,分别包含service层和Dao(controller)层的代码,我们需要运用controller层调用service的服务:

编写完成的项目目录如下:

在这里插入图片描述

同时,需要在controller模块中导入service层的依赖:

<dependency>
    <groupId>com.example</groupId>
    <artifactId>Dubboservice</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

代码如下:

@RestController
@RequestMapping("/user")
public class Hellocontroller {

    @Autowired
    private Helloservice helloservice;
    
    @GetMapping("/hello")
    public String sayHello(String name){
       return helloservice.sayHello(name);
    }
}


public interface Helloservice {
    String sayHello();
}

@Service
public class Helloserviceimpl implements Helloservice {
    @Override
    public String sayHello(String name) {
        System.out.println("Hello,Dubbo and "+name+"!!!!");
        return "Hello,Dubbo and "+name+"!!!!";
    }
}

至于为什么controller层能调用service的代码,明明他们在不同的模块下,@SpringBootAplication扫描的路径应不包含另一个模块的代码呀?

答:因为我们引入了另一个模块的依赖,在我们扫描的时候他同时也会扫描另一个模块的代码,也就会扫到那个那个Bean对象并装配上去

(2)进行改造

我们现在的项目依旧是单体项目,因为每个模块并不能单独的运行,我们需要进行一定的改造:

<1>在父工程pom文件导入依赖:

因为是springBoot编写的,所以需引入dubbo-spring-boot-starter,而不是:dubbo

 <properties>
        <dubbo.version>3.2.0-beta.4</dubbo.version>
        <spring-boot.version>2.7.8</spring-boot.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </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>

            <!-- Dubbo -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-zookeeper-curator5</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
<2>在controller模块和service模块导入依赖:

需要引入dubbo与springboot整合的依赖,以及springboot的依赖

    <dependencies>
        <!-- dubbo -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper-curator5</artifactId>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-reload4j</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- spring boot starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--公共接口模块-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>Dubbointerface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>
<3>添加dubbo注解

在service的实现类中,我们将@service注解进行替换:

@DubboService
public class Helloserviceimpl implements Helloservice {
    @Override
    public String sayHello(String name) {
        System.out.println("Hello,Dubbo and "+name+"!!!!");
        return "Hello,Dubbo and "+name+"!!!!";
    }
}

@DubboService注解可以帮我们把该对象对外发布,也就是在我们配置的注册中心中注册一下

在controller模块中,我们将@Autowired注解进行替换

@RestController
@RequestMapping("/user")
public class Hellocontroller {
    @DubboReference
    private Helloservice helloservice;

    @GetMapping("/hello")
    public String sayHello(String name){
        return helloservice.sayHello(name);
    }
}

@DubboReference的作用包括:

  • 1.从zookeeper注册中心获取userservice的访问url
  • 2.进行远程调用RPC
  • 3.将结果封装为一个代理对象。给变量赋值

@DubboReference注解是远程注入,而@Autowreid注解是本地注入

<4>配置yml文件

我们需要将Bean对象在注册中心注册以及需要从注册中心获取对象,就需要配置注册中心:

在service层中:

#服务端口
server:
  port: 9000

dubbo:
  #配置需要服务模块的名称
  application:
    name: Dubboservice
    #配置注册中心的地址
  registry:
    address: zookeeper://192.168.37.136:2181

在controller层中:

dubbo:
  application:
    name: Dubbocontroller
  registry:
    address: zookeeper://192.168.37.136:2181

配置完成后我们就可以启动两个服务了

<5>测试

通过访问路径:localhost:8080/user/hello?name=zc

可以看到返回结果:

在这里插入图片描述

说明成功

(3)抽离公共接口

我们在上述操作中发现,在service层中和controller层中我们都需要都用Helloservice接口,那么我们就可以单独将其抽离成一个独立的模块:

我们新建一个Dubbointerface模块,其中就存放该接口方法,其他的模块通过引入该模块就可以获取该接口方法了:

新建模块:

在这里插入图片描述

其他模块引入对该模块的依赖:

<dependency>
    <groupId>org.example</groupId>
    <artifactId>Dubbointerface</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

这样依旧测试成功


Dubbo高级配置

1.序列化

在两台机器传输对象时,需要将对象的数据进行序列化和反序列化操作才能进行传输

  • dubbo内部已经将序列化和反序列化的过程内部封装了。
  • 我们只需要在定义pojo类时实现serializable接口即可
  • 一般会定义一个公共的pojo模块,让生产者和消费者都依赖该模块。

2.地址缓存

注册中心挂了,服务是否可以正常访问?

  • 可以,因为dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心。
  • 当服务提供者地址发生变化时,注册中心会通知服务消费者。

3.超时与重试

<1>超时:

  • 服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去
  • 在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
  • dubbo利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
  • 可以使用timeout配置超时时间,默认值为1000,单位毫秒

在这里插入图片描述

通过@Dubboservice标签中的timeout标签或在yml配置文件的registry中指定

<2>重试:

  • 设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接
  • 如果出现网络抖动,则这一次请求就会失败。
  • Dubbo提供重试机制来避免类似问题的发生
  • 通过retries属性来设置重试次数。默认为2次。

通过@Dubboservice标签中的retries标签或在service模块的yml配置文件consumer中指定

例如:

dubbo:
  #配置需要服务模块的名称
  application:
    name: Dubboservice
    #配置注册中心的地址
  registry:
    address: zookeeper://192.168.37.136:2181
    #配置连接超时时间
    timeout: 3000
    #配置重试次数
  consumer:
    retries: 3

<3>多版本

  • 灰度发布:当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。

  • dubbo中使用version属性来设置和调用同一个接口的不同版本

  • 使用@Service注解中的version标签指定当前服务为那个版本,再通过@DubboReference注解中的version标签指定要注入的是哪个版本即可

  • 或者在service模块的yml文件中配置provider的version(先配置id,也就是provider的类名)和consumer的version((先配置id,也就是consumer的类名))

例如有两个service的版本:

@DubboService(version = "v1.0")
public class Helloserviceimpl1 implements Helloservice {

    private Integer i=1;
    @Override
    public String printHello(String name){
        System.out.println(i);
        return "Hello "+name+"!";
    }

    @Override
    public User findUser(int id){
        User user=new User(id,"小明",18);
        return user;
    }
}

@DubboService(version = "v2.0")
public class Helloserviceimpl2 implements Helloservice {
    private Integer i=2;
    @Override
    public String printHello(String name){
        System.out.println(i);
        return "Hello "+name+"!";
    }

    @Override
    public User findUser(int id){
        User user=new User(id,"小明",18);
        return user;
    }
}

@RestController
@RequestMapping("/user")
public class Hellocontroller {

    @DubboReference(version = "v2.0")
    private Helloservice helloservice;

    @GetMapping("/hello")
    public String sayHello(String name){
        return helloservice.printHello(name);
    }

    @GetMapping("/find")
    public User findUser(int id){
        return helloservice.findUser(id);
    }
}

最后在控制台输出的就是:1

<4>负载均衡

负载均衡策略(4种):

1.Random:按权重随机,默认值。按权重设置随机概率。

在这里插入图片描述

  • 通过@Service中的weight标签指定权重,通过@DubboReferance中的LoadBlance标签可以指定均衡策略:random(默认方案)
  • 或者在service的yml文件的consumer中指定均衡策略

2.RoundRobin:按权重轮询。

3.LeastActive:最少活跃调用数,相同活跃数的随机。

4.ConsistentHash:一致性Hash,相同参数的请求总是发到同一提供者。

<5>集群容错

集群容错模式:

  • Failover Cluster:失败重试。默认值。当出现失败,重试其它服务器,默认重试2次,使用retries配置。一般用于读操作
  • Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于写操作。
  • Failsafe Cluster:失败安全,出现异常时,直接忽略。返回一个空结果。
  • Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。
  • Forking Cluster :并行调用多个服务器,只要一个成功即返回。
  • Broadcast Cluster :广播调用所有提供者,逐个调用,任意一台报错则报错。

配置方法都是在@DubboReferance中的cluster标签指定的,例如:

@DubboReferance(cluster="failover")

<6>服务降级

服务降级方式:

  • mock=force:return null表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。

    (也就是不论怎么访问,访问都不会生效)

  • mock=fail:return null表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

    (也就是当访问失败时就让访问不再生效)

同样是在@DubboReferance中配置mock标签,例如:

@DubboReferance(mock="force:return null")

最后的yml文件呈现为:

#服务端口
server:
  port: 9000

dubbo:
  #配置需要服务模块的名称
  application:
    name: Dubboservice
    #配置注册中心的地址
  registry:
    address: zookeeper://192.168.37.136:2181
    #配置连接超时时间
    timeout: 3000
    #配置重试次数
  consumer:
    retries: 3
    #指定负载均衡策略:随机访问
    loadbalance: random
    #指定集群容错策略:失败重试
    cluster: failover
    #指定服务降级策略
    mock: force:return null
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值