微服务面试必问的Dubbo,这么详细还怕自己找不到工作?

news2024/11/29 12:44:23

前言

互联网的不断发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对。

服务化的进一步发展,服务越来越多,服务之间的调用和依赖关系也越来越复杂,诞生了面向服务的架构体系(SOA),

也因此衍生出了一系列相应的技术,如对服务提供、服务调用、连接处理、通信协议、序列化方式、服务发现、服务路由、日志输出等行为进行封装的服务框架。

就这样分布式系统的服务治理框架就出现了,Dubbo也就这样产生了。

概念

Dubbo 是一款高性能、轻量级的开源 RPC 框架、提供服务自动注册、自动发现等高效治理方案,可以和 Spring 框架无缝集成

简单的说,dubbo就是个分布式服务框架,在有分布式需要的时候可以使用 dubbo 的框架,使用 dubbo 的好处:

1、透明化的远程方法调用

2、软负载均衡及容错机制

3、服务自动注册与发现

4、提供了完善的服务接口管理与监控功能

架构图

RPC

简介

RPC 全称为 remote procedure call,即远程过程调用。比如两台服务器 A 和 B,A 服务器上部署一个应用,B 服务器上部署一个应用,A 服务器上的应用想调用 B 服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据

RPC 并不是一个具体的技术,而是指整个网络远程调用过程

RPC 是一个泛化的概念,严格来说一切远程过程调用手段都属于 RP C范畴。各种开发语言都有自己的 RPC 框架。Java 中的 RPC 框架比较多,广泛使用的有RMI、Hessian、Dubbo 等。

原理

服务消费方(client)调用以本地调用方式调用服务。客户端存根(client stub)接收到调用后负责将方法、参数等编码成能在网络中传输的消息体。然后,客户端存根找到服务地址后,将消息发送给服务端。

服务提供方(server)收到序列化后的消息,就按照解码该消息。然后,根据解码结果调用本地服务,执行完毕后,将结果打包发送给消费方。

服务消费方收到执行结果后,也是进行解码后得到结果。

原理

使用场景

RPC 分布式服务,拆分应用进行服务化,提高开发效率,调优性能,节省竞争资源

配置管理,解决服务的地址信息剧增,配置困难的问题

服务依赖,解决服务间依赖关系错踪复杂的问题

服务扩容,解决随着访问量的不断增大,动态扩展服务提供方的机器的问题

核心功能

Remoting:远程通讯,提供对多种 NIO 框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。

Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。

Registry:服务注册中心,服务自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

核心组件

Provider:服务的提供方

Consumer:调用远程服务的服务消费方

Registry:服务注册和发现的注册中心

Monitor:统计服务调用次数和调用时间的监控中心

Container:服务运行容器

组件

服务注册与发现

流程如下:

1、Provider(提供者)绑定指定端口并启动服务

2、供者连接注册中心,并发本机 IP、端口、应用信息和提供服务信息发送至注册中心存储

3、Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心

4、注册中心根据消费者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。

5、Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用

6、Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer设计的原因:

Consumer 与 Provider 解偶,双方都可以横向增减节点数。注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台

7、去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用

8、服务提供者无状态,任意一台宕掉后,不影响使用

流程

服务治理

治理原因

Dubbo的服务治理主要原因:

1、过多的服务 URL 配置困难

2、负载均衡分配节点压力过大的情况下也需要部署集群。

3、服务依赖混乱,启动顺序不清晰。

4、过多服务导致性能指标分析难度较大,需要监控。

主要特性

透明远程调用:就像调用本地方法一样调用远程方法;只需简单配置,没有任何 API 侵入

负载均衡机制:Client 端 LB,可在内网替代 F5 等硬件负载均衡器

容错重试机制:服务 Mock 数据,重试次数、超时机制等

自动注册发现:注册中心基于接口名查询服务提 供者的 IP 地址,并且能够平滑添加或删除服务提供者

性能日志监控:Monitor 统计服务的调用次调和调用时间的监控中心

服务治理中心:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等手动配置

自动治理中心:无,比如:熔断限流机制、自动权重调整等(因此可以搭配SpringCloud的熔断机制等进行开发)

服务治理

架构设计

整体架构

先看下 Dubbo 的整体架构图:

图例说明:

整体架构

图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。

图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。

图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。

图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。

各层说明

config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类

proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton,以ServiceProxy 为中心,扩展接口为 ProxyFactory

registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为RegistryFactory, Registry, RegistryService

cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance

monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为MonitorFactory, Monitor, MonitorService

protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter

exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer

transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec

serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool

主要模块

dubbo-common 公共逻辑模块,包括 Util 类和通用模型

dubbo-remoting 远程通讯模块,相当于 Dubbo 协议的实现,如果 RPC 用 RMI 协议则不需要使用此包。

dubbo-rpc 远程调用模块,抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。

dubbo-cluster 集群模块,将多个服务提供方伪装为一个提供方,包括:负载均衡、容错、路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。

dubbo-registry 注册中心模块,基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。

dubbo-monitor 监控模块,统计服务调用次数,调用时间的,调用链跟踪的服务。

dubbo-config 配置模块,是 Dubbo 对外的 API ,用户通过 Config 使用 Dubbo ,隐藏 Dubbo 所有细节。

dubbo-container 容器模块,是一个 Standalone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。

主要模块

调用方式

异步调用

基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小

异步调用

本地调用

使用了Injvm协议,是一个伪协议,它不开启端口,不发起远程调用,只在JVM内直接关联,但执行Dubbo的Filter链。

Define injvm protocol:

<dubbo:protocol name="injvm" /> 

Set default protocol:

<dubbo:provider protocol="injvm" />

Set service protocol:

<dubbo:service protocol="injvm" />

Use injvm first:(服务暴露与服务引用都需要声明injvm=“true”)

<dubbo:consumer injvm="true" .../>
<dubbo:provider injvm="true" .../>
或
<dubbo:reference injvm="true" .../>   <dubbo:service injvm="true" .../>

容错机制

调用流程

1、Cluster 将 Directory 中的多个 Invoker 伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑

2、Router 负责从多个 Invoker 中按路由规则选出子集,比如读写分离,应用隔离等

3、LoadBalance 负责从多个 Invoker 中选出具体的一个用于本次调用,选的过程包含了负载均衡算法

调用流程

容错策略

Dubbo 官网提出总共有六种容错策略

1、Failover Cluster

失败自动切换,当出现失败,重试其它服务器。(默认)

2、Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

3、Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

4、Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

5、Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过 forks=”2”来设置最大并行数。

6、Broadcast Cluster

广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0 开始支持) 通常用于通知所有提供者更新缓存或日志等本地资源信息。

总结:在实际应用中查询语句容错策略建议使用默认 Failover Cluster,而增删改建议使用 Failfast Cluster 或者使用 Failover Cluster(retries=”0”)策略,防止出现数据重复添加等等其它问题!建议在设计接口时候把查询接口方法单独做一个接口提供查询。

连接方式

Dubbo 的客户端和服务端有三种连接方式,分别是:广播、直连和使用Zookeeper注册中心。

Dubbo 广播

这种方式是dubbo官方入门程序所使用的连接方式,但是这种方式有很多问题,在企业开发中不使用广播的方式。

服务端配置:

<!--配制dubbo-->
<!--提供应用信息,用于计算依赖关系-->
<dubbo:application name="demo-service"/>
<!--使用multicast广播注册暴露服务地址-->
<dubbo:registry address="multicast://192.168.9.4:88888" />

<!--使用dubbo协议在20880端口暴露服务-->
<dubbo:protocol name="dubbo" port="20880"/>

<!--声明暴露的服务接口-->
<dubbo:service interface="com.demo.manger.service.TestService" ref="testServiceImpl" />

客户端配置:

<!--配合dubbo-->
<!--提供应用信息,用于计算依赖关系-->
<dubbo:application name="demo-web"/>

<!--使用multicast广播注册中心暴露服务地址 -->
<dubbo:registry address="multicast://19.188.8.9:8888"/>

<!--声明需要暴露的接口-->
<dubbo:reference interface="com.demo.manager.service.TestService" id="testService" timeout="1000000" />

Dubbo 直连

这种方式在企业中一般在开发中环境中使用,但是生产环境很少使用,因为服务是直接调用,没有使用注册中心,很难对服务进行管理。Dubbo 直连,首先要取消广播,然后客户端直接到指定需要的服务的 url 获取服务即可。

服务端配置:

<!--配制dubbo-->
<!--提供应用信息,用于计算依赖关系-->
<dubbo:application name="demo-service"/>
<!--使用multicast广播注册暴露服务地址-->
<-- <dubbo:registry address="multicast://192.168.9.4:88888" /> -->
<dubbo:registry adress="N/A">

<!--使用dubbo协议在20880端口暴露服务-->
<dubbo:protocol name="dubbo" port="20880"/>

<!--声明暴露的服务接口-->
<dubbo:service interface="com.demo.manger.service.TestService" ref="testServiceImpl" />

客户端配置:

<!--配合dubbo-->
<!--提供应用信息,用于计算依赖关系-->
<dubbo:application name="demo-web"/>

<!--使用multicast广播注册中心暴露服务地址 -->
<-- <dubbo:registry address="multicast://19.188.8.9:8888"/> -->

<!--声明需要暴露的接口-->
<dubbo:reference interface="com.demo.manager.service.TestService" id="testService" timeout="1000000" url="dubbo://127.0.0.1:20880" />

zookeeper 注册中心

Dubbo 注册中心和广播注册中心配置类似,不过需要指定注册中心类型和注册中心地址,这个时候就不是把服务信息进行广播了,而是告诉给注册中心进行管理,这个时候我们就需要有一个注册中心,官方推荐使用 zookeeper 作为注册中心。

Zookeeper 注册中心

注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者在启动时与注册中心交互,消费者不断的发起请求获取服务信息,注册中心不转发请求,压力较小

服务端配置:

<!--配制dubbo-->
<!--提供应用信息,用于计算依赖关系-->
<dubbo:application name="demo-service"/>
<!--使用multicast广播注册暴露服务地址-->
<!-- <dubbo:registry address="multicast://192.168.9.4:88888" /> -->
<!--<dubbo:registry adress="N/A"> -->
<dubbo:registry protocol="zookeeper" address="192.168.37,136:2181">
<!--使用dubbo协议在20880端口暴露服务-->
<dubbo:protocol name="dubbo" port="20880"/>

<!--声明暴露的服务接口-->
<dubbo:service interface="com.demo.manger.service.TestService" ref="testServiceImpl" />

客户端配置:

<!--配合dubbo-->
<!--提供应用信息,用于计算依赖关系-->
<dubbo:application name="demo-web"/>

<!--使用multicast广播注册中心暴露服务地址 -->
<-- <dubbo:registry address="multicast://19.188.8.9:8888"/> -->
<dubbo:registry protocol="zookeeper" address="192.168.37.1336:2181"/>    

<!--声明需要暴露的接口-->
<dubbo:reference interface="com.demo.manager.service.TestService" id="testService" timeout="1000000" />

策略

负载均衡策略

1、Random LoadBalance,随机(默认的负载均衡策略)

RandomLoadBalance 是加权随机算法的具体实现,可以完全随机,也可以按权重设置随机概率。

2、RoundRobin LoadBalance,轮循

可以轮询和加权轮询。存在响应慢的提供者会累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

3、LeastActive LoadBalance,最少活跃调用数

活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求。此时应优先将请求分配给该服务提供者。

4、ConsistentHash LoadBalance,一致性 Hash

一致性 Hash 算法,相同参数的请求一定分发到一个 provider 上去。provider 挂掉的时候,会基于虚拟节点均匀分配剩余的流量,抖动不会太大。

集群容错策略

1、failover cluster(默认)

失败自动切换,调用失败时,自动重试其他机器。通常用于读操作,但重试会带来更长延迟。

2、Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

3、Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

4、Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

5、Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。

动态代理策略

默认使用 javassist 动态字节码生成,创建代理类。也可以通过 spi 扩展机制配置自己的动态代理策略。

集群容错方案

  • 配置说明,方案配置方式,优先使用消费端配置

<!--服务端配置-->
<dubbo:service cluster="failover"/>
<!--消费端配置-->
<dubbo:reference cluster="failover"/>
  • 尽量在只在服务端进行配置

  • cluster类型均为小写

  • 默认为FailoverCluster失败切换方案

集群容错方案support

FailoverCluster(默认):失败切换

  • 场景:调用失败后切换其他服务

  • 配置:

<!--
retries:重试次数,不包括第一次,默认2次
-->
<dubbo:service cluster="failover" retries="3"/>
  • 代码实现逻辑:

    1. 根据负载均衡策略选出需要调用的服务实例,排除已调用的

    2. 执行选出的实例,并将其保存到已调用列表中

    3. 执行实例成功即返回

    4. 执行实例不成功,为到最大重试次数则执行第一步,否则抛出RpcException异常

FailbackCluster:失败重试

  • 场景:调用失败时记录失败请求,定时重发

  • 配置:

<!--
retries:重试次数,不包括第一次,默认3次
failbacktasks:定时器中最大挂起任务数,默认100
-->
<dubbo:service cluster="failback" retries="5" failbacktasks="200"/>
  • 代码实现逻辑

    1. 根据负载均衡策略选出需要调用的服务实例

    2. 执行选出的实例

    3. 执行实例成功即返回

    4. 执行异常则创建延时5秒的定时任务,并加入时间轮定时器,第一次需要进行定时器初始化,分为32个时间片,每1秒滚动一次,最大挂起任务默认100个,超出最大任务数时抛出RejectedExecutionException异常。

    5. 重试执行定时任务,次数超出最大执行次数停止,并输出error日志,默认为3次。

FailfastCluster:快速失败

  • 场景:调用失败立即报错

  • 配置:

<dubbo:service cluster="failfast"/>
  • 代码实现逻辑

    1. 根据负载均衡策略选出需要调用的服务实例

    2. 执行选出的实例

    3. 执行实例成功即返回,失败抛出RpcException异常

FailsafeCluster:安全失败

  • 场景:调用失败后忽略

  • 配置:

<dubbo:service cluster="failsafe"/>
  • 代码实现逻辑

    1. 根据负载均衡策略选出需要调用的服务实例

    2. 执行选出的实例

    3. 执行实例成功即返回,失败输出error日志,并返RpcResult,视为忽略。

ForkingCluster:并发处理

  • 场景:并发调用指定数量的服务,一个成功则返回,对实时性要求高的场景,要求快速返回,需要使用更多服务器资源。

  • 配置:

<!--
forks:最大并发数,默认2
timeout:并发返回超时时间,默认1000ms
-->
<dubbo:service cluster="forking" forks="3" timeout="500"/>
  • 代码实现逻辑

    1. 根据负载均衡策略选出几个不同的服务实例

    2. 并发执行选出的几个实例,并将返回结果放入堵塞队列中

    3. 返回堵塞队列中的第一个值,如规定时间内未获取到队列中的值或获取到异常值则返回RPC异常。

BroadcastCluster:广播

  • 场景:广播方式逐个调用服务提供者,有一个报错则返回错误,多用于通知服务提供者更新本地资源信息,如缓存,日志等。

  • 配置:

<dubbo:service cluster="broadcast"/>
  • 代码实现逻辑

    1. 循环逐个执行所有服务实例信息

    2. 保存一份返回结果和异常信息

    3. 执行完全部实例后,如异常信息不为空,则抛出异常信息,否则返回最后一个实例的结果。

AvailableCluster:可用服务

  • 场景:调用第一个可用服务

  • 配置:

<dubbo:service cluster="available"/>
  • 代码实现逻辑

    1. 循环所有服务实例信息

    2. 执行第一个可用的实例,并返回结果

    3. 如无可用实例则返回RpcException异常

MergeableCluster:合并处理

  • 场景:返回合并或叠加处理结果

  • 配置:

<!--
merger:合并发放名
timeout:调用服务超时时间,默认1000ms
-->
<dubbo:service cluster="mergeable" merger="true" timeout="500"/>
  • 代码实现逻辑

    1. 判断merger,为空、null、0、false、N/A是执行第一个可用服务并返回结果,无可用则执行第一个实例,并返回结果。

    2. 获取方法实例的返回类型

    3. 异步调用所有实例,并将异步结果Result存储到结果集中,返回异常输出error日志

    4. 结果集为空返回 RpcException,大小为 1时返回第一个Result

    5. 当merger的第一个字符为“.”时,判断当 merger 实例返回类型不为void,且返回类型必须是结果集中第一个返回类型的父类型或相同类型时,循环执行merger实例,每一次都传入上一次的返回结果,最终返回获取最后一次结果,非上述情况时循环执行merger实例,返回结果集中的第一个结果。

    6. 当merger为true或default时使用Dubbo默认合并器,否则使用自定义merger合并器,合并后返回

RegistryAwareCluster:默认标识、注册标识

  • 场景:调用注册默认标识的服务

  • 配置:

<!--
default:默认标识
-->
<dubbo:registry address="zookeeper://xxx..." default="true"/>
<dubbo:service cluster="registryaware"/>
  • 代码实现逻辑

    1.8 循环所有服务实例信息

    2. 执行第一个可用的实例且default为true的实例

    3. 无默认实例则执行第一个可用的实例

    4. 无可用的实例则抛出RpcException异常

主要配置

配置应用信息:

<dubbo:application name=“appName-provider” />

配置注册中心相关信息:

<dubbo:registryid=“zk” protocol=“zookeeper” address=“127.0.0.1:2181” />

配置服务协议:

<dubbo:protocol name=“dubbo” port=“20880” threadpool=“cached” threads=“80” />

配置所有暴露服务缺省值:

<dubbo:provider registry=“zk” protocol=“dubbo” retries=“0” version=“1.0.0” timeout=“3000” threadpool=“cached” threads=“4”/>

配置暴露服务:

<dubbo:service interface=“com.orgname.app.serviceX” ref=“serviceX” />

配置所有引用服务缺省值:

<dubbo:consumer check=“false” timeout=“1000” version=“1.0” retries=“0” async=“false” />

注解配置:

com.alibaba.dubbo.config.annotation.Service 配置暴露服务

com.alibaba.dubbo.config.annotation.Reference配置引用服务

超时设置

Dubbo消费端

全局超时配置

<dubbo:consumer timeout="5000" />

指定接口以及特定方法超时配置

<dubbo:reference interface="com.foo.BarService" timeout="2000">
    <dubbo:method name="sayHello" timeout="3000" />
</dubbo:reference>

Dubbo服务端

全局超时配置

<dubbo:provider timeout="5000" />

指定接口以及特定方法超时配置

<dubbo:provider interface="com.foo.BarService" timeout="2000">
    <dubbo:method name="sayHello" timeout="3000" />
</dubbo:provider>

支持协议

1、Dubbo 协议(官方推荐协议)

优点:采用NIO复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用)

缺点:大文件上传时,可能出现问题(不使用 Dubbo 文件上传)

2、RMI(Remote Method Invocation)协议

优点:JDK 自带的能力。可与原生 RMI 互操作,基于 TCP 协议

缺点:偶尔连接失败.

3、Hessian协议

优点:可与原生 Hessian 互操作,基于 HTTP 协议

缺点:需 hessian.jar 支持,http 短连接的*开销大8

常用设计模式

Dubbo 框架在初始化和通信过程中使用了多种设计模式,可灵活控制类加载、权限控制等功能。

工厂模式

Provider 在 export 服务时,会调用 ServiceConfig 的 export 方法。ServiceConfig 中有个字段:

private static final Protocol protocol =
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

Dubbo 里有很多这种代码。这也是一种工厂模式,只是实现类的获取采用了 JDK SPI 的机制。这么实现的优点是可扩展性强,想要扩展实现,只需要在 classpath下增加个文件就可以了,代码零侵入。另外,像上面的 Adaptive 实现,可以做到调用时动态决定调用哪个实现,但是由于这种实现采用了动态代理,会造成代码调试比较麻烦,需要分析出实际调用的实现类。

装饰器模式

Dubbo 在启动和调用阶段都大量使用了装饰器模式。以 Provider 提供的调用链为例,具体的调用链代码是在 ProtocolFilterWrapper 的buildInvokerChain 完成的,具体是将注解中含有 group=provider 的 Filter 实现,按照 order 排序,最后的调用顺序是:

EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter ->
ExecuteLimitFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter ->
ExceptionFilter

更确切地说,这里是装饰器和责任链模式的混合使用。例如,EchoFilter 的作用是判断是否是回声测试请求,是的话直接返回内容,这是一种责任链的体现。而像ClassLoaderFilter 则只是在主功能上添加了功能,更改当前线程的 ClassLoader,这是典型的装饰器模式。

观察者模式

Dubbo 的 Provider 启动时,需要与注册中心交互,先注册自己的服务,再订阅自己的服务,订阅时,采用了观察者模式,开启一个 listener。注册中心会每 5 秒定时检查是否有服务更新,如果有更新,向该服务的提供者发送一个 notify 消息,provider 接受到 notify 消息后,即运行 NotifyListener 的 notify 方法,执行监听器方法。

动态代理模式

Dubbo 扩展 JDK SPI 的类 ExtensionLoader 的 Adaptive 实现是典型的动态代理实现。Dubbo 需要灵活地控制实现类,即在调用阶段动态地根据参数决定调用哪个实现类,所以采用先生成代理类的方法,能够做到灵活的调用。生成代理类的代码是 ExtensionLoader 的 createAdaptiveExtensionClassCode 方法。代理类的主要逻辑是,获取 URL 参数中指定参数的值作为获取实现类的 key

工作流程

整体流程:

第一步:provider 向注册中心去注册

第二步:consumer 从注册中心订阅服务,注册中心会通知 consumer 注册好的服务

第三步:consumer 调用 provider

第四步:consumer 和 provider 都异步通知监控中心

流程图

总结

最后用一张图来形象的模拟 Dubbo 的使用:

使用

以上只是我总结的一些关于 dubbo 最基础的原理及使用介绍,至于代码编写过程的 bug 处理经验,环境搭建、项目布局等等问题,需要我们在平时开发中,将系统知识与实战经验相结合去总结,这样才能真正的去掌握这项技术点。

Dubbo 目前是我用到过的最多的分布式框架,写出来的内容也是最多的,不过由于Dubbo用的太多,而 SpringCloud 难度比 Dubbo 要小很多,现在大部分项目都即将开始转投到了 SpringCloud 上面,后面也会出更多的 SpringCloud 相关的文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142369.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

财富自由、技术瓶颈、面试技巧,找另一半...这些程序员最关心的问题,AI的回答神了!

距离ChatGPT发布已经好几周了&#xff0c;我还沉迷在和它的聊天当中&#xff0c;每天一遇到问题&#xff0c;我的第一反应就是先问问ChatGPT的建议&#xff0c;作为一名程序员&#xff0c;我们可能有很多问题或困惑&#xff0c;我也问问了它&#xff0c;整理了一些比较有代表性…

Nodejs三层架构的封装

nodejs三层架构开发模式 项目结构 依次在每个目录添加代码 1.在dao层下创建database.js模块,里面存放的是连接数据库的模块代码 const {connect,connection} require(mongoose); // 设置要连接的 MongoDB 服务器地址(studentsManage:要连接的数据库名称) const dbURI mong…

Unity InputSystem基础

一些概念 Action Maps 一组Action的集合为一个Action Map。可以同时有多个Action Map&#xff0c;可以进行切换&#xff0c;也可以同时运行&#xff08;监控&#xff09;。例如可以使用joystick控制角色移动&#xff0c;也可以使用joystick控制菜单。通过切换Action Map&#x…

别小看 Log 日志,它难住了我们组的架构师

Slf4j slf4j 的全称是 Simple Loging Facade For Java&#xff0c;它仅仅是一个为 Java 程序提供日志输出的统一接口&#xff0c;并不是一个具体的日志实现方案&#xff0c;就比如 JDBC 一样&#xff0c;只是一种规则而已。所以单独的 slf4j 是不能工作的&#xff0c;必须搭配…

Go后端部署服务器

go后端部署服务器方式一&#xff1a;&#xff08;最简单&#xff09; 和暑假做重点场所项目部署一样&#xff0c;简单&#xff0c;无脑&#xff0c;手动&#xff0c;麻烦 1、# 修改&#xff08;确保&#xff09;环境&#xff0c;因为服务器是linux系统 go env -w GOOSlinux …

FreeRTOS实验使用02

1:队列集使用 主要就是函数xQueueSelectFromSet 返回值的判断&#xff0c;用于判断里面的消息谁有效 Pend (or block) on multiple RTOS queues and semaphores in a set (freertos.org) 官方给的例程更好&#xff0c;更规范 2&#xff1a;任务通知使用 xR xTaskNotify(Task…

手把手教你从0到1通过 Express 完成图片上传并保存至阿里云OSS功能(附详细源码)

&#x1f9e8; 大家好&#xff0c;我是 Smooth&#xff0c;一名大三的 SCAU 前端er &#x1f64c; 如文章有误&#xff0c;恳请评论区指正&#xff0c;谢谢&#xff01; ❤ 写作不易&#xff0c;「点赞」「收藏」「转发」 谢谢支持&#xff01; 背景 近期一个项目由于缺人&…

遗传算法解决旅行商问题

问题描述旅行商问题&#xff08;TSP&#xff09;. 一个商人欲从自己所在的城市出发&#xff0c;到若干个城市推销商品&#xff0c;然后回到其所在的城市。如何选择一条周游路线&#xff0c;使得商人经过每个城市一次且仅一次后回到起点&#xff0c;并使他所走过的路径最短&…

oom killer理解和日志分析:知识储备

参考&#xff1a;oom killer 详解 oom killer日志分析&#xff0c;这是前篇&#xff0c;准备一些基础知识 带着问题看&#xff1a; 1.什么是oom killer 是Linux内核设计的一种机制&#xff0c;在内存不足的时候&#xff0c;选择一个占用内存较大的进程并kill掉这个进程&…

【JVM系列】JVM内存结构

JVM内存结构 运行时数据区 JAVA运行时内存划分堆&#xff0c;方法区&#xff0c;虚拟机栈&#xff0c;本地方法栈和程序计数器。 线程私有的有&#xff1a; - 程序计数器 - 虚拟机栈 - 本地方法栈​ 线程共享的有&#xff1a; - 堆 - 方法区程序计数器 用来记录当前线程执…

Redundant Paths(双向图的缩点(边联通分量缩成点))

F-Redundant Paths_2022图论班第二章连通性例题与习题 (nowcoder.com) 为了从F(1 \leq F \leq 5000)F(1≤F≤5000)一块牧场(编号为1..F)到另一块牧场&#xff0c;贝西和牛群的其他成员不得不穿过烂苹果树附近。奶牛现在厌倦了经常被迫走一条特定的路&#xff0c;想要建造一些新…

YOLO-V5 系列算法和代码解析(六)—— 分布式训练

文章目录预备知识DPDDPDP和DDP对比YOLO-V5 实际使用参考链接预备知识 为了更好的理解分布式相关的内容&#xff0c;需要提前熟悉一些基本概念和特定的名称。分布式训练涉及到设备端&#xff08;CPU&#xff0c;GPU&#xff09;&#xff0c;算法端&#xff08;梯度更新&#xff…

项目团队承诺管理的3个重要因素

每一个项目都需要一个强有力的领导者&#xff0c;以获得适当的成功机会。与一个优柔寡断、缺乏经验的项目领导者相比&#xff0c;一个有组织的领导者在管理一个精心策划的项目时&#xff0c;更有可能取得项目的成功和客户的满意。再加上一个非常投入和负责任的项目团队&#xf…

[ docker相关知识 ] 删除 docker 拉取的镜像 -- 释放内存

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

Speckle 3d数据引擎Python开发实战

在这个教程中&#xff0c;我们将使用 Speckle 数据并使用它来创建一个超级简单的仪表板。 我们将从Speckle流中接收几何图形&#xff0c;更新数据&#xff0c;并使用它来使用 Plotly 和 Dash 进行一些计算和简单绘图。 我们假设你具有 Python 和 Speckle 的一般知识。 如果有任…

信号处理——MATLAB音频信号加噪、滤波

音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结很抱歉大家&#xff0c;最近经常有朋友私信问我关于这篇信号处理的一些问题&#xff0c;因为最近比较忙所以没能一一回复&#xff0c;给大家说句抱歉&#xff0c;希望那些给我私信的人可以看到。大家问的…

golang 垃圾回收-三色标记法(白话版)

对于golang 垃圾回收的了解&#xff0c;我理解更多的就是了解&#xff0c;实际做项目能用到垃圾回收的知识点不多&#xff0c;但有些晦涩难懂的语言&#xff0c;是我们的绊脚石&#xff0c;对于技术怎么能理解就怎么记忆。 1. golang垃圾回收的基础&#xff1a;标记&#xff08…

ESNI 和ECH的前世今生

这边文章中提到过虽然 TLS 能够加密整个通信过程&#xff0c;但是在协商的过程中依旧有很多隐私敏感的参数不得不以明文方式传输&#xff0c;其中最为重要且棘手的就是将要访问的域名&#xff0c;即 SNI&#xff08;Server Name Indication&#xff09;。同时还有用于告知客户端…

javaEE高阶---MyBatis

一 : 什么是MyBatis MyBatis是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库的工具.MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的动作 . MyBatis …

[oeasy]python0037_终端_terminal_电传打字机_tty_shell_控制台_console_发展历史

换行回车 回忆上次内容 换行 和 回车 是两回事 换行 对应字节0x0ALine-Feed 水平 不动垂直 向上喂纸 所以是 feed 回车 对应字节0x0DCarriage-Return 垂直 不动水平 回到纸张左侧 可移动的打印头 运输字符 的 装置 (Carriage)回到 行首 所以是 Return tty、terminal、shell、…