微服务之Dubbo

前言

Dubbo是为了解决公司内部服务之前高效调用的一种框架,它是采用RPC调用(提供高效的序列化方式网络基于Netty/Sockket,长连接内网调用链路短、安全、不需要请求头、拼接Body)。

Dubbo的架构

在这里插入图片描述

  • privider:服务提供者 。在启动的时候会将(服务名称、版本号、P地址、媏口号、协议、权重等交给注册中心)
  • consumer:服务消费者
  • registry:注册中心
  • Monitor:监控 (调用次数、调用时间、响应时间、异常次数、异常信息等)

RPC和HTTP的区别?各自适合使用的场景?

  • RPC和HTTP的区别
    • 通信方式:
      • RPC:允许程序调用另一个地址空间(通常是另一台计算机上)的过程或方法,就像调用本地函数一样。RPC隐藏了网络通信的复杂性,提供了透明的远程调用机制。
      • HTTP:基于请求-响应模式,是一种无状态的协议,主要用于Web通信,通过文本格式(如HTML、JSON、XML)传输数据。
    • 数据传输效率:
      • RPC:通常使用二进制格式传输数据,减少了数据冗余,提高了传输效率。同时,支持HTTP/2等高效协议,具备多路复用、头部压缩等特性。
      • HTTP:使用文本格式传输数据,数据冗余较大,传输效率相对较低。虽然HTTP/2也引入了头部压缩和多路复用等特性,但在某些场景下仍不如RPC高效。
    • 接口定义与类型安全:
      • RPC:使用IDL(接口定义语言)来描述接口,如Protocol Buffers(Protobuf),具有更强的类型安全性和跨语言支持。
      • HTTP:接口定义通常遵循RESTful规范或使用OpenAPI等描述语言,类型安全性较弱,但跨平台、跨语言能力强。
    • 异常处理:
      • RPC:通常使用自定义的异常处理机制,可以更细粒度地处理各种异常情况
      • HTTP:使用HTTP状态码来表示请求的状态,如200表示成功,404表示资源不存在等。
    • 适用场景:
      • RPC:主要用于分布式系统内部的服务间调用,适用于构建高性能、低延迟的微服务架构。
      • HTTP:主要用于Web应用、API接口、移动应用、物联网和大数据等领域的数据传输,支持跨平台、跨语言的交互。
  • 适用场景
    • 使用RPC的场景:
      • 当需要构建高性能、低延迟的微服务架构时,RPC是更好的选择。因为它提供了高效的远程调用机制,减少了数据传输的冗余,提高了通信效率。
      • 在分布式系统中,当服务需要频繁调用且对性能要求较高时,RPC能够提供更好的性能支持。
      • 当服务间的接口定义需要更强的类型安全性和跨语言支持时,RPC的IDL机制能够满足这些需求。
    • 使用HTTP的场景:
      • Web应用:HTTP是Web应用程序的基石,通过传输HTML、CSS、JavaScript等静态资源文件和API接口等动态资源文件,提供支撑服务器响应用户请求的基础。
      • API接口:在Web应用程序中,API接口是连接前端UI和后端数据的桥梁。HTTP协议的接口设计,可以使不同语言、不同框架的应用程序在接口层面得到统一,以方便数据的交互与共享。
      • 移动应用:移动应用通常都需要与服务器进行数据交互,HTTP协议提供了快速、安全、可靠的数据传输方式。
      • 物联网和大数据:在物联网应用中,传感器和设备可以通过HTTP协议与云服务器进行数据交互。在大数据应用中,HTTP协议可用于数据的传输以及分布式计算结果的返回。
        综上所述,RPC和HTTP各有优缺点,适用于不同的场景。在选择时,需要根据项目的具体需求、性能要求、开发成本等因素进行综合考虑。

泛化调用

  • Dubbo 是一个高性能、轻量级的开源 Java RPC 框架。它提供了三大关键能力:面向接口的远程方法调用、智能负载均衡以及自动服务注册与发现。在 Dubbo 的使用过程中,泛化调用是一个比较特殊且强大的特性,它允许客户端在不依赖服务接口定义(即不需要服务提供方的接口 JAR 包)的情况下,直接通过 Dubbo 框架进行远程服务调用。

  • 泛化调用的背景

    • 在微服务架构中,服务间的依赖管理是一个重要问题。传统方式下,服务消费者需要依赖服务提供者的接口定义(通常是通过 Maven 或 Gradle 等构建工具引入 JAR 包)。但这种方式存在一些问题,比如:
      • 版本冲突:多个服务可能依赖同一服务的不同版本。
      • 依赖管理复杂:随着服务数量的增加,管理这些依赖会变得越来越复杂。
      • 部署灵活性受限:服务的更新和部署可能受到依赖关系的限制。
    • 泛化调用提供了一种解决这些问题的方法,它使得服务消费者可以不依赖于具体的服务接口定义,直接通过 Dubbo 框架的 API 调用远程服务。
  • 泛化调用的实现方式

    • 在 Dubbo 中,泛化调用通常通过 GenericService 接口来实现。GenericService 是一个泛型的接口,它定义了一个 $invoke 方法,该方法接受四个参数:方法名、方法参数类型数组、方法参数值数组以及方法返回值类型(对于没有返回值的方法,这个参数可以为 null)。
  • 泛化调用的优缺点

    • 优点:
      • 解耦:客户端不需要依赖服务提供者的接口定义。
      • 灵活性:可以动态地调用远程服务的方法,无需在编译时确定。
      • 简化部署:减少了因依赖关系导致的部署复杂度。
    • 缺点:
      • 类型安全缺失:由于不依赖具体的接口定义,因此无法享受编译时类型检查的好处
      • 性能开销:相对于直接调用,泛化调用可能存在一定的性能开销。
      • 开发成本:编写和维护泛化调用的代码可能相对复杂和繁琐。

dubbo支持哪些调用协议,每个协议的特点

  1. Dubbo协议
  • 特点:
    • 默认协议:Dubbo框架默认使用的协议。
    • 单一长连接:基于单一长连接和NIO异步通讯,适合小数据量大并发的服务调用。
    • 高效性:在服务消费者机器数远大于服务提供者机器数的情况下表现尤为出色。
    • 限制:不建议用于传输大文件或超大字符串。
  1. RMI协议
  • 特点:
    • Java标准:基于Java RMI(远程方法调用)协议,通过Java对象序列化进行数据传输。
    • 跨平台性:具有较好的跨平台性。
    • 连接方式:采用阻塞式短连接和JDK标准序列化方式。
    • 适用场景:适合消费者与提供者个数相当,需要传输文件等大数据量的场景。
  1. Hessian协议
  • 特点:
    • Hessian序列化:基于Hessian序列化框架,通过HTTP传输数据。
    • 适用场景:服务提供者和消费者在同一JVM进程中的场景,或者需要基于HTTP通信的场景。
    • 内嵌服务器:Dubbo缺省内嵌Jetty作为服务器实现。
  1. HTTP协议
  • 特点:
    • 通用性:基于HTTP协议进行通信,可以通过HTTP客户端与服务端进行通信。
    • 灵活性:支持多种传输方式和数据格式。
    • 适用场景:需同时给应用程序和浏览器JS使用的服务。
  1. WebService协议
  • 特点:
    • 跨语言:基于SOAP规范的Webservice协议,通过XML格式进行数据传输,具有良好的跨语言支持。
      适用场景:系统集成,跨语言调用。
  1. Thrift协议
  • 特点:
    • 高性能:基于Apache Thrift框架,使用自定义的二进制协议进行数据传输,具有较好的性能和跨语言支持。
    • 扩展性:在原生协议的基础上添加了一些额外的头信息,如service name, magic number等。
  1. Memcached协议
  • 特点:
    • 缓存同步:基于Memcached协议实现缓存同步,适用于缓存场景下的服务调用。
  1. Redis协议
  • 特点:
    • 数据存储:基于Redis协议实现数据存储和同步,适用于使用Redis缓存的场景。
  1. Dubbo RESTful协议
  • 特点:
    • RESTful风格:基于Dubbo协议的RESTful风格接口,可以使用HTTP或Websocket进行通信。
  1. Dubbo-gRPC
  • 特点:
    • 高性能RPC:基于gRPC协议的Dubbo实现,gRPC是一个高性能、开源、通用的RPC框架,支持多种编程语言。
    • 提升通信性能:通过Dubbo-gRPC,可以实现基于gRPC协议的服务调用,提高服务间的通信性能。
  1. Dubbo-MQTT
  • 特点:
    • 轻量级消息传输:基于MQTT协议的Dubbo实现,MQTT是一个轻量级的发布/订阅消息传输协议,广泛应用于物联网领域。
    • 适用场景:适用于需要低功耗、低带宽、高可靠性的场景。
      总结
      Dubbo支持的调用协议多种多样,每种协议都有其独特的特点和适用场景。在实际应用中,可以根据服务的需求和场景选择合适的协议进行通信。例如,对于小数据量大并发的服务调用,可以选择Dubbo协议;对于需要跨语言调用的场景,可以选择WebService或Thrift协议;对于缓存场景下的服务调用,可以选择Memcached或Redis协议等。

dubbo的序列化方式

  1. Hessian
  • Hessian是Dubbo默认的序列化方式。
  • 它是一种基于二进制的高性能序列化协议,可以将对象以二进制形式进行编码和解码,并支持跨语言的数据传输。
  • Hessian序列化特别适用于Java环境,但也支持其他语言的实现。
  1. JSON
  • 使用JSON进行序列化,支持多种语言。
  • JSON序列化具有良好的可读性和易用性,是Web开发中常用的数据交换格式。
  • Dubbo中可以使用FastJson等库来实现JSON序列化。
  1. Java原生序列化
  • 使用Java默认的序列化方式进行序列化,仅支持Java语言。
  • 这种序列化方式简单直观,但可能存在性能瓶颈和安全性问题。
  1. Kryo
  • Kryo是一种非常高效的Java序列化框架,速度比Java原生序列化快得多。
  • 它支持多种数据结构和复杂对象的序列化,非常适合需要高性能序列化的场景。
  1. FST
  • FST(Fast Serialization Technology)是另一种Java序列化方式,它也具有较高的序列化性能。
  • FST提供了与Java原生序列化相似的接口,但具有更好的性能和更低的内存消耗。
  1. Protobuf
  • Protobuf(Protocol Buffers)是Google开发的一种轻便高效的结构化数据存储格式,可用于数据通信和存储。
  • Protobuf序列化方式支持多种语言,具有良好的跨平台性和可扩展性。
  1. Avro
  • Avro是一个由Hadoop项目所发展的数据序列化系统,基于二进制数据格式。
    它提供了一种紧凑的、快速的二进制数据格式,支持复杂的数据结构,并且具有良好的跨语言支持。

在选择Dubbo的序列化方式时,需要考虑以下几个因素:

  • 性能:不同的序列化方式在性能上有所差异,需要根据实际需求选择适合的序列化方式。
  • 兼容性:如果需要与其他语言或系统进行数据交换,需要选择具有广泛支持和高兼容性的序列化方式。
  • 安全性:一些序列化方式可能存在安全隐患,需要确保所选的序列化方式符合安全要求。
  • 易用性:考虑序列化方式的易用性和维护成本,选择易于理解和维护的序列化方式。

dubbo的负载均衡策略

  1. 随机(Random)
  • 描述:随机选择一个可用的服务提供者来处理请求。
  • 特点:
    • 简单易用:实现和理解都非常简单,不需要维护复杂的状态信息。
    • 负载均衡:在大流量下能够达到较好的负载均衡效果。
    • 适用场景:适用于服务提供者的性能相差不大的场景。
  1. 轮询(Round Robin)
  • 描述:按顺序轮流选择服务提供者来处理请求。每次请求到达时,系统选择下一个节点,当到达列表末尾时重新从头开始。
  • 特点:
    • 公平性:能够确保每个服务节点被均匀调用,适用于负载较为均衡的场景。
    • 简单实现:无需复杂的状态维护,逻辑简单清晰。
    • 适用场景:适用于服务提供者的性能相近且需要均匀分配请求的场景。
  1. 最少活跃调用数(Least Active)
  • 描述:选择当前活跃调用数(即正在处理请求的线程数)最小的服务提供者来处理请求。
  • 特点:
    • 负载敏感:能够选择负载最轻的服务提供者,提高系统的整体响应速度。
    • 高效性:在服务提供者性能不均的场景下,能有效提高系统处理效率。
    • 适用场景:适用于对系统负载比较敏感的场景,能够确保请求被分配给负载较轻的服务提供者。
  1. 一致性哈希(Consistent Hash)
  • 描述:基于调用参数的哈希值来选择服务提供者,确保相同参数的请求始终由同一个服务节点处理。
  • 特点:
    • 会话粘性:保证相同参数的请求由同一个服务节点处理,适用于需要会话保持的应用场景。
    • 平滑扩展:增加或移除节点时,影响的请求最少,具有较好的扩展性。
    • 适用场景:特别适用于需要会话粘性或数据分片的场景,如分布式缓存系统和分布式数据库。
  1. 加权随机(WeightedRandom)
  • 描述:根据服务提供者的权重来随机选择服务提供者。权重越高的服务提供者被选中的概率越大。
  • 特点:
    • 灵活性高:可以根据服务提供者的性能差异来设置不同的权重,实现更精细化的负载均衡。
    • 易于扩展:可以方便地添加自定义的权重计算逻辑。
    • 适用场景:适用于服务提供者性能差异较大,且需要根据性能差异来分配请求的场景。
  1. 加权轮询(WeightedRoundRobin)
  • 描述:按照服务提供者的权重进行轮询选择。权重越大的服务提供者被轮询到的次数越多。
  • 特点:
    • 公平性:在加权的基础上实现了请求的均匀分配。
    • 高效性:能够确保高性能的服务提供者处理更多的请求。
    • 适用场景:与加权随机类似,但更适用于需要更公平地分配请求的场景。

Dubbo的缓存机制

  1. 服务端缓存方式
  • 在服务端,Dubbo支持通过本地缓存来缓存服务响应结果。这种缓存方式将服务响应数据直接存储在服务提供者的内存中,以便快速响应后续的相同请求。
  • 实现方式
    • 本地缓存:Dubbo提供了本地缓存的实现方式,即通过Dubbo的Cache接口或@Cache注解在服务方法上启用缓存。当服务方法被调用时,Dubbo会检查缓存中是否存在相应的响应结果。如果存在,则直接从缓存中返回结果,避免重复的计算和数据库查询等操作。
    • 配置方式:在服务提供方的服务方法上添加@Cache注解,可以启用本地缓存机制,并指定缓存的大小、过期时间等参数。此外,也可以通过XML配置文件或API配置方式来配置缓存。
  • 优点
    • 速度快:由于缓存数据存储在本地内存中,因此能够快速读取响应结果,减少不必要的计算和网络通信开销。
    • 自适应:Dubbo的本地缓存会根据服务的调用频率和内存使用情况等动态调整缓存的大小,以适应不同的场景。
  • 缺点
    • 数据一致性:当服务提供方的数据发生变化时,缓存的数据可能不是最新的,存在数据一致性问题。
    • 内存开销:本地缓存对内存的消耗较大,需要合理设置缓存大小以避免内存溢出。
  1. 客户端缓存方式
  • 在客户端,Dubbo同样支持缓存服务调用的结果。这种缓存方式将服务调用的响应结果缓存在服务消费方的内存中,以减少网络通信和服务提供方的负载。
  • 实现方式
    • 本地缓存:与服务端类似,客户端也可以通过本地缓存来实现服务调用结果的缓存。Dubbo提供了相应的配置方式和注解来支持这一功能。
    • 分布式缓存:除了本地缓存外,客户端还可以选择使用分布式缓存来存储服务调用结果。分布式缓存将缓存数据存储在独立的缓存服务器上,如Redis、Memcached等,客户端通过网络访问这些缓存服务器来获取缓存数据。
  • 优点
    • 减少网络通信:通过缓存服务调用的结果,可以减少客户端与服务端之间的网络通信次数,降低网络延迟和负载。
    • 提高系统性能:缓存可以减少服务端的计算和数据库查询压力,提高整个系统的响应速度和性能。
  • 缺点
  • 数据一致性:与服务端缓存类似,客户端缓存也存在数据一致性问题。当服务端数据发生变化时,需要确保缓存中的数据能够及时更新。
  • 缓存失效:缓存数据需要设置合理的过期时间,以避免缓存失效导致的数据不一致问题。

dubbo的异步调用

import org.apache.dubbo.config.annotation.DubboReference;  
import org.apache.dubbo.rpc.RpcContext;  
import org.springframework.stereotype.Component;  
  
import java.util.concurrent.CompletableFuture;  
  
@Component  
public class GreetingConsumer {  
  
    @DubboReference(async = true) // 注意这里启用异步  
    private GreetingService greetingService;  
  
    public void asyncSayHello(String name) {  
        // 使用CompletableFuture来接收异步结果  
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  
            // 这里实际上Dubbo会处理异步逻辑,我们只是将调用放入CompletableFuture中  
            return greetingService.sayHello(name);  
        }, RpcContext.getContext().getCompletableFutureExecutor()); // 使用Dubbo提供的线程池  
  
        // 处理异步结果  
        future.whenComplete((result, throwable) -> {  
            if (throwable != null) {  
                throwable.printStackTrace();  
                System.out.println("Failed to get response");  
            } else {  
                System.out.println("Response: " + result);  
            }  
        });  
  
        // 注意:这里不会阻塞,你可以继续执行其他任务  
        System.out.println("Async call sent. Waiting for response...");  
  
        // 如果需要,可以在这里执行其他任务  
        // ...  
    }  
}

Dubbo SPI

  1. Dubbo SPI 的主要特点
  • 自动装配:Dubbo SPI 可以在运行时自动加载和装配服务实现。
  • 扩展点加载:支持通过配置文件或注解来指定扩展点的实现。
  • 依赖注入:支持将其他扩展点作为依赖注入到当前扩展点中。
  • 自适应扩展:支持自适应扩展,即根据 URL 参数自动选择最合适的扩展实现。
  1. Dubbo SPI 的实现原理
    Dubbo SPI 的实现主要依赖于以下几个关键组件:
  • ExtensionLoader:这是 Dubbo SPI 的核心类,负责加载和管理扩展点。它提供了加载扩展点、获取扩展点实现、创建自适应扩展等功能。
  • META-INF/dubbo/ 目录下的配置文件:Dubbo 通过扫描这个目录下的配置文件来发现扩展点及其实现。配置文件通常以扩展点的全限定名命名,内容则是该扩展点实现的键值对。
  • @SPI 注解:Dubbo 允许通过 @SPI 注解来定义扩展点,但这不是必须的,因为也可以通过配置文件来定义扩展点。
  • @Adaptive 注解:用于标记自适应扩展实现。Dubbo 会根据这个注解来生成自适应扩展类的字节码。

示例
假设我们有一个扩展点接口 Protocol,我们想要通过 Dubbo SPI 机制来加载它的不同实现。

  • 定义扩展点接口:
@SPI("dubbo")  
public interface Animal {  
    void eat(); 
}

这里使用 @SPI(“dubbo”) 注解来定义扩展点,并指定了默认的扩展实现是 dubbo。

  • 实现扩展点
public class DogAnimal implements Animal {  
    // 实现方法...  
}  

public class PigAnimal implements Animal {  
    // 实现方法...  
}
  • 配置扩展实现
    在 META-INF/dubbo/org.apache.dubbo.rpc.Protocol 文件中配置扩展实现:
dog=com.tiechui.dubbo.rpc.Animal.DogAnimal  
pig=com.tiechui.dubbo.rpc.Animal.PigAnimal
  • 加载和使用扩展
ExtensionLoader<Animal> loader = ExtensionLoader.getExtensionLoader(Animal.class);  
Animal animal = loader.getExtension("dubbo");  
// 使用 Animal 对象...

dubbo支持的服务治理

  1. 服务注册与发现
    管理服务的注册与动态发现。服务提供者启动时向注册中心注册自己的服务,服务消费者启动时向注册中心订阅所需的服务。注册中心会实时推送服务地址列表给消费者,并在有变更时更新信息。
  2. 负载均衡
    在多个服务提供者之间进行负载均衡,以提高系统的性能和资源利用率。Dubbo支持多种负载均衡算法,如轮询、加权轮询、最小连接数和加权最小连接数等。
  3. 故障转移
    在服务调用失败时,提供故障转移机制,以保障系统的可用性。Dubbo内置了多种容错机制,如Failover(失败自动切换)、Failfast(快速失败)、Failsafe(失败安全)、Failback(失败自动恢复)等,可以根据需要选择合适的容错策略。
  4. 服务监控
    监控服务调用次数、调用时间等信息,帮助开发者了解服务的运行状况。Dubbo提供了监控和治理控制台,可以实时监控服务的运行状态和性能指标。
  5. 路由规则
    根据规则路由调用请求到指定服务。Dubbo支持灵活的路由规则配置,可以根据服务提供者的状态和性能选择合适的调用路径,优化服务调用的效率和响应时间。
  6. 配置管理
    动态配置服务参数,实现配置的动态更新和版本控制。开发者可以通过Dubbo的配置中心对服务的参数进行动态调整,而无需重启服务。
  7. 服务降级
    在服务不可用或性能下降时,提供备用方案,保障核心业务的正常运行。服务降级是一种在极端情况下保护系统稳定性的重要手段。
  8. 动态配置与治理
    Dubbo支持动态配置管理,允许在运行时动态调整服务的参数、权重、路由规则等,以适应不同的业务场景和需求。
  9. 支持多种注册中心
    Dubbo支持多种注册中心,如ZooKeeper、Consul、Nacos等,开发者可以根据自己的需求选择合适的注册中心进行服务注册和发现。
  10. 支持微服务架构
    Dubbo广泛应用于微服务架构中,通过其服务治理功能帮助开发者快速构建和管理分布式应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值