分布式架构与Dubbo-1-快速开始

本文深入介绍了分布式系统的基本理论,包括定义和发展演变,并详细讲解了RPC(远程过程调用)的工作原理。接着,文章重点探讨了Apache Dubbo的核心概念,如服务治理和注册发现,并提供了详细的环境搭建步骤。此外,还讨论了Dubbo的配置原则,如超时设置、重试次数管理和多版本控制。最后,文中提到了与SpringBoot的整合方式,包括注解、配置文件和JavaConfig。
摘要由CSDN通过智能技术生成

基础知识

分布式基础理论

什么是分布式系统
  • 《分布式系统原理与范型》定义:

    • 分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统
  • 分布式系统(distributed system)是建立在网络之上的软件系统

  • 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进

发展演变

在这里插入图片描述

  • 分布式服务架构的难度在于如何进行RPC(远程过程调用),以及如何拆分业务,提高业务的复用程度
  • 流动计算架构(SOA),基于访问压力实时管理集群容量,提高集群利用率
什么是RPC
  • RPC (Remote Procedure Call) 是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同

  • RPC基本原理图
    在这里插入图片描述
    在这里插入图片描述

  • 一次完整的RPC调用流程(同步调用)如下:

    1. 服务消费方 (client) 调用以本地调用方式调用服务
    2. client stub 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体 (序列化)
    3. client stub 找到服务地址,并将消息发送到服务端
    4. server stub 收到消息后进行解码 (反序列化)
    5. server stub 根据解码结果调用本地的服务
    6. 本地服务执行并将结果返回给 server stub
    7. server stub 将返回结果打包成消息并发送至消费方
    8. client stub 接收到消息,并进行解码
    9. 服务消费方得到最终结果
    • RPC框架的目标就是将2-8步封装,对用户来说是透明的不可见的
  • 决定RPC框架效率的两个因素:通信效率和序列化反序列化效率

  • dubbo的作用:治理和维护各个分系统

dubbo核心概念

  • Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现

dubbo环境搭建

dubbo-admin搭建

  1. 下载并启动zookeeper作为注册中心
  2. 从GitHub上下载dubbo-admin的zip项目
  3. 解压进入dubbo-admin目录,修改好配置文件后打包,java -jar jar包名运行jar包
  4. 默认localhost:7001进入dubbo-admin界面

项目搭建

  1. 创建2个springboot工程,一个作为提供者,一个作为消费者

  2. 编写对应工程的功能

  3. 再编写一个工程作为前二者的接口工程,放入二者的接口以及java bean

    • 提供者
      在这里插入图片描述

    • 消费者
      在这里插入图片描述

    • 接口项目
      在这里插入图片描述

    • 测试其他项目的时候其依赖的接口启动类的@SpringBootApplication要去掉,因为项目是springboot+dubbo架构,其他项目依赖于接口项目里的pojo,在接口项目中也有启动类@SpringBootApplication,因为在其他项目的测试类中启动方法时,会加载接口项目的启动类,会造成错误,注释掉接口项目启动类上的@SpringBootApplication注解即可。但不用测试类的时候又不会出错

    • 接口工程不用配置,专注于编写接口,所以接口项目可以使用maven工程创建,这样就彻底解决上述问题了

  4. 在二者的pom.xml中引入依赖的接口

    <dependency>
        <groupId>com.study</groupId>
        <artifactId>study_interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
  5. 提供者引入dubbo依赖和zookeeper客户端

    <!--引入dubbo-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>2.7.8</version>
    </dependency>
    
    <!--引入zookeeper-->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>2.12.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>2.12.0</version>
    </dependency>
    
  6. application.properties配置dubbo

    # 当前服务/应用的名字
    dubbo.application.name=user-service-provider
    
    # 注册中心的协议和地址
    dubbo.registry.address=zookeeper://192.168.88.22:2181
    # 或
    # dubbo.registry.protocol=zookeeper
    # dubbo.registry.address=192.168.88.22:2181
    
    # 通信规则(通信协议和接口)
    dubbo.protocol.name=dubbo
    dubbo.protocol.port=20880
    
    # 连接监控中心
    dubbo.monitor.protocol=registry
    # 开启包扫描,可替代 @EnableDubbo 注解
    # dubbo.scan.base-packages=com.study
    
  7. 在启动类上加入启动dubbo注解

    @SpringBootApplication
    // 开启基于注解的dubbo功能(主要是包扫描@DubboComponentScan)
    // 也可以在配置文件中使用dubbo.scan.base-package来替代   @EnableDubbo
    @EnableDubbo
    public class UserServiceProvideApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(UserServiceProvideApplication.class, args);
        }
    
    }
    
  8. 在提供者需要暴露的服务类上加上注解@DubboService

    @DubboService // 暴露服务
    @Component // 理论上这个注解可以不用了,因为在其项目中目前没有需要调用IoC容器中的该对象
    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            UserAddress address1 = new UserAddress(1, "翻斗花园二号楼一零零一室", "1", "胡老师", "123", "Y");
            UserAddress address2 = new UserAddress(2, "爱情公寓3601", "1", "曾老师", "250", "N");
            return Arrays.asList(address1, address2);
        }
    }
    
  9. 配置消费者:启动类加注解@EnableDubbo,配置文件

    # 避免端口冲突,设为8081端口访问
    # server.port=8081
    
    dubbo.application.name=order-service-consumer
    dubbo.registry.address=zookeeper://192.168.88.22:2181
    dubbo.monitor.protocol=registry
    dubbo.protocol.name=dubbo
    dubbo.protocol.port=20881
    
  10. 在消费者需要消费的接口上加上注解@DubboReference

    @Component
    public class OrderServiceImpl implements OrderService {
    
        @DubboReference // 类似于@Autowired,自动装配需要远程调用的类,项目启动时找不到会报错
        private UserService userService;
    
        @Override
        public void initOrder(String userId) {
            // 查询用户的收获地址
            List<UserAddress> addressList = userService.getUserAddressList(userId);
            addressList.forEach(System.out::println);
        }
    }
    

dubbo配置

配置原则

  • JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口
  • XML 次之,如果在 XML 中有配置,则dubbo.properties中的相应配置项无效
  • Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties的相应配置项才会生效,通常用于共享公共配置,比如应用名

启动时检查

  • Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check="true"
  • 可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动
  • 另外,如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭check,否则服务临时不可用时,会抛出异常,拿到null引用,如果check="false",总是会返回引用,当服务恢复时,能自动连上
  • @DubboReference(check = false)

超时设置

  • 由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间

  • 消费端

    • 全局设置dubbo.consumer.timeout=1000
    • 指定方法设置@DubboReference(timeout = 1000)
  • 服务端

    • 全局设置dubbo.provider.timeout=1000
    • 指定方法设置@DubboService(timeout = 1000)

重试次数

  • retries:重试次数,不包含第一次调用,0代表不重试
  • @DubboService(retries = 2)默认次数为2,与timeout相同,可以在不同作用域中设置
  • 幂等(设置重试次数)【查询、删除、修改】、非幂等(不能设置重试次数)【新增】
  • 如果有多个相同的提供者,会使用轮询的方法依次重试

多版本

  • 当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用
  • 可以按照以下的步骤进行版本迁移
    1. 在低压力时间段,先升级一半提供者为新版本
    2. 再将所有消费者升级为新版本
    3. 然后将剩下的一半提供者升级为新版本
  • @DubboService(version = "1.0.0"),参数为*时随机调用一个版本

本地存根

  • 远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy

  • 通常情况才采用远程服务调用后,对于服务消费者的请求,均是在服务提供者的远程机器上执行的!通过采用本地存根的形式就可以将服务消费者请求的一些验证操作在其本地进行执行,这样就减少了网络的传输,提高了执行效率

  • Stub实现@DubboService(stub = "true")

    public class BarServiceStub implements BarService {
        private final BarService barService;
        
        // 构造函数传入真正的远程代理对象
        public BarServiceStub(BarService barService){
            this.barService = barService;
        }
     
        public String sayHello(String name) {
            // 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
            try {
                return barService.sayHello(name);
            } catch (Exception e) {
                // 你可以容错,可以做任何AOP拦截事项
                return "容错数据";
            }
        }
    }
    
    • Stub 必须有可传入 Proxy 的构造函数
    • 在 interface 旁边放一个 Stub 实现,它实现 BarService接口,并有一个传入远程 BarService实例的构造函数

配置覆盖关系

  • 对于服务提供者和服务消费者Dubbo均提供了以下四种粒度的设置

    1. 方法级别

    2. 接口级别

    3. 服务消费者级别

    4. 服务提供者级别

  • 配置的覆盖规则:

    1. (精确优先)方法级配置别优于接口级别,接口级别优于全局配置,即小Scope优先
    2. (消费者优先)精确度相同的情况下,则消费方优先,提供方次之

与SpringBoot整合的三种方式

  • 第一种方式:
    • 注解的方式:在java类上使用Dubbo提供的注解
  • 第二种方式:
    • 配置文件方式:在xml配置文件中对Dubbo进行配置,包括服务应用的名称配置,注册中心配置,通信规则,服务提供者信息,服务消费者信息等
  • 第三种方式:
    • Java Config方法:通过java配置类(在一个java类上使用@Configuration注解)的方式配置注册中心,通信规则,服务提供者信息,服务消费者信息等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值