欢迎来到Dubbo系列,在面试中被问到Dubbo相关的问题时,大部分都是简历上写了Dubbo,或者面试官想尝试问问你对Dubbo是否了解。
本系列主要是针对面试官通过一个点就使劲儿往下问的情况。
面试官:说说你们项目亮点
好的面试官
我们这个项目的技术亮点在于采用了Spring Cloud Alibaba架构,能够承载xxxx并发服务,采用Dubbo作为项目的RPC框架进行远程调用,…
面试官铺捉到了rpc、dubbo
面试官:什么是RPC
RPC(Remote Procedure Call)
远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。通俗的讲就是像调用本地服务一样调用远程服务。
既然你都说了什么是RPC,那你总得说说RPC的原理吧
面试官:说说RPC的原理是什么
核心要素:客户端、远程通信、服务端
好的面试官
我这里把rpc框架的原理分成7个方面来说:
- 服务消费端(client)以本地调用的方式调用远程服务;
- 客户端 Stub(client stub) 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体(序列化):RpcRequest;
- 客户端 Stub(client stub) 找到远程服务的地址,并将消息发送到服务提供端;
- 服务端 Stub(桩)收到消息将消息反序列化为 Java 对象: RpcRequest;
- 服务端 Stub(桩)根据RpcRequest中的类、方法、方法参数等信息调用本地的方法;
- 服务端 Stub(桩)得到方法执行结果并将组装成能够进行网络传输的消息体:RpcResponse(序列化)发送至消费方;
- 客户端 Stub(client stub)接收到消息并将消息反序列化为 Java 对象:RpcResponse ,这样也就得到了最终结果。
以上就是个人对RPC原理的理解。
面试官此时可能会想,那你知道哪些RPC框架
面试官:除了Dubbo,你还知道哪些RPC框架
目前市面上有较多出名的 RPC 框架,除了Dubbo以外,还有Thrift、gRPC 等。
这会总得该到说Dubbo原理了吧
面试官:能说下Dubbo的工作原理吗?
好的,dubbo的工作原理个人理解可以从五个方面来说:
- 服务启动的时候,provider和consumer根据配置信息,连接到注册中心register,分别向注册中心注册和订阅服务
- register根据服务订阅关系,返回provider信息到consumer,同时consumer会把provider信息缓存到本地。如果信息有变更,consumer会收到来自register的推送
- consumer生成代理对象,同时根据负载均衡策略,选择一台provider,同时定时向monitor记录接口的调用次数和时间信息
- 拿到代理对象之后,consumer通过代理对象发起接口调用
- provider收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现
以上就是个人对dubbo原理的理解。
知道dubbo原理后,你那总得说说Dubbo 和 Spring Cloud 的区别吧
面试官:说说Dubbo 和 Spring Cloud 的区别
好的,Dubbo和Spring Cloud是两种不同的微服务框架,它们各自具有独特的特点和优势,适用于不同的场景。
下面我从四个方面来说一下他两的区别:
-
架构设计:Dubbo是一个RPC(远程过程调用)框架,旨在提供高性能、透明化的远程方法调用,采用类似传统SOA(面向服务的架构)的架构设计。它支持多种注册中心,如Zookeeper、Redis等,并内置了多种负载均衡策略。相比之下,Spring Cloud是基于Spring Boot的微服务框架,旨在简化分布式系统的开发,采用较为松耦合的架构设计,允许开发者更加灵活地选择适合自己的组件。Spring Cloud提供了包括服务注册与发现、负载均衡、熔断器等在内的众多组件。
-
开发成本:Dubbo的开发成本相对较低,因为它提供了高度的可定制性,但这也意味着需要开发者有更深入的理解和编程能力。Spring Cloud则通过整合Spring生态下的众多项目,如Eureka、Hystrix、Zuul等,提供了一站式的解决方案,降低了集成难度,提高了开发效率。
-
通信协议:Dubbo默认使用单一长连接和NIO(非阻塞I/O)异步通讯方式,通过建立长连接发送多个请求和响应,减少了连接建立和关闭的开销。而Spring Cloud底层基于HTTP协议传输,虽然通信效率上可能不如Dubbo,但它支持多语言开发,只需要遵循HTTP协议便能整合一起。
-
适用场景:Dubbo适合需要高性能RPC调用、对通信效率有较高要求的场景,尤其是当系统已经使用了Zookeeper等作为注册中心时。Spring Cloud则更适合需要快速构建微服务应用、灵活部署方式以及对服务治理功能有较高需求的场景,尤其是当团队熟悉Spring生态时。
综上所述,Dubbo和Spring Cloud各有优势,选择哪个框架取决于项目的具体需求和技术栈。在实际项目中,它们也可以互补使用,例如Dubbo作为内部服务的RPC调用,而Spring Cloud用于构建RESTful API等对外服务。
看来知道的挺多的,那继续问点dubbo深点的东西。
面试官:那你说说Dubbo中服务暴露的流程?
好的,关于dubbo中服务暴露的流程我们可以分成四个步骤:
- 在容器启动的时候,通过ServiceConfig解析标签,创建dubbo标签解析器来解析dubbo的标签,容器创建完成之后,触发ContextRefreshEvent事件回调开始暴露服务
- 通过ProxyFactory获取到invoker,invoker包含了需要执行的方法的对象信息和具体的URL地址
- 再通过DubboProtocol的实现把包装后的invoker转换成exporter,然后启动服务器server,监听端口
- 最后RegistryProtocol保存URL地址和invoker的映射关系,同时注册到服务中心
以上是个人总结的dubbo中服务暴露流程。
面试官:说说Dubbo服务引用的流程?
好的,客户端要引用服务,最后才是调用的过程。
整个过程个人理解大致可以分成三步:
- 首先客户端根据配置文件信息从注册中心订阅服务
- 之后DubboProtocol根据订阅的得到provider地址和接口信息连接到服务端server,开启客户端client,然后创建invoker
- invoker创建完成之后,通过invoker为服务接口生成代理对象,这个代理对象用于远程调用provider,服务的引用就完成了。
分布式架构中,总得聊聊服务的动态上下线吧
面试官:Dubbo是怎么实现动态感知服务下线的呢?
我们先搞清楚服务的两种订阅模式: pull 和 push 两种方式:
● pull 模式需要客户端定时向注册中心拉取配置;
● push 模式采用注册中心主动推送数据给客户端。
Dubbo推荐使用Zookeeper注册中心采用是事件通知与客户端拉取方式。服务第一次订阅的时候将会拉取对应目录下全量数据,然后在订阅的节点注册一个 watcher。一旦目录节点下发生任何数据变化,Zookeeper将会通过 watcher 通知客户端。客户端接到通知,将会重新拉取该目录下全量数据,并重新注册 watcher。利用这个模式,Dubbo 服务就可以做到服务的动态发现。
dubbo的SPI机制是深入研究Dubbo的必经之路,所以,也得问问
面试官:那你说说Dubbo SPI机制
说dubbo的SPI机制之前,我想说一下关于什么是SPI。
SPI全称为 Service Provider Interface,是一种服务发现机制,本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类,这样可以在运行时,动态为接口替换实现类。
Dubbo也正是通过SPI机制实现了众多的扩展功能,而且dubbo没有使用java原生的SPI机制,而是对齐进行了增强和改进。
SPI在dubbo应用很多,包括协议扩展、集群扩展、路由扩展、序列化扩展等等。
使用方式可以在META-INF/dubbo目录下配置:
key=
然后通过dubbo的ExtensionLoader按照指定的key加载对应的实现类,这样做的好处就是可以按需加载,性能上得到优化。
原理知道的不少,聊点实战的
面试官:说说Dubbo的优先级配置
好的,关于Dubbo中的优先级配置,我总结了两个点:
1.以timeout为例,显示了配置的查找顺序,其他retries,loadbalance等类似。
- 方法级优先,接口级次之,全局配置再次之
- 如果级别一样,则消费方优先,提供方次之
其中,服务提供方配置,通过URL经由注册中心传递给消费方
2.建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消 费方同时引用多个服务,就不需要关心每个服务的超时设置。
面试官:服务上线怎么兼容旧版本?
可以用版本号(version=)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。
比如说:线上有一个version=1.0.0的版本正在使用,因为新增某些功能,需要重新发布,所以,可以设置此时version=1.0.1,先把Dubbo服务版本为1.0.1的发布上去一部分,然后把消费方引用版本也改成1.0.1,也发布上去。
此时就变成了,1.0.0和1.0.1的两个Dubbo服务版本了,后面就可以逐步把1.0.0的都下线,全部上1.0.1的服务,但是注意上线是先发1.0.1的Dubbo服务,下线是先下1.0.0的消费方引用。
聊dubbo肯定少不了容错策略
面试官:服务读写推荐的容错策略是怎样的?
读操作建议使用 Failover失败自动切换,默认重试两次其他服务器。
写操作建议使用 Failfast快速失败,发一次调用失败就立即报错。
读可以多次读,写那就只给留一次。
面试官:Dubbo集群容错方式有哪些?
好的,关于Dubbo集群容错一共有六种:
- Failover Cluster失败自动切换:dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可用通过引用服务的时候配置,默认重试次数为1也就是只调用一次。
- Failback Cluster失败自动恢复:在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的调用进行重试
- Failfast Cluster快速失败:只会调用一次,失败后立刻抛出异常
- Failsafe Cluster失败安全:调用出现异常,记录日志不抛出,返回空结果
- Forking Cluster并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一个provider成功返回了结果,就会立刻返回结果
- Broadcast Cluster广播模式:逐个调用每个provider,如果其中一台报错,在循环调用结束后,抛出异常。
再聊个相对比较有意思的就是让你来设计一个RPC框架,你会如何设计?
面试官:如果让你实现一个RPC框架,你会怎么设计?
好的,其实想设计一个RPC框架,我们只能从大的方向说几点,毕竟要想设计一个完美的RPC框架需要将很多东西。
所以,关于设计RPC框架,我简单总结四个点:
- 首先需要一个服务注册中心,这样consumer和provider才能去注册和订阅服务
- 需要负载均衡的机制来决定consumer如何调用客户端,这其中还当然要包含容错和重试的机制
- 需要通信协议和工具框架,比如通过HTTP或者rmi的协议通信,然后再根据协议选择使用什么框架和工具来进行通信,当然,数据的传输序列化要考虑
- 除了基本的要素之外,像一些监控、配置管理页面、日志是额外的优化考虑因素。
推荐文章1:徒手撸框架–实现 RPC 远程调用
推荐文章2:如何手撸一个较为完整的RPC框架