Dubbo 学习

本文深入介绍了Apache Dubbo,一个高性能的Java RPC框架,详细讲解了其架构概述、处理流程、服务注册中心Zookeeper的使用。接着探讨了Dubbo中的SPI机制,包括JDK的SPI和Dubbo的扩展点实现方式,以及Adaptive功能。此外,还涵盖了Dubbo的负载均衡策略、异步调用、线程池管理和路由规则。最后,通过一个简易的Dubbo方法级性能监控实战案例,展示了如何利用Filter进行性能监控和TP90、TP99的计算。
摘要由CSDN通过智能技术生成

一、Dubbo 架构概述

1.1 什么是Dubbo

Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。

1.2 dubbo 的特性

提供了六大核心能力:面向接口代理的高性能RPC调用,智能容错和负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维。

二、 Dubbo 处理流程

在这里插入图片描述

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

调用关系说明

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

Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。

三、服务注册中心Zookeeper

通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的用。Dubbo官方推荐使用Zookeeper作为服务注册中心。Zookeeper 是 Apache Hadoop 的子项目,作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。

四、Dubbo高级实战

1、SPI

1.1 SPI简介

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。 目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现的机制。使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。

1.2 JDK中的SPI

在这里插入图片描述
Java中如果想要使用SPI功能,先提供标准服务接口,然后再提供相关接口实现和调用者。这样就可以通过SPI机制中约定好的信息进行查询相应的接口实现。

SPI遵循如下约定:

  1. 当服务提供者提供了接口的一种具体实现后,在META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
  2. 接口实现类所在的jar包放在主程序的classpath中;
  3. 主程序通过java.util.ServiceLoader动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM; 4、SPI的实现类必须携带一个无参构造方法;
 public static void main(String[] args) {
   
        final ServiceLoader<HelloService> helloServices  = ServiceLoader.load(HelloService.class);
        for (HelloService helloService : helloServices){
   
            System.out.println(helloService.getClass().getName() + ":" + helloService.sayHello());
        }
    }

1.3 Dubbo中的SPI

dubbo中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。比如比较常见的协议,负载均衡,都可以通过SPI的方式进行定制化,自己扩展。Dubbo中已经存在的所有已经实现好的扩展点。
在这里插入图片描述

1.4 Dubbo中扩展点使用方式

我们使用三个项目来演示Dubbo中扩展点的使用方式,一个主项目main,一个服务接口项目api,一个服务实现项目impl。

api项目创建
(1)导入坐标 dubbo
(2)创建接口
在接口上 使用@SPI

impl项目创建
(1)导入 api项目 的依赖
(2)建立实现类,为了表达支持多个实现的目的,这里分别创建两个实现。分别为HumanHelloService 和 DogHelloService 。
(3)SPI进行声明操作,在 resources 目录下创建目录 META-INF/dubbo 目录,在目录下创建名称为com.lagou.dubbo.study.spi.demo.api.HelloService的文件,文件内部配置两个实现类名称和对应的全限定名:

human=com.lagou.service.impl.HumanHelloService
dog=com.lagou.service.impl.DogHelloService

main项目创建
(1)导入坐标 接口项目 和 实现类项目
(2)创建DubboSpiMain
和原先调用的方式不太相同, dubbo 有对其进行自我重新实现 需要借助ExtensionLoader,创建新的运行项目。

  public static void main(String[] args) {
   
        // 获取扩展加载器
        ExtensionLoader<HelloService>  extensionLoader  = ExtensionLoader.getExtensionLoader(HelloService.class);
        // 遍历所有的支持的扩展点 META-INF.dubbo
        Set<String>  extensions = extensionLoader.getSupportedExtensions();
        for (String extension : extensions){
   
            String result = extensionLoader.getExtension(extension).sayHello();
            System.out.println(result);
        }

    }

(3)dubbo自己做SPI的目的

  1. JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加 载,会很浪费资源
  2. 如果有扩展点加载失败,则所有扩展点无法使用
  3. 提供了对扩展点包装的功能(Adaptive),并且还支持通过set的方式对其他的扩展点进行注入

1.5 Dubbo SPI中的Adaptive功能

Dubbo中的Adaptive功能,主要解决的问题是如何动态的选择具体的扩展点。通过getAdaptiveExtension 统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行动态选择。 (dubbo中所有的注册信息都是通过URL的形式进行处理的。)

这里同样采用相同的方式进行实现。
(1)创建接口
api中的 HelloService 扩展如下方法, 与原先类似,在sayHello中增加 Adaptive 注解,并且在参数中提供URL参数.注意这里的URL参数的类为 org.apache.dubbo.common.URL
其中@SP可以指定一个字符串参数,用于指明该SPI的默认实现。

@SPI("human")
public interface HelloService {
   
    String  sayHello();
    @Adaptive
    String  sayHello(URL  url);
}

(2)创建实现类
与上面Service实现类代码相似,只需增加URL形参即可
(3)编写DubboAdaptiveMain
最后在获取的时候方式有所改变,需要传入URL参数,并且在参数中指定具体的实现类参数如:

public class DubboAdaptiveMain {
   
 public static void main(String[] args) {
    
   URL url = URL.valueOf("test://localhost/hello?hello.service=dog");
   final HelloService adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension(); 
   adaptiveExtension.sayHello(url); 
  } 
  }

注意:

  • 因为在这里只是临时测试,所以为了保证URL规范,前面的信息均为测试值即可,关键的点在于hello.service 参数,这个参数的值指定的就是具体的实现方式。关于为什么叫hello.service 是因为这个接口的名称,其中后面的大写部分被dubbo自动转码为 . 分割。
  • 通过 getAdaptiveExtension 来提供一个统一的类来对所有的扩展点提供支持(底层对所有的扩展点进行封装)。
  • 调用时通过参数中增加 URL 对象来实现动态的扩展点使用。
  • 如果URL没有提供该参数,则该方法会使用默认在 SPI 注解中声明的实现。

1.6 Dubbo调用时拦截操作

与很多框架一样,Dubbo也存在拦截(过滤)机制,可以通过该机制在执行目标程序前后执行我们指定的代码。Dubbo的Filter机制,是专门为服务提供方和服务消费方调用过程进行拦截设计的,每次远程方法执行,该拦截都会被执行。这样就为开发者提供了非常方便的扩展性,比如为dubbo接口实现ip白名单功能、监控功能 、日志记录等。

@Activate(group = {
   CommonConstants.CONSUMER,CommonConstants.PROVIDER})
public class DubboInvokeFilter   implements Filter {
   
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
   
        long   startTime  = System.currentTimeMillis();
        try {
   
            // 执行方法
            
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值