大家好,我是哪吒。
面试中被问到dubbo,我觉得可以从以下10点着手回答,堪称完美!
Dubbo是一个高性能的Java RPC框架。RPC是远程过程调用的缩写,其基本思想是:客户端像调用本地方法一样,通过网络请求调用远程服务器上的服务。Dubbo可以帮助我们更方便地构建分布式应用程序,它具有高效的远程调用、服务自动注册和发现、负载均衡、容错机制等众多特性,是企业级应用中可靠的基础架构。
一、介绍
1、Dubbo是什么
Dubbo是一种高性能、轻量级的分布式服务框架,它的设计目标是为大规模分布式应用提供支持。
Dubbo由阿里巴巴提供,最初由Alibaba Dubbo Team开发,目前已经成为Apache基金会的顶级项目。Dubbo在国内得到了广泛的应用,像阿里巴巴、京东、美团等众多互联网企业都在使用该框架。
图片
2、为什么需要Dubbo
在分布式系统中,服务之间相互依赖非常复杂,需要大量的通信和协调。Dubbo可以帮助我们更方便地构建分布式应用程序,它具有高效的远程调用、服务自动注册和发现、负载均衡、容错机制等众多特性。通过Dubbo,我们可以更方便地实现服务治理、服务调用链追踪、服务降级、服务熔断等重要功能。
3、Dubbo的特性
Dubbo最重要的特性包括:
- 高效的远程调用,支持多种传输协议、序列化协议和集群容错机制;
- 可扩展的服务自动发现,支持多种注册中心;
- 丰富的负载均衡策略,支持轮询、随机、最少活跃调用等多种策略;
- 灵活的集群容错机制,支持多种容错策略;
- 多协议支持,Dubbo同时支持dubbo://、http://和hessian://等多种协议。
二、Dubbo的核心概念
1、暴露Export
Dubbo的暴露和引用是通过ProviderConfig和ConsumerConfig实现的。
ProviderConfig是服务提供者配置类,可以用于配置服务的接口、服务实现类、协议等,还可以设置暴露服务所用的协议、权重、端口号等信息。
ConsumerConfig是服务消费者配置类,可以用于配置服务消费者所接口、协议等信息,还可以设置引用服务所用的协议、集群等信息。
图片
暴露:
- 暴露过程中,首先需要解析配置,根据配置中的协议创建相应的协议实现。
- 将协议绑定到指定的 IP 和端口上。
- 将服务地址信息注册到注册中心,以供其他调用者查询。
- 通知订阅者(监听器)服务地址信息的变化。
- 调用者接收到订阅者的通知,得知服务地址信息变化。
- 调用者通过网络层向提供者发起调用请求。
- 提供者处理请求后,返回结果给调用者。
2、引用Refer
引用的过程类似,只是方向相反,具体如下:
图片
引用
- 引用过程中,同样需要解析配置,根据配置中的协议创建相应的协议实现。
- 连接到指定的服务地址。
- 查询注册中心,获取对应服务地址信息。
- 返回服务地址信息给调用者。
- 提供者处理调用请求,返回结果给调用者。
- 调用者接收到结果,结束调用过程。
3、服务提供者和服务消费者
Dubbo的服务提供者是指提供服务的主体,通常会暴露自己的服务接口,并通过某种协议提供服务。而服务消费者是使用服务的主体,通常会引用提供者的服务接口,并通过某种协议调用服务。
图片
- 服务提供者向 Zookeeper 注册服务,服务消费者向 Zookeeper 订阅服务。
- 服务消费者通过 Zookeeper 获取服务提供者的地址信息,然后调用服务提供者的服务。
4、注册中心
Dubbo最核心的概念就是注册中心,它用于管理服务提供者的注册与发现,使服务消费者能够动态地发现和访问服务提供者。Dubbo支持多种注册中心,包括Zookeeper、Redis、Multicast等等,其中Zookeeper是Dubbo默认的注册中心。
图片
注册中心
- 服务提供者将自己提供的服务注册到注册中心。
- 服务消费者从注册中心订阅所需的服务列表。
- 注册中心返回可用的服务列表给服务提供者和服务消费者。
- 服务消费者调用服务提供者的服务。
- 服务提供者返回服务结果给服务消费者。
5、负载均衡
Dubbo 的负载均衡是指服务消费者在调用服务提供者的时候,如何从多个服务提供者中选择一个进行调用。
Dubbo 默认提供了多种负载均衡策略,例如随机、轮询、最少活跃数等。服务消费者通过 Dubbo 的负载均衡模块,将请求分发给多个服务提供者,然后由负载均衡模块根据选定的负载均衡策略选择一个服务提供者进行调用,从而达到分摊负载的效果。
图片
负载均衡
在图中,服务消费者 A 需要调用一个服务提供者,但是有多个服务提供者可供选择,这时候负载均衡 B 就发挥作用了。B 会根据负载均衡策略,选择一个服务提供者进行调用,例如选择了服务提供者1 C。如果 C 发生故障或宕机,B 就会重新选择一个可用的服务提供者,例如选择了服务提供者2 D。这样,服务消费者 A 就可以通过 Dubbo 的负载均衡模块,动态地选择服务提供者,从而实现负载均衡。
6、集群容错
Dubbo的集群容错是指当服务提供者发生故障时,Dubbo如何从备选节点中选择一个可用的节点让服务消费者访问。Dubbo提供了多种集群容错策略,包括快速失败、失败切换、失败重试等等,可以根据需求选择适合的策略。
图片
集群容错
- Consumer:服务的消费者,发起服务调用的一方。
- Invoker:Dubbo 中的调用器,将消费者的请求转换成可执行的任务并执行。
- Cluster:Dubbo 中的集群容错模块,将多个 Invoker 封装成一个集群。
- Failover:Dubbo 集群容错模块中的容错策略之一,如果某次调用失败,会自动切换到下一个 Invoker 进行调用,直到成功为止。
- Failfast:Dubbo 集群容错模块中的容错策略之一,如果某次调用失败,会立即抛出异常。
- Failsafe:Dubbo 集群容错模块中的容错策略之一,如果某次调用失败,会记录下异常,但不会抛出异常。
- Failback:Dubbo 集群容错模块中的容错策略之一,如果某次调用失败,会在后台异步重试。
- Forking:Dubbo 集群容错模块中的容错策略之一,将请求并发调用多个 Invoker,只要有一个 Invoker 成功返回结果,就立即返回。
三、Dubbo的架构
1、服务提供者和服务消费者之间的通信流程
在Dubbo中,服务提供者和服务消费者之间的通信流程较为复杂,涉及到多个角色的交互。
下面简要介绍Dubbo的通信流程:
- 服务消费者向注册中心发起服务发现请求,获取服务列表。
- 注册中心返回服务列表给服务消费者。
- 服务消费者根据负载均衡策略选择一个服务提供者。
- 服务提供者返回自身的 IP 地址和端口号给服务消费者。
- 服务消费者通过网络向服务提供者发送请求消息。
- 服务提供者处理请求并返回响应消息给服务消费者。
图片
dubbo的架构
整个通信流程中,Dubbo使用了类似RPC(Remote Procedure Call)的方式进行通信,即服务消费者发送请求给服务提供者,服务提供者返回结果给服务消费者。
Dubbo的主要区别在于,Dubbo支持多种协议和序列化机制,同时还提供了负载均衡、集群容错等功能。
2、Dubbo的三层架构
Dubbo的三层架构包括:
(1)接口层
接口层是Dubbo的核心,它定义了服务提供者和服务消费者之间的通信接口。在Dubbo中,接口默认使用Java接口实现,具有很强的可扩展性。
(2)配置层
配置层的作用是通过配置文件或代码来配置Dubbo的各种参数,包括连接参数、超时时间、重试次数等等。Dubbo支持多种配置方式,包括XML配置、注解配置和属性配置。
(3)基础设施层
基础设施层是Dubbo的底层架构,包括了Dubbo的RPC框架、网络通信、序列化和反序列化等实现细节。Dubbo的基础设施层具有较高的性能和可定制性。
图片
Dubbo的三层架构
3、Dubbo的扩展机制
Dubbo提供了较为完善的扩展机制,使得开发者可以轻松改变Dubbo的默认行为,实现个性化定制。
Dubbo的扩展机制主要有三种:
(1)SPI机制
Dubbo使用了SPI(Service Provider Interface)机制,开发者可以通过在class path下提供指定的接口实现类来替换Dubbo框架默认的实现。在Dubbo中,SPI机制通过Java的ServiceLoader实现。
(2)Adaptive机制
Dubbo的Adaptive机制是对SPI机制的一种补充,它可以根据不同的场景自动适配最合适的实现类。Adaptive机制通过动态生成的代理类来实现。
(3)Extension机制
Extension机制是Dubbo的核心扩展机制,它允许开发者自定义Dubbo的各种插件,包括Protocol、Transport和Serialization等。Extension机制通过@SPI和@Adaptive注解实现。开发者可以通过实现指定接口和在注解中指定拓展名,来实现自定义插件的加载和使用。
四、Dubbo的配置
1、XML配置
Dubbo的XML配置是最早的配置方式,在配置过程中需要编写XML文件,指定Dubbo相关的标签和属性。其中,最基本的配置是服务提供者和服务消费者的相关配置,如下:
<!-- 服务提供者注册到注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 暴露服务 -->
<dubbo:service interface="com.xxx.xxxService" ref="xxxServiceImpl" timeout="3000" />
<!-- 引用服务 -->
<dubbo:reference interface="com.xxx.xxxService" id="xxxService" timeout="3000" />
在这段XML配置中,我们首先在标签中指定了注册中心的地址信息,然后在标签中指定了服务提供者的接口和实现类,以及引用服务的接口和实现。timeout属性用于设置超时时间。
除了服务提供者和服务消费者的相关配置外,还有其他相关的配置。比如,可以使用<dubbo:protocol>标签指定Dubbo使用的协议类型和端口号,同时也可以在<dubbo:method>标签中为方法单独指定超时时间等参数。
2、注解配置
注解配置是一种比较简便的配置方式,可以直接在Java代码中使用注解指定Dubbo相关的配置信息。使用注解配置时,需要在配置类中添加@EnableDubbo注解开启Dubbo相关功能,示例如下:
@Configuration
@EnableDubbo(scanBasePackages = "com.xxx.service.impl")
public class DubboConfig {
}
其中,scanBasePackages属性指定了Dubbo扫描的包路径。然后就可以在服务提供者和服务消费者的实现类中使用Dubbo提供的注解进行配置,示例如下:
@Service(timeout = 3000)
public class XxxServiceImpl implements XxxService {
@Override
public String hello(String name) {
return "Hello " + name;
}
}
对于服务消费者,则可以使用@DubboReference注解引用服务,示例如下:
@Service
public class XxxConsumer {
@DubboReference(timeout = 3000)
private XxxService xxxService;
public String hello(String name) {
return xxxService.hello(name);
}
}
在这个例子中,我们使用@DubboReference注解指定了服务的接口和超时时间,然后在XxxConsumer类中通过xxxService调用服务。
3、属性配置
属性配置是一种比较灵活的配置方式,它允许我们在配置文件中定义属性,然后在代码中读取这些属性并进行相关操作。使用属性配置时,我们需要在代码中创建一个DubboProperties对象,并将其中的属性值通过@ConfigurationProperties注解注入到该对象中。示例如下:
@Component
@ConfigurationProperties(prefix = "dubbo")
public class DubboProperties {
private String registryAddress;
// get/set方法省略
}
然后,我们可以使用这个DubboProperties对象中定义的属性配置Dubbo相关的参数,示例如下:
@Service(timeout = "#{dubboProperties.timeout}")
public class XxxServiceImpl implements XxxService {
@Autowired
private DubboProperties dubboProperties;
@Override
public String hello(String name) {
return "Hello " + name;
}
}
在这个例子中,我们使用了#{dubboProperties.timeout}的方式,读取DubboProperties对象中的timeout属性来指定服务超时时间。我们还可以在DubboProviders对象中定义其他属性,在需要的地方使用${}的方式读取这些属性。
五、Dubbo的高可用与容错
1、服务降级
服务降级指的是当系统出现故障或者异常情况时,系统可以通过关闭一些非核心的功能来保证其他核心功能的正常运行。Dubbo提供了服务降级的功能,通过这个功能,Dubbo可以在某些条件下提供替代方案,比如返回空结果、返回默认结果等等。
Dubbo的服务降级是通过Mock来实现的,Mock可以在接口定义的时候指定。Dubbo在正常情况下会使用服务提供者提供的服务,当服务提供者出现异常或者超时时,Dubbo会自动调用Mock中的方法返回预设的值。
2、服务熔断
服务熔断是指当系统中某个服务出现异常或者超时等情况时,Dubbo会在一定时间内暂停对该服务的调用,防止服务雪崩,提高系统的可用性。Dubbo支持配置熔断的时间窗口和请求的最大失败次数,当超过这个次数后,Dubbo将不再调用该服务,直到时间窗口结束。
Dubbo的服务熔断是通过circuit breaker模式来实现的,Dubbo会根据服务的负载情况来判断是否需要熔断。
3、服务隔离
服务隔离指的是将不同的服务放在不同的进程或者容器中运行,防止某个服务出现故障影响到其他服务的正常运行。Dubbo支持将不同的服务放在不同的进程或者容器中运行,实现服务的隔离。
4、重试机制
重试机制指的是在服务调用失败后,Dubbo会根据一定的规则进行重试,直到服务调用成功或达到最大重试次数。Dubbo可以配置重试次数、重试间隔时间等参数,实现重试机制。
Dubbo默认提供了重试机制,可以通过在配置文件中设置retries参数来启用。如果服务调用失败,则Dubbo会自动重新尝试调用服务,直到达到最大重试次数或服务调用成功。重试过程中,Dubbo会等待一定的时间间隔,以避免对服务的过度压力。
六、Dubbo的负载均衡策略
1、轮询负载均衡
轮询负载均衡算法是默认的算法,它会将服务提供者列表按照顺序轮流选择。如果其中一个服务提供者的性能较差,那么使用轮询算法会导致它会被频繁地请求,从而降低整体性能。因此,轮询算法适用于所有服务提供者性能相同的情况下。
2、随机负载均衡
随机负载均衡算法可以随机选择一个服务提供者来处理请求。与轮询算法相比,随机算法并不考虑服务提供者之间的负载或性能,因此速度更快。但是,在某些情况下,服务提供者之间的负载差异太大,随机算法可能会导致某些服务提供者接受过多的请求。因此,随机算法适用于所有服务提供者性能相同的情况下,或服务提供者之间的性能差异较小的情况下。
3、最少活跃调用负载均衡
最少活跃调用(Least Active)是一种智能负载均衡算法。该算法会选择活跃调用数最少的服务提供者来处理请求,也就是当前正忙碌程度最小的服务提供者。这种算法适合那些提供长时间服务的服务者,比如像查询某种缓存服务,查询开始不占用太多服务器资源,但是随着查询次数增加会占用 相当多的服务端资源,这时候使用Least Active算法可以选取负载最小的服务提供者,避免资源过度占用。
4、一致性哈希负载均衡
一致性哈希负载均衡是一种智能负载均衡算法,在分布式场景下,可以保证负载均衡和数据一致性。该算法会将所有服务提供者看作一个环,每个服务提供者对应一个独特的哈希值。
对于一个请求,一致性哈希算法通过哈希值将其映射到服务提供者环中的一个位置,然后选择服务提供者环上第一个顺时针方向遇到的服务提供者来处理请求。
该算法优点在于,当新增或删除一个服务提供者时,仅需重新映射部分请求到新的服务提供者,而不是全部请求,从而避免了大规模迁移,可以提高系统的稳定性和扩展性。
七、Dubbo的集群容错机制
1、失败自动切换
在调用服务时,Dubbo会选择一个可用的服务提供者,如果该提供者未响应或发生异常,Dubbo会自动切换到下一个可用的服务提供者进行调用,这就是失败自动切换机制。
2、失败安全保护
在失败自动切换的基础上,Dubbo提供了另一种集群容错机制:失败安全保护。它的原理是当出现某个服务提供者不可用时,Dubbo会暂时禁用该服务提供者,一段时间后再次开启,检查其可用性。通过这种方式,Dubbo保证了系统的稳定性以及在出现异常情况时调用的可用性。
3、并行调用
Dubbo在集群容错中提供了一种新的机制:并行调用。
当服务提供者在某个时间段内不能响应请求时,Dubbo会开启多个服务提供者实例,将请求发送给这些实例进行并行处理,快速的获取结果并返回给服务消费者。
4、快速失败
快速失败机制指当某个服务提供者出现异常时,Dubbo会快速的抛出异常给服务消费者,避免服务调用者长时间等待请求响应结果。同时,Dubbo也提供了一个超时时间,如果服务提供者在规定时间内未能响应请求,则Dubbo会快速的抛出异常给服务消费者,避免请求长时间等待没有响应结果。
八、Dubbo的底层通信
1、Dubbo的网络通信
Dubbo的底层通信是建立在Netty的通信框架上的,Netty是一个高性能的、异步的、事件驱动的网络应用程序框架。在Dubbo中,Netty扮演着很重要的角色,其提供的通信能力能够支持Dubbo不同节点之间的通信,并且通过高效的I/O操作完成请求响应的过程。Dubbo利用Netty的通信框架实现了从网络层到协议层的完整封装,使得Dubbo的通信效率得到很大的提升。
Dubbo的网络通信过程是非常复杂的,在服务提供者和服务消费者之间建立连接,并进行请求响应的过程中,每一步都可能出现各种问题,例如网络延迟、服务端宕机、序列化错误等等,因此Dubbo在网络通信过程中加入了多种机制来提高网络通信的效率和安全性。其中,比较重要的机制包括心跳机制、序列化与反序列化、长连接池等等。
2、序列化和反序列化
Dubbo利用Java自带的ObjectInputStream和ObjectOutputStream类实现序列化和反序列化的过程,通过序列化和反序列化使得复杂的对象能够在网络中传输。
Dubbo支持多种序列化协议,包括Java原生的序列化协议(即Dubbo协议)、JSON、Hessian、Kryo等。Dubbo默认采用Java原生的序列化协议,虽然其具有很好的兼容性,但是其性能较差。因此,通常情况下建议使用其他的序列化协议,例如Hessian或Kryo,以提高序列化的效率。
九、Dubbo的扩展机制
1、自定义SPI扩展
Dubbo采用SPI(Service Provider Interface)的机制,用于扩展或替换框架中的某个实现。Dubbo对SPI机制的扩展可以通过Java的SPI机制实现,也可以通过Dubbo自己定义的SPI机制实现,Dubbo自己定义的SPI机制要完善一些。
Dubbo自定义的SPI机制定义了一个扩展点接口,每个扩展点接口对应了一组扩展实现类,而这些实现类都必须要使用SPI的配置文件进行配置。
Dubbo的扩展点接口中,我们可以定义类似于ExtensionLoader这样的类,通过这些类,我们可以获取到相关扩展实现类,从而进行自定义的扩展。
2、自定义过滤器
Dubbo的过滤器是一种拦截器,可以在请求到达消费者时、在提供者执行服务逻辑前后以及在调用方收到响应时对请求和响应进行处理。Dubbo提供了一些内置的过滤器,例如安全过滤器、异常过滤器、日志过滤器等。
不过,Dubbo也允许我们自定义过滤器来实现自己的特定需求,自定义的过滤器需要实现Filter接口,然后通过SPI机制进行扩展。
自定义的过滤器可以用于多种场景,例如监控、鉴权、统计和日志等。
3、自定义负载均衡策略
Dubbo框架内置了多种负载均衡策略,例如随机负载均衡、轮询负载均衡和最少活跃调用负载均衡等。但是,这些负载均衡策略并不一定适用于所有的场景,因此Dubbo也允许我们自定义负载均衡策略。
自定义负载均衡策略需要实现LoadBalance接口,然后通过SPI机制进行扩展。自定义负载均衡策略可以根据不同场景的需求,实现不同的算法和逻辑,从而更好地满足业务需求。
十、总结
1、Dubbo的优缺点
Dubbo是阿里巴巴公司开发的一款高性能、高可用的分布式服务框架。在分布式架构中,Dubbo担任着重要的角色,实现了服务的注册、发现、负载均衡、容错等功能,为分布式系统提供了更好的可扩展性和可维护性。
同时,Dubbo也存在一些优缺点。
首先,Dubbo具有较强的可定制化性,可以根据实际业务需求来选择不同的配置和扩展机制。
其次,Dubbo的性能表现出色,适用于高并发、大规模的分布式系统。但是,Dubbo也存在一些问题,比如复杂的部署和配置流程,限制了其在小型项目中的应用。
2、Dubbo的未来发展趋势
未来,Dubbo将会继续发展和改进,市场对Dubbo的需求也将继续增加。除了更新迭代,Dubbo还将更加注重安全、大数据等领域的拓展和应用。
总的来说,Dubbo在分布式架构中的地位和应用前景都非常广阔。
本文转载自微信公众号「哪吒编程」,可以通过以下二维码关注。转载本文请联系哪吒编程公众号。