Dubbo

Dubbo是阿里巴巴公司开源的一个高性能、轻量级的 Java RPC 框架。
致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。
官网:http://dubbo.apache.org

RPC概述

RPC是远程过程调用(Remote Procedure Call)。 RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制,让使用者不必显式的区分本地调用和远程调用。

优点:
  1、分布式设计
  2、部署灵活
  3、解构服务
  4、扩展性强

有哪些RPC框架?
  Dubbo:国内最早开源的 RPC 框架,由阿里巴巴公司开发并于 2011 年末对外开源,仅支持 Java 语言。
  Motan:微博内部使用的 RPC 框架,于 2016 年对外开源,仅支持 Java 语言。
  Tars:腾讯内部使用的 RPC 框架,于 2017 年对外开源,仅支持 C++ 语言。
  SpringCloud:国外 Pivotal 公司 2014 年对外开源的 RPC 框架,提供了丰富的生态组件。
  gRPC:Google 于 2015 年对外开源的跨语言 RPC 框架,支持多种语言。
  Thrift:最初是由 Facebook 开发的内部系统跨语言的 RPC 框架,2007 年贡献给了 Apache 基金,成为Apache 开源项目之一,支持多种语言。

特性:
  1、RPC框架一般使用长链接,不必每次通信都要3次握手,减少网络开销。
  2、RPC框架一般都有注册中心,有丰富的监控管理。发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作协议私密,安全性较高
  3、RPC 协议更简单内容更小,效率更高,服务化架构、服务化治理,RPC框架是一个强力的支撑。

目前Dubbo在企业中有两种开发思路

  • 基于SOA思想
  SOA:(Service-Oriented Architecture,面向服务的架构)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过接口协议来完成服务间通信。
  将传统单一应用拆分为web(消费者)模块和service(提供者)模块,基于Dubbo通信。

    image

  • 辅助SpringCloud架构提升效率

  Dubbo基于TCP(传输层)协议,效率更高。可以替换Feign,提升高并发压力。

imageimage

Dubbo入门

Dubbo的基本架构

image

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

入门实践

1、安装Nacos(参考nocos章节)
2、安装DubboAdmin
  DubboAdmin是阿里巴巴管理提供的管理控制台,可以实现服务查询,详情展示,服务测试等功能。借由DubboAdmin可以更好的帮助开发人员对服务进行管理和监控。
  DubboAdmin的源代码托管在github上,可以通过命令拉取。修改配置并运行

1、下载代码: 
 git clone https://github.com/apache/dubbo-admin.git
2、在 dubbo-admin-server/src/main/resources/application.properties中指定注册中心地址
3、构建  
 mvn clean package -Dmaven.test.skip=true
4、启动
 mvn --projects dubbo-admin-server spring-boot:run
    或者
 cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar
5、访问 http://localhost:8080

image

3、使用Dubbo构建分布式架构,完成根据用户id查询用户

image

  3.1 搭建服务提供者user-provider

1、创建提供者模块并引入依赖(pom.xml)

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>

    <!--dubbo的起步依赖-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>2.7.8</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>2.7.8</version>
    </dependency>
</dependencies>

2、将service,mapper,domain导入到提供者模块中
3、将UserSerivice暴露为dubbo服务

@DubboService
public class UserServiceImpl implements UserService {
  …………
}

4、application.yml配置

server:
  port: 18081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: user-provider
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: HH:mm:ss:SSS
# 配置dubbo提供者
# dubbo协议和访问端口
dubbo:
  protocol:
    name: dubbo
    port: 20881
# 注册中心的地址
  registry:
    address: nacos://127.0.0.1:8848
# dubbo注解的包扫描
  scan:
    base-packages: cn.itcast.user.service

image

image

 注:针对dubbo协议及访问端口:服务消费者调用Netty服务器的20881端口,Netty相当于Socket服务器。Tomcat相当于提供者运行启动的容器。

imageimage

   3.2 搭建服务消费者user-consumer

1、创建提供者模块并引入依赖

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <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>2.7.8</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>2.7.8</version>
    </dependency>
</dependencies>

2、将controller,service接口导入到提供者模块中
3、在Controller中引入dubbo服务

@RestController
@RequestMapping("/user")
public class UserController {
    //引用远程服务
    @DubboReference
    private UserService userService;

4、application.yml配置

server:
  port: 18080
spring:
  application:
    name: user-consumer
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: HH:mm:ss:SSS
dubbo:
  registry:
    address: nacos://127.0.0.1:8848

  3.3 将API接口抽取为独立模块,并且把接口有关的domain都放到这个模块中

image

序列化

两个机器传输数据,在RPC通信时,往往采用二进制数据格式传输Java对象,故需要对对象进行序列化处理。

image

dubbo 内部已经将序列化和反序列化的过程内部封装了。在定义domain类时实现Serializable接口即可。

image

Dubbo的高级特性

启动检查

为了保障服务的正常可用,Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常。

image

在正式环境这是很有必要的一项配置,可以保证整个调用链路的平稳运行。
在开发时,往往会存在没有提供者的情况。由于启动检查的原因,可能导致开发测试出现问题。
可以通过check=false关闭。

image

多版本

在正式系统中,为了保证系统可用性和更好的并发性,往往通过集群部署。

如果提供者代码出现重大更新。如何对提供者升级部署呢?
  Dubbo提供了提供者多版本的支持,平滑处理项目功能升级部署。

image

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

 多版本实现

1、编写新的UserServce实现类,作为新版本代码
2、在暴露服务时,指定服务版本

imageimage

3、消费者引用服务时,指定引用的服务版本

image

超时与重试

服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。
在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
  • dubbo 利用超时机制来解决这个问题(使用timeout属性配置超时时间,默认值1000,单位毫秒)。

    消费者调用提供者是设置一个超时时间,等待超过该时间无响应将连接关闭。

    image

  • 若超时时间较短,当网络波动时请求就会失败,Dubbo通过重试机制避免此类问题的发生。
    场景:消费者调用提供者,设置超时时间1s,恰好发生网络波动,未收到响应,默认提供者故障,断开连接,当前请求失败。   
    解决:引入重试机制,当前请求失败,会再次发送两遍请求,如都没响应,断开连接。(一共访问三次)

    image

    针对增删改涉及数据库数据情况,重试三次会导致数据出错

      1、可通过@DubboReference 的retries=0关闭重试:

      image

      2、也可以修改application.yml关闭所有消费者重试

      image

负载均衡

在集群部署时,Dubbo提供了4种负载均衡策略,帮助消费者找到最优提供者并调用

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

  image

  左侧为服务消费者,右侧有三个服务提供者。那针对每一个提供者,我们都可以设置权重。设置权重可以理解为,他请求所占的百分比。比如说呢,第一台机器权重是2,第二台机器权重是3,第三台机器权重就是5。在 Dubbo 内部会将所有的权重进行相加,相加的和应该等于10。
  那这样一来,第1号机器它所占的数据区间就应该是0-2,那接着,第二台机器所占的区间就应该是2-5。那第三台机器所占的区间就应该是5-10。不同服务器,不同的服务提供者,不同的服务提供者,他占用的数字区间是不一样的。
  由于3号机器权重设置了5,所以它占用的数字区间是最大的。那么接下来随机的时候,它会以权重的和为基数进行随机。随机一个值,如果说落在了0-2,就去访问1号提供者。如果落在了2-5,就会访问2号提供者。如果随机的值落在了5-10,就会访问3号提供者。
  Random 虽然叫做随机,但是并不是真正意义上的每个人占1/3的几率。还会跟权重进行挂钩。当然你的权重越高,随机到你的概率就会越大。
  • RoundRobin :按权重轮询

  image

  将所有服务器权重相加,按权重比例轮询,如1号、2号、3号服务器权重比为2:3:5,访问10次,1号2次、2号3次、3号5次。

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

  image

  服务消费者调用服务提供者的时候,可能存在高并发的这种情况。如果说调用1号机器的时候,同时有3个人调用,2号机器同时有两个人在调用,而3号机器只有一个人在调用。他会去查看每一个服务器,看一下内部同时调用的数量。如果这台机器同时调用的数量较少,他认为这台机器的性能较高,因为它同时的处理能力更强。所以接着把请求发送到这台机器上。
  当然,你发送过来之后,这个同时调用的数量就变成2。
  • ConsistentHash:一致性 Hash,相同参数的请求总是发到同一提供者。

  image

  相同参数的请求,会发送到同一个提供者上。如果我们设置成了一致性哈希,当服务消费者和服务提供者进行请求的时候,就会根据某一项参数进行绑定。比如说,我们要查询 user 等于1的用户,我们就可以用1来进行绑定。
  那这样,后续查询所有用户等于1的,都会分配到1号服务提供者上。
  那你要查询用户等于2,都会分配到2号,如果大于等于3都会分配到3号。

可通过@DubboReference 的loadbalance进行设置。

image

 

posted @ 2025-07-28 23:06  溯鸣  阅读(52)  评论(0)    收藏  举报