【♣Dubbo】RPC(远程调用)和Dubbo面试题
什么是RPC
RPC(Remote Procedure Call) 即远程过程调用,通过名字我们就能看出 RPC 关注的是远程调用而非本地调用。
为什么要 RPC?因为两个不同的服务器上的服务提供的方法不在一个内存空间,所以需要通过网络编程才能传递方法调用所需要的参数。并且方法调用的结果也需要通过网络编程来接收。但是如果我们自己手动网络编程来实现这个调用过程的话工作量是非常大的,因为我们需要考虑底层传输方式(TCP还是UDP)、序列化方式等等方面。
RPC 能帮助我们做什么呢? 简单来说,通过 RPC 可以帮助我们调用远程计算机上某个服务的方法,这个过程就像调用本地方法一样简单。并且我们不需要了解底层网络编程的具体细节。
举个例子:两个不同的服务 A、B 部署在两台不同的机器上,服务 A 如果想要调用服务 B 中的某个方法的话就可以通过 RPC 来做。
总之,RPC 的出现就是为了让你调用远程方法像调用本地方法一样简单。
RPC的原理是什么
整个 RPC的 核心功能看作是下面5 个部分实现的:
- 客户端(服务消费端):调用远程方法的一端。
- 客户端 Stub(桩):这其实就是一代理类。代理类主要做的事情很简单,就是把你调用方法、类、方法参数等信息传递到服务端。
- 网络传输:网络传输就是你要把你调用的方法的信息比如说参数这些东西传输到服务端,然后服务端执行完之后再把返回结果通过网络传输给你传输回来。网络传输的实现方式有很多种,比如基本的 Socket或者性能以及封装更加优秀的 Netty(推荐)。
- 服务端 Stub(桩):这个桩就不是代理类了。我觉得理解为桩实际不太好,大家注意一下就好。这里的服务端 Stub 实际指的就是接收到客户端执行方法的请求后,去执行对应的方法然后返回结果给客户端的类。
- 服务端(服务提供端):提供远程方法的一端。
- 服务消费端(client)以本地调用的方式调用远程服务;
- 客户端 Stub(client stub) 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体(序列化):RpcRequest;
- 客户端 Stub(client stub) 找到远程服务的地址,并将消息发送到服务提供端;
- 服务端 Stub(桩)收到消息将消息反序列化为Java对象: RpcRequest;
- 服务端 Stub(桩)根据RpcRequest中的类、方法、方法参数等信息调用本地的方法;
- 服务端 Stub(桩)得到方法执行结果并将组装成能够进行网络传输的消息体:RpcResponse(序列化)发送至消费方;
- 客户端 Stub(client stub)接收到消息并将消息反序列化为Java对象:RpcResponse ,这样也就得到了最终结果。
Dubbo是什么?
dubbo是一个分布式框架,远程服务调用的分布式框架,是阿里的开源项目,目前Apache 基金会孵化项目,其核心部分包含:
- 集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
- 远程通讯:提供对多种长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
- 自动发现:基于注册中心目录服务,使消费提供方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
Dubbo官网:https://dubbo.apache.org/zh/
为什么要用Dubbo?
因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性。
使用 Dubbo 可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。
透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需要简单配置,没有任何API入侵。软负载均衡及容错机制,可以在内网替代F5等硬件负载均衡器。降低成本,减少单点。服务自动注册与发现,不在需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
Dubbo 架构中的核心角色有哪些?
它们之间的关系:
- Container:服务运行容器,负责加载、运行服务提供者。必须。
- Provider:暴露服务的服务提供方,会向注册中心注册自己提供的服务。必须。
- Consumer:调用远程服务的服务消费方,会向注册中心订阅自己所需的服务。必须。
- Registry:服务注册与发现的注册中心。注册中心会返回服务提供者地址列表给消费者。非必须。
- Monitor:统计服务的调用次数和调用时间的监控中心。服务消费者和提供者会定时发送统计数据到监控中心。 非必须。
Dubbo 中的 Invoker 概念了解么?
Invoker 是 Dubbo 领域模型中非常重要的一个概念,Invoker 就是 Dubbo 对远程调用的抽象。
按照 Dubbo 官方的话来说,Invoker 分为:
- 服务提供 Invoker
- 服务消费 Invoker
假如我们需要调用一个远程方法,我们需要动态代理来屏蔽远程调用的细节,我们屏蔽掉的这些细节就依赖对应的 Invoker 实现, Invoker 实现了真正的远程服务调用。
Dubbo 的 SPI 机制了解么? 如何扩展 Dubbo 中的默认实现?
SPI(Service Provider Interface)机制被大量用在开源项目中,它可以帮助我们动态寻找服务/功能(比如负载均衡策略)的实现。
SPI 的具体原理是这样的:我们将接口的实现类放在配置文件中,我们在程序运行过程中读取配置文件,通过反射加载实现类。这样,我们可以在运行的时候,动态替换接口的实现类。和 IoC 的解耦思想是类似的。
Java 本身就提供了 SPI 机制的实现。不过Dubbo 没有直接用,而是对Java原生的 SPI机制进行了增强,以便更好满足自己的需求。
使用举例:
1)比如说我们想要实现自己的负载均衡策略,我们创建对应的实现类 XxxLoadBalance 实现 LoadBalance 接口或者 AbstractLoadBalance 类。
2)将这个实现类的路径写入到resources 目录下的 META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance文件中即可。(文件名是接口名,内容是接口的具体实现类的全路径)
Dubbo支持哪些协议?
- dubbo 默认协议(推荐)
- rmi 协议
- hessian 协议
- http 协议
- webservice 协议
- thrift 协议
Dubbo有些哪些注册中心?
- Zookeeper 注册中心(官方推荐)
- Multicast 注册中心
- Redis 注册中心
- Simple 注册中心
- Nacos 注册中心
Dubbo服务注册与发现的流程?
(1)启动:Provider(服务提供者)绑定指定端口并启动服务
(2)Provider 注册服务地址:Provider 连接注册中心,将本机 IP、端口、应用信息和提供服务信息发送至注册中心存储
(3)Consumer 订阅服务地址:Consumer(服务消费者)连接注册中心 ,发送应用信息、所求服务信息至注册中心
(4)服务订阅或变更时,推送服务地址列表
- 注册中心根据 Consumer 请求的服务信息匹配对应的 Provider 列表,并发送至 Consumer 应用缓存
- Provider 状态变更会实时通知注册中心、在由注册中心实时推送至 Consumer
(5)随机调用一个服务地址,失败重试另外一个服务地址
- Consumer 在发起远程调用时,选择基于缓存的 Provider 列表中的一个 Provider 的地址,发起调用
(6)后台定时采集服务调用次数和调用时间等信息
Dubbo有哪些负载均衡策略?
Dubbo 实现了常见的集群策略,并提供扩展点予以自行实现。
- Random LoadBalance:随机选取提供者策略,随机转发请求,可以加权
- RoundRobin LoadBalance:轮询选取提供者策略,请求平均分布
- LeastActive LoadBalance:最少活跃调用策略,可以让慢提供者接收更少的请求
- ConstantHash LoadBalance:一致性 Hash 策略,相同参数请求总是发到同一提供者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者
缺省时为 Random LoadBalance(随机选取)。
Dubbo有哪些集群容错方案?
- Failover Cluster,失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。
- Failfast Cluster,快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
- Failsafe Cluster,失败安全,出现异常时,直接忽略。通常用于写入日志等。
- Failback Cluster,失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知等。
- Forking Cluster,并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks 来设置最大并行数。
- Broadcast Cluster,广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存本地资源信息。
默认是Failover Cluster(失败自动切换)。
Dubbo的注册中心挂掉,Consumer和Provider之间还能通讯吗?
可以通讯。主要是因为Dubbo初始化的时候,消费者会将服务提供者的地址等信息缓存到本地。
- 注册中心集群,发生宕机会自动切换
- 启动 Dubbo 时,Consumer 会从 zookeeper 拉取 Provider 注册的地址、接口等数据,缓存在本地
- Consumer 每次调用时,按照本地存储的 Provider 地址进行调用
- Provider 全部宕机,Consumer 会无法使用,并无限次重连等待 Provider 恢复
- 无法增加和调用新服务
Dubbo支持哪些序列化方式?
- Hessian 序列化:不是原生的,是修改过的 hessian lite,默认启用
- json 序列化:使用 FastJson 库
- java 序列化:JDK 提供的序列化,性能不理想
- dubbo 序列化:未成熟的高效 java 序列化实现,不建议在生产环境使用
谈谈遇到的Dubbo超时问题
dubbo 调用服务超时,默认是会重试两次的,但可能两次请求都是成功的。如果没有幂等性处理,就会产生重复数据。
- 可以考虑去除 dubbo 超时重试机制,重新评估设置超时时间
- dubbo 的重试在集群环境下,会把超时的请求发到其他服务
- 引起超时的原因可能出在消费端,也可能出现在服务端,服务器的网络、内存、CPU、存储空间都可能引起超时问题
- 超时时间设置过小也会导致超时问题
Dubbo 和 Spring Cloud 有什么区别?
两个没关联,如果硬要说区别,有以下几点:
- 通信方式不同:Dubbo 使用的是 RPC 通信,而 Spring Cloud 使用的是 HTTP RESTFul 方式。
- 组成部分不同
Dubbo需要 Web 容器吗?
不需要,如果硬要用 Web 容器,只会增加复杂性,也浪费资源。
Dubbo内置了哪几种服务容器?
-
Spring -
Jetty -
Log4j
Dubbo 的服务容器只是一个简单的 Main 方法,并加载一个简单的 Spring 容器,用于暴露服务。
Dubbo有哪几种配置方式?
-
Spring 配置方式 -
Java API 配置方式
Dubbo启动时如果依赖的服务不可用会怎样?
Dubbo 默认会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。
Dubbo支持服务多协议吗?
Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。
- 发布单个协议
- 同一服务发布多个协议
- 不同的服务发布不同的协议
当一个服务接口有多种实现时怎么做?
当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可。
Dubbo支持分布式事务吗?
目前暂时不支持。
Dubbo的好处?
-
透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。 -
软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。 -
服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。(下面讲解) -
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
2022-03-27 Dubbo 2.7 整合SpringBoot
2022-03-27 Dubbo 2.7 整合Spring(注解形式)
2022-03-27 Dubbo 2.7 整合Spring(xml形式)