RPC框架——Dubbo

Dubbo简介

Dubbo是用来实现分布式RPC调用的框架。

Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
Dubbo支持多种协议,包括Dubbo协议、hession协议等,Dubbo协议底部的传输协议是TCP。

Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。其还有注册中心、协议支持、服务监控等内容,详细内容见下。

Dubbo框架

Dubbo框架设计一共划分了10个层,最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。
在这里插入图片描述
框架整体分为十层:

  1. 服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
  2. 配置层(Config):对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类。
  3. 服务代理层(Proxy):服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory。
  4. 服务注册层(Registry):封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory、Registry和RegistryService。可能没有服务注册中心,此时服务提供方直接暴露服务。
  5. 集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster、Directory、Router和LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
  6. 监控层(Monitor):RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory、Monitor和MonitorService。
  7. 远程调用层(Protocol):封将RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
  8. 信息交换层(Exchange):封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger、ExchangeChannel、ExchangeClient和ExchangeServer。
  9. 网络传输层(Transport):抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel、Transporter、Client、Server和Codec。
  10. 数据序列化层(Serialize):可复用的一些工具,扩展接口为Serialization、 ObjectInput、ObjectOutput和ThreadPool。

协议详情:
https://blog.csdn.net/yuer2008200820008/article/details/80208025

Dubbo的特点

1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

Dubbo采用全spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

Dubbo的运作

Dubbo应用时只是关心服务提供者以及服务消费者。
在这里插入图片描述

服务调用过程如下:

  1. 服务提供方(Provider)发布服务到服务注册中心;
  2. 服务消费方(Consumer)从服务注册中心(Registry)订阅服务;
  3. 服务消费方调用已经注册的可用服务;
  4. 监视中心(Monitor)记录调用过程。

过程中角色说明:

  1. Provider: 暴露服务的服务提供方。
  2. Consumer: 调用远程服务的服务消费方。
  3. Registry: 服务注册与发现的注册中心,可以选择Zookeeper作为注册中心,存储Provider注册的远程服务信息。且注册中心和提供方和调用方之间均保持长连接,可以获取Provider发布的服务的变化情况,并将最新的服务列表推送给Consumer
  4. Monitor: 统计服务的调用次调和调用时间的监控中心。
  5. Container: 服务运行容器。

具体过程为:

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

为什需要监控中心呢?

  1. 出错的时候可以及时发现。
  2. 当服务不够用的时候(比如大促),可以通过看服务的调用次数等,推算这个服务需要多少机器支撑?什么时候该加机器?

原文链接:https://blog.csdn.net/baoyu_G/article/details/82314435

Dubbo注册中心

使用Dubbo时,一般将注册中心放在Zookeeper中(当然有Redis、Multicast、Simple做注册中心),而Zookeeper就是用来管理集群的,Zookeeper不是在单独的一台服务器中,而是整个集群中每台机器共同组成了Zookeeper,其中有一台leader服务器来协调其他服务器。

服务的提供者、调用者都是在Zookeeper管理的集群中,如下图:
在这里插入图片描述

过程如下:

  1. 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地 址
  2. 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地 址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
  3. 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地 址。

注意:注册和订阅的都是URL地址信息。

Zookeeper(注册中心)提供的功能:

  1. 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
  2. 当注册中心重启时,能自动恢复注册数据,以及订阅请求
  3. 当会话过期时,能自动恢复注册数据,以及订阅请求

Zookeeper的订阅

zk采用事件通知+客户端拉取的方式订阅。

  1. 在客户端第一次链接到注册中心时,会获取到对应目录下的所有的数据。并且在订阅的节点上注册一个watcher,客户端会与注册中心保持一个tcp的长链接。
  2. 后续每个节点有数据变化的时候,注册中心会根据watcher的回调主动通知客户端,这就是事件通知。
  3. 当客户端接到通知时,会主动拉取对应节点下的全量数据,这就是客户端拉取。

zk的每一个节点都有一个版本号,当节点数据发生变化的时候,节点对应的版本号就会发生变化,并且这个时候会触发watcher通知对应的客户端。

Zookeeper的缓存

基本上每一个场景中,缓存的作用就是用空间换取时间。试想如果每次远程调用的时候都要从注册中心全量拉取一遍服务列表,那么注册中心能撑住主这么大的流量。

所以dubbo的注册中心会有缓存机制,当consumer或者治理中心获取到注册信息之后会进行本地缓存。这也就是为什么注册中心挂了双方还可以进行调用的原因

为什么选用Zookeeper?

Zookeeper的数据模型很简单,有一系列被称为ZNode的数据节点组成,与传统的磁盘文件系统不同的是,zk将全量数据存储在内存中,可谓是高性能,而且支持集群,可谓高可用,另外支持事件监听。这些特点决定了zk特别适合作为注册中心(数据发布/订阅)。

转自:https://www.cnblogs.com/qtlq/p/11296578.html

Dubbo服务暴露过程

大概过程为:

  1. 暴露本地服务
  2. 暴露远程服务
  3. 启动netty
  4. 连接zookeeper
  5. 到zookeeper注册
  6. 监听zookeeper

什么是本地暴露和远程暴露,他们的区别?

在dubbo中我们一个服务可能既是Provider,又是Consumer,因此就存在他自己调用自己服务的情况。如果再通过网络去访问,那自然是舍近求远,因此有本地暴露服务的这个设计来解决这个问题。

本地暴露:是暴露在JVM中,不需要网络通信。
远程暴露:是将ip、端口等信息暴露给远程客户端,调用时需要网络通信。

暴露的过程:

  1. 开始调用export() 方法,判断是否有延迟暴露。
  2. 没有则开始调用doExport方法,进行暴露。
  3. doExport方法先执行一系列的检查方法,然后调用doExportUrls方法。
  4. 调用proxyFactory.getInvoker() 方法获取Invoker,会将服务的实现封装成一个Invoker,Invoker中封装了服务的实现类。
  5. 将Invoker封装成Exporter,并缓存起来,缓存里使用Invoker的url作为key。这中间需要用到Dubbo的协议(Protocol),也就是需要用到,如果是Dubbo协议,也就是DubboProtocol,它会打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由dubbo自己实现。也就是说在暴露过程中,会启动Netty。
  6. 启动Netty,服务端Server启动,监听端口。
  7. 请求来到时,根据请求信息生成key,到缓存查找Exporter,就找到了Invoker,就可以完成调用。

在这里插入图片描述

链接:https://www.jianshu.com/p/292fcdcfe41e
https://www.jianshu.com/p/dcfe426e9cd7

什么是netty

Netty的作用就是网络通信,它是NIO的。

Netty是一个高性能、异步事件驱动的NIO框架,基于JAVA NIO提供的API实现。它提供了对TCP、UDP和文件传输的支持。作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。
Netty结合Selector(由java的NIO提供)和Reactor模式设计了高效的线程模型。

启动Netty就相当于是可以与其他服务器进行网络通信,服务器本身即是Server也是Client。作为Server,服务器可以接收Client的连接请求,并以NIO的方式处理连接的IO请求。

详细内容见:https://www.cnblogs.com/technologykai/articles/10910878.html

Dubbo服务引用过程

首先是订阅服务的过程:

  1. 根据订阅时的配置,准备生成ReferenceBean(生成需要调用的服务实例)。
  2. 创建服务代理,调用ReferenceConfig.createProxy() 方法。
  3. createProxy() 方法又会调用RegistryProtocol的refer() 方法
  4. refer() 方法有需要用到RegistryDirectory。RegistryDirectory 通过 RegistryDirectory.subscribeUrl() 向 Zookeeper 订阅服务节点信息并 watch 变更,这样就实现了服务自动发现。
  5. 创建服务代理成功后,会产生invoker列表

然后是引用服务的过程:

  1. 服务引用时从内存缓存中获取并返回invoker列表。
  2. 通过Router 从invoker 列表中刷选出符合路由规则的 invoker 子集。
  3. 通过 LoadBalance 选择最终的一个目标 invoker,发起服务调用。
  4. 如果调用失败,每次重试时,都通过 LoadBalance ,基于软负载算法,找到合适的服务,选出一个 Invoker 进行调用。
  5. 调用成功,执行方法。

Dubbo负载均衡策略

Dubbo负载均衡有四种策略:

  1. Random LoadBalance(默认):随机策略。按照概率设置权重,比较均匀,并且可以动态调节提供者的权重,按照权重来负载均衡,权重越大分配流量越高,一般就用这个默认的就可以了。
  2. RoundRobin LoadBalance:轮询策略。默认就是均匀地将流量打到各个机器上去,按公约后的权重设置轮询比率。但是如果各个机器的性能不一样,容易导致性能差的机器负载过高,存在执行比较慢的服务提供者堆积请求的情况。所以此时需要调整权重,让性能差的机器承载权重小一些,流量少一些。。
  3. LeastActive LoadBalance:最少活跃调用数。这个就是自动感知一下,如果某个机器性能越差,那么响应就越慢,越不活跃,此时就会给不活跃的性能差的机器更少的请求。如果每个提供者的活跃数相同,则随机选择一个。在每个服务提供者里面维护者一个活跃数计数器,所以如果这个值越小说明当前服务提供者处理的速度很快,所以路由选择时候就选择该活跃度最小的机器。
  4. ConsistentHash LoadBalance:一致性Hash策略。根据服务提供者ip设置hash环,可以保证相同参数的请求总是发到同一提供者,当某一台提供者挂了时,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动。
  • 一致性Hash负载均衡策略原理?

Dubbo的容错策略

当服务消费方调用服务提供者失败后,Dubbo有如下几种容错策略:

  1. failover cluster 失败重试:失败自动切换,自动重试其他机器,默认就是这个,常见于读操作。
  2. failfast cluster 快速失败:一次调用失败就立即报错,也就是只调用一次,常见于写操作。
  3. failsafe cluster 失败安全:出现异常时忽略掉。常用于不重要的接口调用,比如记录日志。
  4. failback cluster 失败自动恢复:失败了后台自动记录请求,然后按照一定的策略后期定时重发,比较适合于写消息队列(消息通知)这种。
  5. forking cluster 并行调用:并行调用多个 provider,只要一个成功就立即返回。
  6. broadcacst cluster 广播调用:逐个调用所有的 provider。

Dubbo实现RPC实例

详细实例查看原文。
转载自:https://blog.csdn.net/houshaolin/article/details/76408399

  • Mock 可以在测试中模拟服务调用的各种异常情况,还用来实现服务降级。
发布了67 篇原创文章 · 获赞 32 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_43751710/article/details/104664150