详细参见官方文档:http://dubbo.apache.org/zh-cn/docs/user/configuration/xml.html
比如,xml配置
所有标签都支持自定义参数,用于不同扩展点实现的特殊配置,如:
标签
用途
解释
服务配置
用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心
[2]
引用配置
用于创建一个远程服务代理,一个引用可以指向多个注册中心
协议配置
用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受
应用配置
用于配置当前应用信息,不管该应用是提供者还是消费者
模块配置
用于配置当前模块信息,可选
注册中心配置
用于配置连接注册中心相关信息
监控中心配置
用于配置连接监控中心相关信息,可选
提供方配置
当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选
消费方配置
当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选
方法配置
用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息
参数配置
用于指定方法参数配置
官方提供提供了集成库 dubbo-spring-boot
,对应仓库为 https://github.com/apache/incubator-dubbo-spring-boot-project 。
一共分成 10 层,当然理解后是非常清晰的
图例说明
最顶上九个图标,代表本图中的对象与流程。
图中左边 淡蓝背景( Consumer ) 的为服务消费方使用的接口,右边 淡绿色背景( Provider ) 的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。
图中从下至上分为十层,各层均为单向依赖,右边的 黑色箭头( Depend ) 代表层之间的依赖关系,每一层都可以剥离上层被复用。其中,Service 和 Config 层为 API,其它各层均为 SPI 。
注意,Dubbo 并未使用 JDK SPI 机制,而是自己实现了一套 Dubbo SPI 机制。
图中 绿色小块( Interface ) 的为扩展接口,蓝色小块( Class ) 为实现类,图中只显示用于关联各层的实现类。
图中 蓝色虚线( Init ) 为初始化过程,即启动时组装链。红色实线( Call )为方法调用过程,即运行时调时链。紫色三角箭头( Inherit )为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。
各层说明
虽然,有 10 层这么多,但是总体是分层 Business、RPC、Remoting 三大层。如下:
==================== Business ====================
Service 业务层:业务代码的接口与实现。我们实际使用 Dubbo 的业务层级。
接口层,给服务提供者和消费者来实现的。
==================== RPC ====================
config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 Spring 解析配置生成配置类。
配置层,主要是对 Dubbo 进行各种配置的。
proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 扩展接口为 ProxyFactory 。
服务代理层,无论是 consumer 还是 provider,Dubbo 都会给你生成代理,代理之间进行网络通信。
如果胖友了解 Spring Cloud 体系,可以类比成 Feign 对于 consumer ,Spring MVC 对于 provider 。
registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService 。
服务注册层,负责服务的注册与发现。
如果胖友了解 Spring Cloud 体系,可以类比成 Eureka Client 。
cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance 。
集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务。
如果胖友了解 Spring Cloud 体系,可以类比城 Ribbon 。
monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService 。
监控层,对 rpc 接口的调用次数和调用时间进行监控。
如果胖友了解 SkyWalking 链路追踪,你会发现,SkyWalking 基于 MonitorFilter 实现增强,从而透明化埋点监控。
==================== Remoting ====================
protocol 远程调用层:封将 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter 。
远程调用层,封装 rpc 调用。
exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer 。
信息交换层,封装请求响应模式,同步转异步。
transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec 。
网络传输层,抽象 mina 和 netty 为统一接口。
serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool 。
数据序列化层。
默认情况下,调用是同步的方式。
可以参考 《Dubbo 用户指南 —— 异步调用》 文档,配置异步调用的方式。当然,使用上,感觉蛮不优雅的。所以,在 Dubbo 2.7 版本后,又提供了新的两种方式,具体先参见 《Dubbo下一站:Apache顶级项目》 文章。估计,后续才会更新官方文档。
Dubbo 异常处理机制涉及的内容比较多,核心在于 Provider 的 异常过滤器 ExceptionFilter 对调用结果的各种情况的处理。所以建议胖友看如下三篇文章:
Dubbo 通过 CacheFilter 过滤器,提供结果缓存的功能,且既可以适用于 Consumer 也可以适用于 Provider 。
通过结果缓存,用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量。
Dubbo 目前提供三种实现:
lru
:基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。threadlocal
:当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。jcache
:与 JSR107 集成,可以桥接各种缓存实现。可以。对于正在运行的 Consumer 调用 Provider 是不需要经过注册中心,所以不受影响。并且,Consumer 进程中,内存已经缓存了 Provider 列表。
那么,此时 Provider 如果下线呢?如果 Provider 是正常关闭,它会主动且直接对和其处于连接中的 Consumer 们,发送一条“我要关闭”了的消息。那么,Consumer 们就不会调用该 Provider ,而调用其它的 Provider 。
另外,因为 Consumer 也会持久化 Provider 列表到本地文件。所以,此处如果 Consumer 重启,依然能够通过本地缓存的文件,获得到 Provider 列表。
再另外,一般情况下,注册中心是一个集群,如果一个节点挂了,Dubbo Consumer 和 Provider 将自动切换到集群的另外一个节点上。
流程说明:
/dubbo/com.foo.BarService/providers
目录下写入自己的 URL 地址/dubbo/com.foo.BarService/providers
目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers
目录下写入自己的 URL 地址/dubbo/com.foo.BarService
目录下的所有提供者和消费者 URL 地址。在图中,我们可以看到 Zookeeper 的节点层级,自上而下是:
Root 层:根目录,可通过
的 "group"
设置 Zookeeper 的根节点,缺省使用 "dubbo"
。
Service 层:服务接口全名。
Type 层:分类。目前除了我们在图中看到的 "providers"
( 服务提供者列表 ) "consumers"
( 服务消费者列表 ) 外,还有 [这里是代码028]( 路由规则列表 ) 和 [这里是代码029]( 配置规则列表 )。
URL 层:URL ,根据不同 Type 目录,下面可以是服务提供者 URL 、服务消费者 URL 、路由规则 URL 、配置规则 URL 。
实际上 URL 上带有 "category"
参数,已经能判断每个 URL 的分类,但是 Zookeeper 是基于节点目录订阅的,所以增加了 Type 层。
实际上,服务消费者启动后,不仅仅订阅了 "providers"
分类,也订阅了 "routes"
"configurations"
分类。
Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果用户使用 kill -9 PID
等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID
时,才会执行。
服务提供方的优雅停机过程
服务消费方的优雅停机过程
① Zookeeper 注册中心的情况下
服务提供者,注册到 Zookeeper 上时,创建的是 EPHEMERAL 临时节点。所以在服务提供者异常关闭时,等待 Zookeeper 会话超时,那么该临时节点就会自动删除。
② Redis 注册中心的情况下
使用 Redis 作为注册中心,是有点小众的选择,我们就不在本文详细说了。感兴趣的胖友,可以看看 《精尽 Dubbo 源码分析 —— 注册中心(三)之 Redis》 一文。总的来说,实现上,还是蛮有趣的。因为,需要通知到消费者,服务列表发生变化,所以就无法使用 Redis Key 自动过期。所以… 还是看文章吧。哈哈哈哈。
不是,Consumer 可以强制直连 Provider 。
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。
相关文档,可见 《Dubbo 用户指南 —— 直连提供者》 。
另外,直连 Dubbo Provider 时,如果要 Debug 调试 Dubbo Provider ,可以通过配置,禁用该 Provider 注册到注册中心。否则,会被其它 Consumer 调用到。具体的配置方式,参见 《Dubbo 用户指南 —— 只订阅》 。
Dubbo 目前支持如下 9 种通信协议:
dubbo://
,默认协议。参见 《Dubbo 用户指南 —— dubbo://》 。rest://
,贡献自 Dubbox ,目前最合适的 HTTP Restful API 协议。参见 《Dubbo 用户指南 —— rest://》 。rmi://
,参见 《Dubbo 用户指南 —— rmi://》 。webservice://
,参见 《Dubbo 用户指南 —— webservice://》 。hessian://
,参见 《Dubbo 用户指南 —— hessian://》 。thrift://
,参见 《Dubbo 用户指南 —— thrift://》 。memcached://
,参见 《Dubbo 用户指南 —— memcached://》 。redis://
,参见 《Dubbo 用户指南 —— redis://》 。http://
,参见 《Dubbo 用户指南 —— http://》 。注意,这个和我们理解的 HTTP 协议有差异,而是 Spring 的 HttpInvoker 实现。实际上,社区里还有其他通信协议正处于孵化:
jsonrpc://
,对应 Github 仓库为 https://github.com/apache/incubator-dubbo-rpc-jsonrpc ,来自千米网的贡献。?? 每一种通信协议的实现,在 《精尽 Dubbo 源码解析》 中,都有详细解析。
另外,在 《Dubbo 用户指南 —— 性能测试报告》 中,官方提供了上述协议的性能测试对比。
远程暴露,比较好理解。在 「Dubbo 支持哪些通信协议?」 问题汇总,我们看到的,都是远程暴露。每次 Consumer 调用 Provider 都是跨进程,需要进行网络通信。
本地暴露,在 《Dubbo 用户指南 —— 本地调用》 一文中,定义如下:
本地调用使用了
injvm://
协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。
在通信框架的选择上,强大的技术社区有非常多的选择,如下列表:
那么 Dubbo 是如何做技术选型和实现的呢?Dubbo 在通信层拆分成了 API 层、实现层。项目结构如下:
dubbo-remoting-api
dubbo-remoting-netty3
dubbo-remoting-netty4
dubbo-remoting-mina
dubbo-remoting-grizzly
再配合上 Dubbo SPI 的机制,使用者可以自定义使用哪一种具体的实现。美滋滋。
在 Dubbo 的最新版本,默认使用 Netty4 的版本。?? 这就是结论。嘻嘻。
Dubbo 目前支付如下 7 种序列化方式:
dubbo://
协议的默认序列化方案。Hessian 除了是 Web 服务,也提供了其序列化实现,因此 Dubbo 基于它实现了序列化拓展。另外,Dubbo 维护了自己的 [这里是代码053] ,对 Hessian 2 的 序列化 部分的精简、改进、BugFix 。Random LoadBalance
RoundRobin LoadBalance
LeastActive LoadBalance
ConsistentHash LoadBalance
在 《Dubbo 用户指南 —— 集群容错》 中,我们可以看到 Dubbo 内置 6 种负载均衡策略。其中,默认使用 failover
失败自动重试其他服务的策略。
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2"
来设置重试次数(不含第一次)。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2"
来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
可能有胖友对动态代理不是很了解。因为,Consumer 仅仅引用服务 ***-api.jar
包,那么可以获得到需要服务的 XXXService 接口。那么,通过动态创建对应调用 Dubbo 服务的实现类。简化代码如下:
// ProxyFactory.java
/**
* create proxy.
*
* 创建 Proxy ,在引用服务调用。
*
* @param invoker Invoker 对象
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
T getProxy(Invoker invoker) throws RpcException;
invoker
,实现了调用 Dubbo 服务的逻辑。
结果,就是 XXXService 的实现类,而这个实现类,就是通过动态代理的工具类进行生成。通过动态代理的方式,实现了对于我们开发使用 Dubbo 时,透明的效果。当然,因为实际场景下,我们是结合 Spring 场景在使用,所以不会直接使用该 API 。
目前实现动态代理的工具类还是蛮多的,如下:
其中,Dubbo 动态代理使用了 Javassist 和 JDK 两种方式。
为什么默认使用 Javassist?
在 Dubbo 开发者【梁飞】的博客 《动态代理方案性能对比》 中,我们可以看到这几种方式的性能差异,而 Javassit 排在第一。也就是说,因为性能的原因。
有一点需要注意,Javassit 提供字节码 bytecode 生成方式和动态代理接口两种方式。后者的性能比 JDK 自带的还慢,所以 Dubbo 使用的是前者字节码 bytecode 生成方式。
那么是不是 JDK 代理就没意义?
实际上,JDK 代理在 JDK 1.8 版本下,性能已经有很大的提升,并且无需引入三方工具的依赖,也是非常棒的选择。所以,Spring 和 Motan 在动态代理生成上,优先选择 JDK 代理。
一旦使用 Dubbo 做了服务化后,必须必须必须要做的服务治理,也就是说,要做服务的管理与监控。当然,还有服务的降级和限流。这块,放在下面的面试题,在详细解析。
Dubbo 管理平台 + 监控平台
dubbo-monitor
监控平台,基于 Dubbo 的【monitor 监控层】,实现相应的监控数据的收集到监控平台。dubbo-admin
管理平台,基于注册中心,可以获取到服务相关的信息。关于这块的选择,胖友直接看看 《Dubbo监控和管理(dubbokeeper)》 。
另外,目前 Dubbo 正在重做 dubbo-admin
管理平台,感兴趣的胖友,可以跟进 https://github.com/apache/incubator-dubbo-ops 。
链路追踪
关链路追踪的概念,就不重复介绍了,?? 如果不懂,请自行 Google 下。
目前能够实现链路追踪的组件还是比较多的,如下:
比如说服务 A 调用服务 B,结果服务 B 挂掉了。服务 A 再重试几次调用服务 B,还是不行,那么直接降级,走一个备用的逻辑,给用户返回响应。
在 Dubbo 中,实现服务降级的功能,一共有两大种方式。
① Dubbo 原生自带的服务降级功能
具体可以看看 《Dubbo 用户指南 —— 服务降级》 。
当然,这个功能,并不能实现现代微服务的熔断器的功能。所以一般情况下,不太推荐这种方式,而是采用第二种方式。
② 引入支持服务降级的组件
目前开源社区常用的有两种组件支持服务降级的功能,分别是:
因为目前 Hystrix 已经停止维护,并且和 Dubbo 的集成度不是特别高,需要做二次开发,所以推荐使用 Sentinel 。具体的介绍,胖友可以看看 《Sentinel 介绍》 。
在做服务稳定性时,有一句非常经典的话:
那么,上面看到的服务降级,就属于怀疑第三方。
而本小节的限流目的,就是防备使用方。
此处,艿艿要再推荐一篇文章:《你应该如何正确健壮后端服务?》 。
目前,在 Dubbo 中,实现服务降级的功能,一共有两大种方式。
① Dubbo 原生自带的限流功能
通过 TpsLimitFilter 实现,仅适用于服务提供者。具体的使用方式,源码实现,看看 《精尽 Dubbo 源码分析 —— 过滤器(九)之 TpsLimitFilter》 。
?? 参照 TpsLimitFilter 的思路,可以实现自定义限流的 Filter ,并且使用 Guava RateLimiter 工具类,达到 令牌桶算法限流 的功能。
② 引入支持限流的组件
关于这个功能,还是推荐集成 Sentinel 组件。
所谓失败重试,就是 consumer 调用 provider 要是失败了,比如抛异常了,此时应该是可以重试的,或者调用超时了也可以重试。
实际场景下,我们一般会禁用掉重试。因为,因为超时后重试会有问题,超时你不知道是成功还是失败。例如,可能会导致两次扣款的问题。
所以,我们一般使用 failfast 集群容错策略,而不是 failover 策略。配置如下:
另外,一定一定一定要配置适合自己业务的超时时间。
当然,可以将操作分成读和写两种,前者支持重试,后者不支持重试。因为,读操作天然具有幂等性。
Dubbo 支持多种主流注册中心,如下:
目前 Alibaba 正在开源新的注册中心 Nacos ,也是未来的选择之一。
当然,Netflix Eureka 也是注册中心的一个选择,不过 Dubbo 暂未集成实现。
另外,此处会引申一个经典的问题,见 《为什么不应该使用 ZooKeeper 做服务发现》 文章。
所谓幂等,简单地说,就是对接口的多次调用所产生的结果和调用一次是一致的。扩展一下,这里的接口,可以理解为对外发布的 HTTP 接口或者 Thrift 接口,也可以是接收消息的内部接口,甚至是一个内部方法或操作。
那么我们为什么需要接口具有幂等性呢?设想一下以下情形:
所以,从这段描述中,幂等性不仅仅是 Dubbo 接口的问题,包括 HTTP 接口、Thrift 接口都存在这样的问题,甚至说 MQ 消息、定时任务,都会碰到这样的场景。那么应该怎么办呢?
这个不是技术问题,这个没有通用的一个方法,这个应该结合业务来保证幂等性。
所谓幂等性,就是说一个接口,多次发起同一个请求,你这个接口得保证结果是准确的,比如不能多扣款、不能多插入一条数据、不能将统计值多加了 1。这就是幂等性。
其实保证幂等性主要是三点:
对于每个请求必须有一个唯一的标识,举个栗子:订单支付请求,肯定得包含订单 id,一个订单 id 最多支付一次,对吧。
每次处理完请求之后,必须有一个记录标识这个请求处理过了。常见的方案是在 mysql 中记录个状态啥的,比如支付之前记录一条这个订单的支付流水。
每次接收请求需要进行判断,判断之前是否处理过。比如说,如果有一个订单已经支付了,就已经有了一条支付流水,那么如果重复发送这个请求,则此时先插入支付流水,orderId 已经存在了,唯一键约束生效,报错插入不进去的。然后你就不用再扣款了。
实际运作过程中,你要结合自己的业务来,比如说利用 redis,用 orderId 作为唯一键。只有成功插入这个支付流水,才可以执行实际的支付扣款。
要求是支付一个订单,必须插入一条支付流水,order_id 建一个唯一键 unique key。你在支付一个订单之前,先插入一条支付流水,order_id 就已经进去了。你就可以写一个标识到 redis 里面去,set order_id payed,下一次重复请求过来了,先查 redis 的 order_id 对应的 value,如果是 payed 就说明已经支付过了,你就别重复支付了。
参考 《Dubbo 用户指南 —— 多版本》 。
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
利用多版本的特性,我们也能实现灰度的功能。对于第 2 步,不要升级所有消费者为新版本,而是一半。
通过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,可以防止消费者绕过注册中心访问提供者。
另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者。
这个问题,仔细回答,需要思考 Web 容器的定义。然而实际上,真正想问的是,Dubbo 服务启动是否需要启动类似 Tomcat、Jetty 等服务器。
这个答案可以是,也可以是不是。为什么呢?根据协议的不同,Provider 会启动不同的服务器。
dubbo://
协议时,答案是否,因为 Provider 启动 Netty、Mina 等 NIO Server 。rest://
协议时,答案是是,Provider 启动 Tomcat、Jetty 等 HTTP 服务器,或者也可以使用 Netty 封装的 HTTP 服务器。hessian://
协议时,答案是是,Provider 启动 Jetty、Tomcat 等 HTTP 服务器。这个问题,不是仅仅适用于 Dubbo 的场景,而是 SOA、微服务。
对于使用了 Dubbo 的系统,配置分成两类:
对于 ① ,如果我们在 Provider 配置 Dubbo 请求超时时间,当 Consumer 未配置请求超时时间,会继承该配置,使用该请求超时时间。
的配置来使用。当然,如果 Consumer 自己配置了该配置项,则使用自身的。例如说,Provider 配置了请求超时时间是 10s ,而 Consumer 配置了请求超时超时是 5s ,那么最终 Consumer 请求超时的时间是 5s 。对于 ② ,市面上有非常多的配置中心可供选择:
这个问题不大。对于配置中心的选择,我们考虑的不是它和 Dubbo 的集成,而是它和 Spring 的集成。因为,大多数情况下,我们都是使用 Spring 作为框架的整合基础。目前,Apollo 和 Nacos 对 Spring 的支持是比较不错的。
首先,关于分布式事务的功能,不是 Dubbo 作为服务治理框架需要去实现的,所以 Dubbo 本身并没有实现。所以在 《Dubbo 用户指南 —— 分布式事务》 也提到,目前并未实现。
说起分布式,理论的文章很多,落地的实践很少。笔者翻阅了各种分布式事务组件的选型,大体如下:
那怎么选择呢?目前社区对于分布式事务的选择,暂时没有定论,至少笔者没有看到。笔者的想法如下:
所以结论是什么呢?
另外,胖友在理解分布式事务时,一定要记住,分布式事务需要由多个本地事务组成。无论是上述的那种事务组件模型,它们都是扮演一个协调者,使多个本地事务达到最终一致性。而协调的过程中,就非常依赖每个方法操作可以被重复执行不会产生副作用,那么就需要:
Dubbo 如何集成到网关服务,需要思考两个问题:
我们先来看看,市面上有哪些网关服务:
如上三个解决方案,都是基于 HTTP 调用后端的服务。那么,这样的情况下,Dubbo 只能通过暴露 rest://
协议的服务,才能被它们调用。
那么 Dubbo 的 rest://
协议的服务,怎么能够被如上三个解决方案注册发现呢?
spring-cloud-starter-zookeeper-discovery
库。具体可参见 《Service Discovery with Zookeeper》 文章。可能会有胖友问,有没支持 dubbo://
协议的网关服务呢?目前有新的网关开源 Soul ,基于 Dubbo 泛化调用的特性,实现对 dubbo://
协议的 Dubbo 服务的调用。
首先,我们来看看这两个技术栈在国内的流行程度,据艿艿了解到:
这样说起来,仿佛 Spring Cloud 和 Dubbo 是冲突的关系?!
实际上,并不然。我们现在所使用的 Spring Cloud 技术体系,实际上是 Spring Cloud Netflix 为主,例如说:
但是,开源的世界,总是这么有趣。目前 Alibaba 基于 Spring Cloud 的接口,对的是接口,实现了一套 Spring Cloud Alibaba 技术体系,并且已经获得 Spring Cloud 的认可,处于孵化状态。组件如下:
更多的讨论,胖友可以尾随知乎上的 《请问哪位大神比较过 spring cloud 和 dubbo ,各自的优缺点是什么?》 。
艿艿的个人态度上,还是非常看好 Spring Cloud Alibaba 技术体系的。为什么呢?因为 Alibaba 背后有阿里云的存在,提供开源项目和商业服务的统一。?? 这个,是 Netflix 所无法比拟的。例如说:
开源项目
阿里云服务
Tengine
LBS
Dubbo
EDAS
RocketMQ
ONS
这里在抛出一个话题。目前传说 Dubbo 在国外的接受度比较低,那么在 Spring Cloud Alibaba 成功孵化完后,是否能够杀入国外的市场呢?让我们拭目以待。
在聊一丢丢有意思的事情。
事实上,Netflix 已经基本不再维护 Eureka、Hystrix ,更有趣的是,因为网关的事情,Zuul 和 Spring Cloud 团队有点闹掰了,因而后来有了 Spring Cloud Gateway 。因而,Zuul2 后续在 Spring Cloud 体系中的情况,会非常有趣~
另外,Spring Cloud 貌似也实现了一个 LoadBalance 负载均衡组件哟。
面试官心理分析
说实话,就这问题,其实就跟问你如何自己设计一个 MQ 一样的道理,就考两个:
- 你有没有对某个 rpc 框架原理有非常深入的理解。
- 你能不能从整体上来思考一下,如何设计一个 rpc 框架,考考你的系统设计能力。
面试题剖析
其实问到你这问题,你起码不能认怂,因为是知识的扫盲,那我不可能给你深入讲解什么 kafka 源码剖析,dubbo 源码剖析,何况我就算讲了,你要真的消化理解和吸收,起码个把月以后了。
所以我给大家一个建议,遇到这类问题,起码从你了解的类似框架的原理入手,自己说说参照 dubbo 的原理,你来设计一下,举个例子,dubbo 不是有那么多分层么?而且每个分层是干啥的,你大概是不是知道?那就按照这个思路大致说一下吧,起码你不能懵逼,要比那些上来就懵,啥也说不出来的人要好一些。
举个栗子,我给大家说个最简单的回答思路:
- 上来你的服务就得去注册中心注册吧,你是不是得有个注册中心,保留各个服务的信心,可以用 zookeeper 来做,对吧。
- 然后你的消费者需要去注册中心拿对应的服务信息吧,对吧,而且每个服务可能会存在于多台机器上。
- 接着你就该发起一次请求了,咋发起?当然是基于动态代理了,你面向接口获取到一个动态代理,这个动态代理就是接口在本地的一个代理,然后这个代理会找到服务对应的机器地址。
- 然后找哪个机器发送请求?那肯定得有个负载均衡算法了,比如最简单的可以随机轮询是不是。
- 接着找到一台机器,就可以跟它发送请求了,第一个问题咋发送?你可以说用 netty 了,nio 方式;第二个问题发送啥格式数据?你可以说用 hessian 序列化协议了,或者是别的,对吧。然后请求过去了。
- 服务器那边一样的,需要针对你自己的服务生成一个动态代理,监听某个网络端口了,然后代理你本地的服务代码。接收到请求的时候,就调用对应的服务代码,对吧。
这就是一个最最基本的 rpc 框架的思路,先不说你有多牛逼的技术功底,哪怕这个最简单的思路你先给出来行不行?
如果上述描述,胖友看的比较闷逼,可以阅读下徐妈写的 《简单了解 RPC 实现原理》 ,自己动手撸一个最最最基础的 RPC 通信的过程。
因为 Dubbo 实现了大量的抽象,并且提供了多种代码实现,以及大量的 RPC 特性,所以代码量会相对较多。
如果胖友是自己实现一个最小化的 PRC 框架,可能代码量会比想象中的少很多,可能几千行代码就够了。强烈推荐,胖友自己撸起袖子,动起手来。从此之后,你会对 RPC 框架,有更深入的理解。