高性能Java RPC 框架----Dubbo

Dubbo 简介

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

  • 面向接口代理的高性能RPC调用: 提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节
  • 智能负载均衡: 内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量
  • 服务自动注册与发现: 支持多种注册中心服务,服务实例上下线实时感知
  • 高度可扩展能力: 遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三方实现
  • 运行期流量调度: 内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能
  • 可视化的服务治理与运维: 提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数

Dubbo 设计架构

高性能Java RPC 框架----Dubbo_第1张图片
  服务发现的一个核心组件是注册中心,Provider 注册地址到注册中心,Consumer 从注册中心读取和订阅 Provider 地址列表。

Dubbo注册中心 Zookeeper

  Dubbo目前支持的注册中心有nacos、zookeeper、multicast、redis、simple,当然官方还是推荐使用zookeeper作为注册中心,所以本文使用zookeeper进行演示。相关的安装教程可以参考 服务注册与发现-Zookeeper(二)

Dubbo 监控中心

Dubbo Admin

  监控中心可以帮助用户通过可视化界面管理和维护众多的服务,可以通过可视化界面很直观的查看各个服务的情况,下载地址:https://github.com/apache/dubbo-admin,目前支持docker快速部署,或者你也可以通过运行源码或手动打包部署,本文演示手动打包部署到Linux系统中。注意:监控中心目前不兼容3.0+版本,本文仅做演示,可能后期会出兼容的版本
  1. 从github 上下载源码

git clone https://github.com/apache/dubbo-admin.git

  2. 在 \dubbo-admin\dubbo-admin-server\src\main\resources 目录下修改配置文件指定注册中心地址

# 配置zookeeper地址
admin.registry.address=zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
admin.config-center=zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181
admin.metadata-report.address=zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181

  3. 在dubbo-admin 根目录进行打包

mvn clean package -Dmaven.test.skip=true

  4. 运行,监控中心可以通过源码启动,也可以通过打包后的jar启动
方式1:源码启动
  监控中心是前后端分离开发的,所以源码启动时需要前后端分开启动

# 启动前端,dubbo-admin-ui 为前端源码
npm install # 安装依赖
npm run dev

# 启动后端,dubbo-admin-server 为后端源码
# 通过编译器或者mvn命令进行启动
mvn spring-boot:run

  启动后访问8082端口:http://localhost:8082/,默认用户名和密码都为 root

方式2:打包部署
  将步骤三打包后的jar包上传到服务器进行启动,打包后的文件已经默认集成了UI

java -jar dubbo-admin-server-0.4.0.jar

  启动后访问8080端口,默认用户名和密码都为 root
高性能Java RPC 框架----Dubbo_第2张图片

Dubbo Monitor Simple

  Dubbo Monitor Simple主要用户监控服务调用,例如进行统计等操作查询。下载地址:https://github.com/apache/dubbo/tree/2.5.x/dubbo-simple,注意是2.5.x分支,其他分支已经没有这个项目了,不知道新版本能不能支持它。
高性能Java RPC 框架----Dubbo_第3张图片
  1. 将整个dubbo克隆到本地

# 克隆项目
git clone https://github.com/apache/dubbo.git
# 切换到2.5.x分支
git checkout 2.5.x

  2. 在 \dubbo\dubbo-simple\dubbo-monitor-simple 目录下将项目进行打包,打包之前,也可以先进行修改配置:\dubbo\dubbo-simple\dubbo-monitor-simple\src\main\assembly\conf\dubbo.properties

# 打包
mvn clean package -Dmaven.test.skip=true

  3. 打包完成,在target目录,注意,打包后的文件是dubbo-monitor-simple-2.5.10-assembly.tar.gz 而不是jar,直接运行jar是跑不起来的,接下来就将压缩包进行解压,如果你在上一步没有修改配置,需要在此修改配置,在conf目录下修改dubbo.properties
高性能Java RPC 框架----Dubbo_第4张图片

# 注册中心地址
dubbo.registry.address=zookeeper://192.168.0.132:2181?backup=192.168.0.133:2181,192.168.0.134:2181
# 其他服务与监控中心的通信端口
dubbo.protocol.port=7070
# 监控中心web访问端口
dubbo.jetty.port=8081

  4. 启动,在bin目录下已经写好的了启动脚本
高性能Java RPC 框架----Dubbo_第5张图片
  5. 服务配置,需要在服务中配置 dubbo:monitor 节点,具体的参考下一节


<dubbo:monitor protocol="registry"/> 

  6. 访问web页面,启动后在浏览器中进行访问:http://localhost:8081/
高性能Java RPC 框架----Dubbo_第6张图片

Dubbo 入门案例

服务提供者

  1. 导入jar包


<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubboartifactId>
    <version>3.0.7version>
dependency>

<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-dependencies-zookeeperartifactId>
    <version>3.0.7version>
    <type>pomtype>
dependency>

  2. 配置服务提供者,在资源目录下创建 provider.xml 文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
    
    <dubbo:application name="dubbo-provider-demo"/>
    
    <dubbo:registry protocol="zookeeper" address="192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181"/>
    
    <dubbo:protocol name="dubbo" port="20881"/>
    
    <dubbo:service interface="com.hxz.dubbo.service.IProviderDemoService" ref="prodiverDemoService"/>
    
    <bean id="prodiverDemoService" class="com.hxz.dubbo.service.ProdiverDemoService"/>
    
    <dubbo:monitor protocol="registry"/> 
    
beans>

  3. 启动,由于使用的是普通maven项目,需要使用上下文进行启动

public static void main(String[] args) throws IOException {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
    context.start();
    System.in.read();
}

  4. 测试服务提供者,在监控中心的控制页面,可以看到服务提供者已经注册到dubbo里面了
高性能Java RPC 框架----Dubbo_第7张图片

服务消费者

  1. 导入jar包


<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubboartifactId>
    <version>3.0.7version>
dependency>

<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-dependencies-zookeeperartifactId>
    <version>3.0.7version>
    <type>pomtype>
dependency>

  2. 配置服务消费者,在资源目录下创建 consumer.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    
    <context:component-scan base-package="com.hxz.dubbo.service"/>
    
    <dubbo:application name="dubbo-consumer-demo"/>
    
    <dubbo:registry address="zookeeper://192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181"/>
    
    <dubbo:consumer timeout="3000"/>
    
    <dubbo:reference id="providerService" interface="com.hxz.dubbo.service.IProviderDemoService"/>
    
    <dubbo:monitor protocol="registry"/> 
    
beans>

  3. 测试,消费者去远程调用服务提供者,相关的接口代码请查看Gitee源码

public static void main(String[] args) throws IOException {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
    context.start();
    ConsumerDemoService service = context.getBean(ConsumerDemoService.class);
    List<DemoEntity> list = service.list();
    list.forEach(System.out::println);
    System.in.read();
}

高性能Java RPC 框架----Dubbo_第8张图片

SpringBoot 整合 Dubbo

服务提供者

  1. 导入jar,我是用的是apache的整合包而不是alibaba的整合包,注意两者区别还是挺大的,alibaba的整合包网上的教程还是挺多,但是apache的整合包教程就很少


<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-spring-boot-starterartifactId>
    <version>3.0.7version>
dependency>

<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-dependencies-zookeeperartifactId>
    <version>3.0.7version>
    <type>pomtype>
    <exclusions>
        <exclusion>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
        exclusion>
    exclusions>
dependency>

  2. 配置dubbo

server:
  port: 8001
spring:
  application:
    name: dubbo-provider-boot-demo

dubbo:
  # 应用相关
  application:
    name: ${spring.application.name}  # dubbo 应用名称
  # 注册中心相关
  registry:
    protocol: zookeeper  # 注册协议 zookeeper  nacos multicast redis
    address: 192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181  # 注册地址
    register: true
  # 通信规则
  protocol:
    name: dubbo  # 通信协议
    port: 20881  # 通信端口
  # 监控中心
  monitor:
    protocol: register  # 协议

  3. 测试demo接口代码

@Service
@DubboService(group = "${spring.application.name}",version = "1.0.0")  // 暴露服务, 注意目前3.0+版本需要指定组和版本,否则在web控制中心会莫名其妙的不显示了
public class ProdiverDemoService implements IProviderDemoService {
    @Override
    public List<DemoEntity> list() {
        return Arrays.asList(new DemoEntity(UUID.randomUUID().toString().replace("-", ""), "张三", new Random().nextInt(100)),
                new DemoEntity(UUID.randomUUID().toString().replace("-", ""), "李四", new Random().nextInt(100)),
                new DemoEntity(UUID.randomUUID().toString().replace("-", ""), "王五", new Random().nextInt(100)));
    }
}

  4. 开启dubbo功能并启动测试,使用 @EnableDubbo 注解开启,启动后在web控制中心可以看到注册的服务

@SpringBootApplication
@EnableDubbo // 开启dubbo功能
public class DubboProviderBootDemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DubboProviderBootDemoApplication.class, args);
	}
}

高性能Java RPC 框架----Dubbo_第9张图片

服务消费者

  1. 导入jar包


<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-spring-boot-starterartifactId>
    <version>3.0.7version>
dependency>

<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-dependencies-zookeeperartifactId>
    <version>3.0.7version>
    <type>pomtype>
    <exclusions>
        <exclusion>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
        exclusion>
    exclusions>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

  2. 配置dubbo

server:
  port: 8002
spring:
  application:
    name: dubbo-consumer-boot-demo
dubbo:
  # 应用相关
  application:
    name: ${spring.application.name} # dubbo 应用名称
  # 注册中心相关
  registry:
    protocol: zookeeper  # 注册协议 zookeeper  nacos multicast redis
    address: 192.168.0.132:2181,192.168.0.133:2181,192.168.0.134:2181  # 注册地址
    register: true
  # 监控中心
  monitor:
    protocol: register  # 协议

  3. 通过 @DubboReference 调用远程,注意:调用远程接口的组和版本如果配置了就要保持一致

@Service
public class ConsumerDemoService implements IConsumerDemoService {
    @DubboReference(group = "dubbo-provider-boot-demo",version = "1.0.0") // 远程调用服务
    private IProviderDemoService providerService;

    @Override
    public List<DemoEntity> list() {
        return providerService.list();
    }
}

  4. 开启dubbo功能进行测试

@SpringBootApplication
@EnableDubbo // 开启dubbo功能
public class DubboConsumerBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboConsumerBootDemoApplication.class, args);
    }
}

  通过postman调用controller接口,成功获取返回值
高性能Java RPC 框架----Dubbo_第10张图片

Dubbo 高可用

1. 注册中心宕机

  当注册中心宕机后,经过测试发现,还可以消费dubbo暴露的服务;服务提供者和消费者可以通过本地缓存通信,即当消费者调用了一次提供者,会在消费者本地缓存提供者的详细信息,因此注册中心宕机后可以跳过注册中直接调用提供者。除此之外,其他的如监控中心宕机也不影响

  • 监控中心宕机不影响使用,只会丢失部分采样数据
  • 数据库宕机后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心集群中任意宕机一台,会自动切换到另一台
  • 注册中心全部宕机后,服务提供者和消费者可以通过本地缓存通信
  • 服务提供者无状态,任意一台宕机后,不影响使用
  • 服务提供者全部宕机后,服务消费者将无法使用,并无限次重连等待服务提供者恢复

Dubbo 直连

  Dubbo 直连可以绕过注册中心,即不使用注册中心直接调用dubbo的其他服务,通过 @DubboReferenceurl 属性直接连接服务提供者的通信地址
  注意:使用dubbo直连时,需要将注册中心相关的配置注释掉,并且不建议在生产环境使用

@Service
public class ConsumerDemoService implements IConsumerDemoService {
    @DubboReference(group = "dubbo-provider-boot-demo", version = "1.0.0",url = "127.0.0.1:20881") // 远程调用服务, 直接连接服务提供者
    private IProviderDemoService providerService;

    @Override
    public List<DemoEntity> list() {
        return providerService.list();
    }
}

Dubbo负载均衡

  集群模式下,Dubbo提供了多种负载均衡策略,默认为Random 随机调用。

算法 特性 备注
RandomLoadBalance 加权随机 默认算法,默认权重相同
RoundRobinLoadBalance 加权轮询 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同
LeastActiveLoadBalance 最少活跃优先 + 加权随机 背后是能者多劳的思想
ShortestResponseLoadBalance 最短响应优先 + 加权随机 更加关注响应速度
ConsistentHashLoadBalance 一致性 Hash 确定的入参,确定的提供者,适用于有状态请求

Random

  • 加权随机,按权重设置随机概率。
  • 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
  • 缺点:存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

RoundRobin

  • 加权轮询,按公约后的权重设置轮询比率,循环调用节点
  • 缺点:同样存在慢的提供者累积请求的问题。

LeastActive

  • 加权最少活跃调用优先,活跃数越低,越优先调用,相同活跃数的进行加权随机。活跃数指调用前后计数差(针对特定提供者:请求发送数 - 响应返回数),表示特定提供者的任务堆积量,活跃数越低,代表该提供者处理能力越强。
  • 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大;相对的,处理能力越强的节点,处理更多的请求。

ShortestResponse

  • 加权最短响应优先,在最近一个滑动窗口中,响应时间越短,越优先调用。相同响应时间的进行加权随机。
  • 使得响应时间越快的提供者,处理更多的请求。
  • 缺点:可能会造成流量过于集中于高性能节点的问题。

ConsistentHash

  • 一致性 Hash,相同参数的请求总是发到同一提供者。
  • 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
  • 算法参见:Consistent Hashing | WIKIPEDIA
  • 缺省只对第一个参数 Hash,如果要修改,请配置
  • 缺省用 160 份虚拟节点,如果要修改,请配置
    高性能Java RPC 框架----Dubbo_第11张图片
    在这里插入图片描述
      从源码中我们可以查到dubbo默认的负载均衡机制是随机(random),Apache 为我们提供了5种机制
    示例:服务提供者
// 注解方式
@DubboService(group = "${spring.application.name}",version = "1.0.0",loadbalance = "leastactive")  // 暴露服务.// 轮询值loadbalance :consistenthash leastactive random roundrobin shortestresponse
public class ProdiverDemoService implements IProviderDemoService {}

// xml 配置方式
<!-- 暴露的接口服务,ref指向服务的实现 轮询值loadbalance :consistenthash leastactive random roundrobin shortestresponse -->
<dubbo:service interface="com.hxz.dubbo.service.IProviderDemoService" ref="prodiverDemoService" loadbalance="leastactive"/>

示例:服务消费者

// 注解方式
// 轮询值loadbalance :consistenthash leastactive random roundrobin shortestresponse
@DubboReference(group = "dubbo-provider-boot-demo", version = "1.0.0",loadbalance = "roundrobin") // 远程调用服务
private IProviderDemoService providerService;

// xml 配置
<!-- 声明需要调用的远程服务接口, 生成远程服务的代理 轮询值loadbalance :consistenthash leastactive random roundrobin shortestresponse -->
<dubbo:reference id="providerService" interface="com.hxz.dubbo.service.IProviderDemoService" loadbalance="consistenthash"/>

  关于更多的用法可以参考官方文档:https://dubbo.apache.org/zh/docs/advanced/
  源码地址:https://gitee.com/peachtec/hxz-study

你可能感兴趣的:(dubbo,dubbo)