概述

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 分布式服务框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。她最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo 采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
官网
官方GitHub

Dubbo 架构

8-Dubbo 简介 - 图1

节点角色说明

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费者
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行器

原理

Nacos 能实现 HTTP 和 RPC 通信,我们用 Dubbo 生成服务提供者和服务消费。
如下图,三个服务提供者有三个 IP ,这个三个 IP 回注册到 Nacos 注册中心中,并由 Wathcher Table 观察着,服务消费者从注册中心拿到 IP 缓存到自己本地服务中,这样就可以直接链接服务提供者,提高响应速度。
当服务提供者有个服务挂掉了,注册中心的观察着就会把挂掉的 IP 异步同步到消费者本地缓存中,更新可以 IP。

image.png
image.png

调用关系说明

  • 服务容器负责启动,加载,运行服务提供者
  • 服务提供者在启动时,向注册中心注册自己提供的服务
  • 服务消费者在启动时,向注册中心订阅自己所需的服务
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

    Dubbo 功能特性

  • 面向接口代理的高性能RPC调用: 提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节

  • 智能负载均衡: 内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量
  • 服务自动注册与发现: 支持多种注册中心服务,服务实例上下线实时感知
  • 高度可扩展能力: 遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization 被设计为扩展点,平等对待内置实现和第三方实现
  • 运行期流量调度: 内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能
  • 可视化的服务治理与运维: 提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数

    附:扩展阅读

    什么是 RPC

    分布式是促使RPC诞生的领域,RPC是一种编程模型,并没有规定你具体要怎样实现,无论使用 HTTP 或者是 RMI 都是可以的。

假设你有一个计算器接口,Calculator,以及它的实现类Calculatorlmpl,那么在系统还是单体应用时,你要调用Calculator的 add方法来执行一个加运算,直接new一个Calculatorlmpl,然后调用add方法就行了,这其实就是非常普通的本地函数调用,因为在同一个地址空间,或者说在同一块内存,所以通过方法栈和参数栈就可以实现。
image.png
现在,基于高性能和高可靠等因素的考虑,你决定将系统改造为分布式应用,将很多可以共享的功能都单独拎出来.比如上面说到的计算器,你单独把它放到一个服务里头,让别的服务去调用它。
image.png
这下问题来了,服务A里头并没有Calculatorlmpl 这个类,那它要怎样调用服务B的Calculatorlmpl的add方法呢?

RPC要解决的两个问题

  • 解决分布式系统中,服务之间的调用问题
  • 远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑

    如何实现一个 RPC

    实际情况下,RPC很少用到HTTP协议来进行数据传输,毕竟我只是想传输一下数据而已,何必动用到一个文本传输的应用层协议呢,我为什么不直接使用二进制传输?比如直接用Java的Socket 协议进行传输?

不管你用何种协议进行数据传输,一个完整的RPC过程,都可以用下面这张图来描述
image.png
以左边的Client端为例,Application就是RPC的调用方,Client Stub就是我们上面说到的代理对象,也就是那个看起来像是Calculator的实现类,其实内部是通过RPC方式来进行远程调用的代理对象,至于Client Run-time Library,则是实现远程调用的工具包,比如JDK的 Socket,最后通过底层网络实现层实现数据的传输。

这个过程中最重要的就是序列化和反序列化了,因为数据传输的数据包必须是二进制的,你直接丢一个Java对象过去,人家可不认识,你必须把Java对象序列化为二进制格式,传给Server端,Server端接收到之后,再反序列化为Java对象。

RPC vs RestFul

RPC是面向过程,Restful是面向资源,并且使用了HTTP动词。从这个维度上看,Restful风格的URL在表述的精简性、可读性上都要更好。

阿里为何放弃Zookeeper

CAP

有个思考,从CAP角度考虑,服务注册中心是CP系统还是AP系统呢?

  • 服务注册中心是为了服务间调用服务的,那么绝对不允许因为服务注册中心出现了问题而导致服务间的调用出问题
  • 假如有node1,node2,node3集群节点。保存着可用服务列表ip1,ip2,ip23,试想如果此时不一致,比如node1只保存了ip1,ip2,此时服务读取node1的节点,那么会造成什么影响?

调用node1的服务,顶多就是负载均衡时不会有流量打到ijp3,然后等node1同步回i23后,又一致了,这对服务其实没什么太大影响。所以,推测出服务注册中心应该是个AP系统。

zookeeper是个CP系统,强一致性

  • 场景1,当master挂了,此时Zookeeper集群需要重新选举,而此时服务需要来读取可用服务,是不可用的。影响到了服务的可用性当然你可以说服务本地有缓存可用列表。然而下面这种方式就更无法处理了。
  • 场景2,分区可用。试想,有3个机房,如果其中机房3和机房1,2网络断了,那么机房3的注册中心就不能注册新的机器了,这显然也不合理从健康检查角度来看

Zookeeper是通过TCP的心跳判断服务是否可用,但TCP的活性并不代表服务是可用的,如:连接池已满,DB挂了等

理想的注册中心

  • 服务自动注册发现。最好有新的服务注册上去时还能推送到调用端
  • 能对注册上来的机器方便的进行管理,能手动删除(发送信号让服务优雅下线)、恢复机器
  • 服务的健康检查,能真正的检测到服务是否可用
  • 可以看到是否有其他调用服务正在订阅注册上来的服务
  • 能够带上些除了IP外的其它信息