Dubbo快速入门

1、什么是Dubbo

Dubbo 是一个分布式高性能透明化的 RPC 服务框架,

提供服务自动注册自动发现等高效服务治理方案,

可以和Spring 框架无缝集成。

2、为什么要使用Dubbo

Dubbo 的诞生和 SOA 分布式架构的流行有着莫大的关系。SOA 面向服务的架构(Service Oriented Architecture),也就是把工程按照业务逻辑拆分成服务层表现层两个工程。服务层中包含业务逻辑,只需要对外提供服务即可表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。

SOA架构中有两个主要角色:

  • 服务提供者(Provider)
  • 服务使用者(Consumer)
  • 我觉得主要可以从 Dubbo 提供的下面四点特性来说为什么要用 Dubbo:
    • 负载均衡——同一个服务部署在不同的机器时该调用那一台机器上的服务
    • 服务调用链路生成——随着系统的发展,服务越来越多,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。Dubbo 可以为我们解决服务之间互相是如何调用的。
    • 服务访问压力以及时长统计、资源调度和治理——基于访问压力实时管理集群容量,提高集群利用率。
    • 服务降级——某个服务挂掉之后调用备用服务 另外,Dubbo 除了能够应用在分布式系统中,也可以应用在现在比较火的微服务系统中。不过,由于 Spring Cloud 在微服务中应用更加广泛,所以,我觉得一般我们提 Dubbo 的话,大部分是分布式系统的情况

3、什么是分布式

分布式或者说 SOA 分布式重要的就是面向服务,说简单点分布式就是我们把整个系统拆分成不同的服务然后将这些服务放在不同的服务器上减轻单体服务的压力提高并发量和性能。比如电商系统可以简单地拆分成订单系统、商品系统、登录系统等等,拆分之后的每个服务可以部署在不同的机器上,如果某一个服务的访问量比较大的话也可以将这个服务同时部署在多台机器上。

4、为什么要用分布式

从开发角度来讲单体应用的代码都集中在一起,而分布式系统的代码根据业务被拆分。所以,每个团队可以负责一个服务的开发,这样提升了开发效率。另外,代码根据业务拆分之后更加便于维护扩展

另外,我觉得将系统拆分成分布式之后不光便于系统扩展和维护,更能提高整个系统的性能。使用更多的计算机完成同样的功能,计算机越多,CPU内存存储资源也越多,处理并发访问数据量就越大。

5、Dubbo的架构与工作流程

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

调用关系说明:

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

重要知识点总结:

  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
  • 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

6、Dubbo的负载均衡策略

在集群负载均衡时,Dubbo 提供了多种均衡策略,默认为 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">random</font> 随机调用。可以自行扩展负载均衡策略。

Random LoadBalance(默认,基于权重的随机负载均衡机制)

  • 随机,按权重设置随机概率。
  • 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

RoundRobin LoadBalance(不推荐,基于权重的轮询负载均衡机制)

  • 轮循,按公约后的权重设置轮循比率。
  • 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

LeastActive LoadBalance

  • 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
  • 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

ConsistentHash LoadBalance

  • 一致性 Hash,相同参数的请求总是发到同一提供者。(如果你需要的不是随机负载均衡,是要一类请求都到一个节点,那就走这个一致性hash策略。)
  • 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

注解配置方式:

消费方基于基于注解的服务级别配置方式:

  1. <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">@Reference(loadbalance = "roundrobin")</font>
  2. <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">HelloService helloService;</font>

xml 配置方式 服务端服务级别

<font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);"><dubbo:service interface="..." loadbalance="roundrobin" /></font>

7、Dubbo的集群容错策略

Failover Cluster(默认)

失败自动切换,当出现失败,重试其它服务器。(缺省)通常用于读操作,

但重试会带来更长延迟。可通过 retries="2"来设置重试次数(不含第一次)。

Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,

比如新增记录。

Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读

操作,但需要浪费更多服务资源。可通过 forks="2"来设置最大并行数。

Broadcast Cluster

广播逐个调用所有提供者,任意一个报错则报错

8、Dubbo使用demo

首先创建个Springboot工程,共有三个子模块,

provider模块:服务提供方,consumer:服务调度方(消费),common:公共模块:暴露接口

导入依赖包,provider与consumer的如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- dubbo依赖 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>3.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-rpc-dubbo</artifactId>
            <version>3.2.4</version>
        </dependency>
        <!-- triple协议 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-rpc-triple</artifactId>
            <version>3.2.4</version>
        </dependency>
        <dependency>
            <!-- 注册中心 -->
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-registry-zookeeper</artifactId>
            <version>3.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.llg</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

配置中心:provider

server:
  port: 8081
spring:
  application:
    name: dubbo-provider
dubbo:
  protocol:
    name: tri
    port: 20881
  registry:
    address: zookeeper://127.0.0.1:2181

配置中心:consumer

server:
  port: 8082
spring:
  application:
    name: dubbo-consumer
dubbo:
  protocol:
    name: tri
    port: 20881
  registry:
    address: zookeeper://127.0.0.1:2181

provider和consumer的启动器需要加上@EnableDubbo注解

将用户Service接口定义到common模块,方便其他服务调用,Service的实现类在provider模块

/**
 * 用户接口
 *
 * @author llg
 * @create 2023-12-30 12:43
 */
public interface UserService {
    // UNARY
    String getUserName();
}

userService的实现类,Dubbo的业务类用@DubboService取代@Service注解,用于Dubbo服务发现

/**
 * 功能描述
 *
 * @author llg
 * @create 2023-12-30 12:26
 */
@DubboService
public class UserServiceImpl implements UserService {

    @Override
    public String getUserName(){
        return "llg";
    }
}

consumer的OrderService调用UserService服务,通过@DubboReference注解注入远程服务。直接调用

/**
 * 功能描述
 *
 * @author llg
 * @create 2023-12-30 12:26
 */
@DubboService
public class OrderService {

    @DubboReference
    UserService userService;

    public String getOrder(){
        userService.getUserName();
    }
}

9、Dubbo3.0的新特性Stream流

Stream 是 Dubbo3 新提供的一种调用类型,在以下场景时建议使用流的方式:

  • 接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送
  • 流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的
  • 推送类场景,多个消息在同一个调用的上下文中被发送和处理

Stream 分为以下三种:

  • SERVER_STREAM(服务端流)
  • CLIENT_STREAM(客户端流)
  • BIDIRECTIONAL_STREAM(双向流)

由于 <font style="color:rgb(119, 119, 119);background-color:rgb(243, 244, 244);">java</font> 语言的限制,BIDIRECTIONAL_STREAM 和 CLIENT_STREAM 的实现是一样的。

在 Dubbo3 中,流式接口以 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">SteamObserver</font> 声明和使用,用户可以通过使用和实现这个接口来发送和处理流的数据、异常和结束。

服务端流:

UserService:

// Server_Stream
    @Override
    public void sayHelloServerStream(String name, StreamObserver<String> response) {
        // 处理name
        response.onNext("Hello " + name + "!");
        response.onNext("Hello " + name + "!");
        // 处理结束
        response.onCompleted();
    }

OrderService

@DubboReference
    UserService userService;

    public String getOrder(){

        userService.sayHelloServerStream("llg", new StreamObserver<String>() {
            @Override
            public void onNext(String data) {
                System.out.println("接收结果 = " + data);
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("接收异常");
            }

            @Override
            public void onCompleted() {
                System.out.println("结束");
            }
        });
    }

双端流 or 客户端流

UserService:

@Override
    public StreamObserver<String> sayHelloStream(StreamObserver<String> response) {
        return new StreamObserver<String>() {
            @Override
            public void onNext(String data) {
                System.out.println("服务端接收到的数据:"+data);
            //     处理数据
                response.onNext("服务端返回的数据:"+data);
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("接收异常");
            }

            @Override
            public void onCompleted() {
                System.out.println("发送完成");
            }
        };
    }

OrderService

public String getOrder(){
        
 StreamObserver<String> streamObserver = 
     userService.sayHelloStream(new StreamObserver<String>() {
            @Override
            public void onNext(String data) {
                System.out.println("data = " + data);
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("接收异常");
            }

            @Override
            public void onCompleted() {
                System.out.println("结束");
            }
        });
        streamObserver.onNext("1");
        streamObserver.onNext("2");
        streamObserver.onNext("3");
        streamObserver.onCompleted();
        return "success";
    }
1. 硬件将处理机划分为两种状态,即管态和目态,这样做给操作系统设计带来什么好处 ? 答:便于设计安全可靠的操作系统。管态和目态是计算机硬件为保护操作系统免受用户程序的干扰和破坏而引入的两种状态。通常操作系统在管态下运行,可以执行所有机器指令;而用户程序在目态下运行,只能执行非特权指令。如果用户程序企图在目态下执行特权指令,将会引起保护性中断,由操作系统终止该程序的执行,从而保护了操作系统。 2. 何为特权指令?举例说明之。如果允许用户执行特权指令,会带来什么后果? 答:只能在管态下才能执行的指令称为特权指令。如开关中断、置程序状态寄存器等。如果允许用户执行特权指令,它将不仅影响当前运行的程序,而且还有可能影响操作系统的正常运行,甚至整个系统。3. 中断向量在机器中的存储位置是由硬件确定的,还是由软件确定的 ? 答:中断向量在机器中的位置是由硬件确定的。例如,在 INTEL 80x86 CPU 中,内存空间0x00000——0x003ff为中断向量空间。4. 中断向量的内容是由操作系统程序确定的还是由用户程序确定的? 答:中断向量的内容是由操作系统程序确定的。向量的内容包括中断处理程序的入口地址和程序状态字(中断处理程序运行环境),中断处理程序是由操作系统装入内存的,操作系统将根据装入的实际地址和该中断处理程序的运行环境来填写中断向量。5. 中断向量内的处理机状态位应当标明是管态还是目态 ? 为什么? 答:应当标明是管态。 该状态由系统初试化程序设置,这样才能保证中断发生后进入操作系统规定的中断处理程序。 6. 中断和程序并发之间的关系是什么? 答:中断是程序并发的必要条件。如果没有中断,操作系统不能获得系统控制权,无法按调度算法对处机进行重新分配,一个程序将一直运行到结束而不会被打断。7. 说明“栈”和“堆”的差别. 答:栈是一块按后进先出(FIFO)规则访问的存储区域,用来实现中断嵌套和子程序调用的参数和返回断点。而堆虽然是一块存储区域,但是对堆的访问是任意的,没有后进先出的要求,堆主要用来为动态变量分配存储空间。 8. 何为系统栈?何为用户栈?系统栈有何用途?用户栈有何用途? 答:系统栈是内存中操作系统空间的一个固定区域;用户栈是内存中用户空间的一个区域。系统栈的作用:(1)保存中断现场,对于嵌套中断,被中断程序的现场信息依次压入系统栈,中断返回时逆序弹出;(2)保存操作系统子程序间相互调用的参数、返回值、返回点、以及子程序的局部变量。用户栈的作用:用于保存用户进程的子程序间相互调用的参数、返回值、返回点、以及子程序的局部变量。9. 用户堆栈段的长度为何无法确定 ? 答:用户堆栈段的长度主要取决于两个因素:(1)用户进程(线程)中子程序(函数)之间的嵌套调用深度;(2)子程序参数和局部变量的数量及类型;(3)动态变量的使用。这些在进程(线程)运行前无法确定,由此导致用户堆栈段的长度无法预先准确确定。 10堆栈段的动态扩充为何可能导致进程空间的搬迁? 答:堆栈段的扩充需要在原来进程空间大小的基础上增添新的存储区域,而且通常要求与原来存储区域连续。由于原存放位置处可扩展的区域可能已经被其它进程占用,故可能需要将整个进程空间搬迁到另外一个区域,以实现地址空间扩展要求。11. 何谓并行 ? 何谓并发? 在单处理机系统中,下述并行和并发现象哪些可能发生,哪些不会发生 ? (1) 进程与进程之间的并行; (2) 进程与进程之间的并发; (3) 处理机与设备之间的并行; (4) 处理机与通道之间的并行; (5) 通道与通道之间的并行; (6) 设备与设备之间的并行; 答:所谓并行是指同一时刻同时进行,进程并行需要多处理器的支持;所谓并发,是指在一段时间内,多个进程都在向前推进,而在同一时刻,可能只有一个进程在执行,多个进程轮流使用处理器。 在单处理器传统中,可能发生的并行和并发现象如下: (2) 进程与进程之间的并发。例如,在Windows操作系统中,mp3播放进程和Word字处理进程可以并发执行,这样用户就可以边听音乐边写文章了。 (3) 处理机与设备之间的并行。例如,当处理机进行科学运算时,打印机可以打印文档。 (4) 处理机与通道之间的并行。通道程序的执行可与处理机的操作并行。 (5) 通道与通道之间的并行。通常一个系统中有多个通道,这些通道可以并行地执行相应的通道程序。 (6) 设备与设备之间的并行。例如打印机打印文档时,磁带机在输入数据。 12. 何谓作业? 它包括哪几个部分? 各部分用途是什么?答:所谓作业是指用户要求计算机系统为其完成的计算任务的集合。一个作业通常包括程序、程序所处理的数据以及作业说明书。程序用来完成特定的功能,数据是程序处理的对象,作业说明书用来说明作业处理的步骤。13. 从透明性和资源共享两方面,说明网络操作系统与分布式操作系统之间的差别。 答:从透明性上看,分布式操作系统优于网络操作系统。网络用户能够感觉到所访问的资源是在本地还是在远地;而在分布式系统中,用户感觉不到所访问的资源是否在本地,分布式操作系统掩盖了资源在地理位置上的差异。 从资源共享上看 ,分布式操作系统比网络操作系统能共享更多的资源。在网络操作系统中,一个计算任务不能由一台主机任意迁移到另外一台主机上运行;而在分布式操作系统中,所有作业可以由一台主机任意迁移到另外一台主机上处理,即可实现处理机资源的共享,从而达到整个系统的负载平衡。 14. 为什么构成分布式系统的主机一般都是相同的或兼容的?答:这样更有利于进程的动态迁移。如果主机不兼容,则在一台主机上能运行的进程,因所用指令系统不同,在另一台主机上可能无法运行,导致进程难于在不同主机间迁移,使得分布式系统难于实现负载平衡。构成分布式系统的主机一般都是相同的或兼容的。15. 为什么嵌入式操作系统通常采用微内核结构?   答:嵌入式操作系统与一般操作系统相比具有比较明显的差别 : (1)嵌入式操作系统规模一般较小,因为一般硬件配置较低,而且对操作系统提供的功能要求也不高。(2)应用领域差别大,对于不同的应用领域其硬件环境和设备配置情况有明显差别。 所以,嵌入式操作系统一般采用微内核 ( micro kernel )结构,包括如下基本功能: (1)处理机调度;(2)基本内存管理;(3)通讯机制;(4)电源管理。在这些基本成分之上可进行扩展,以适应不同应用目标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Debug笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值