ダボフレームワークのアーキテクチャ

まず、全体的なフレームワーク

1、ダボはじめに

Apacheのダボは、高性能、軽量なオープンソースのJava RPCフレームワークです。
リモートメソッド呼び出しのためのインターフェース、インテリジェントなフォールトトレランスと負荷分散、および自動登録やサービスの発見:これは3つのコアコンピタンスを持っています。

1、ダボの特長

開発者のためのリモート呼び出しの基礎となる詳細を遮蔽する高性能ベースのリモートコールエージェントを提供する能力、粒度サービスインターフェイス:高性能インターフェースエージェントRPCコールの1、。
2、インテリジェントロードバランシング:内蔵負荷バランシング戦略、下流ノードのインテリセンスの健康の様々な、大幅システムのスループットを向上させる、通話待ち時間を減少させます。
3、自動サービス登録と発見:レジストリサービス、サービスインスタンスでオフラインリアルタイム知覚の様々なサポート。
図4に示すように、高度にスケーラブルな容量:設計原理は、+プラグイン、このようなプロトコル、トランスポート、シリアル化などのすべての中核能力は、拡張ポイント、等しい治療として設計されたサードパーティの実装を実現するために構築されているマイクロカーネル従います。
5、実行時のトラフィックスケジューリング:内蔵の条件、スクリプト、およびその他のルーティングポリシーの異なるルーティングルールを設定することにより、簡単な優先順位室などの機能で、灰色公開します。
図6は、可視化とサービス管理運用および保守は:豊かなサービス管理、運用、保守ツールを提供します:常に発行サービスメタデータ、サービス、健康状態およびコール統計、リアルタイムでのルーティングポリシーを確認し、設定パラメータを調整します。

2、ダボの欠点

1、クロス言語サポートは弱いです:のみダボ現在人気のJAVA言語で、他の言語ではあまりサポートされています。NAクロスランゲージコール。
2は、レジストリは問題があるこれらのコンポーネントは、サービスコールはすぐに中断され、サードパーティ製のコンポーネント(のZooKeeperまたはRedisの)、に大きく依存しています。

3、業界の他のプログラム

gRPC

Googleは、高性能、汎用オープンソースのRPCフレームワーク、いるProtobuf(プロトコルバッファ)直列化プロトコルの開発を開発している、と多くの開発言語のサポートに基づいています。非Java言語での業界の枠組みでは、GRPCは、最も一般的に使用される一般的なRPCフレームワークです。しかしGRPCにはサービスの発見は、一般的に組み合わせETCDがサービス検出を行う必要はありません。

春、雲

春の雲は、一連のフレームの順序付きコレクションです。その用途は、巧みに、サービス発見、登録、流通センター、メッセージ・バス、ロードバランシング、回路遮断器、監視および他のデータのような分散システム・インフラストラクチャの開発を簡素化、春ブーツの開発の様式で行うことができる春ブーツの開発を促進しますそして、展開を開始するためのキー。

Tomcatの

オープンソースのマイクロブログmotanシーナは、使いやすさのための軽量、RPCフレームワークです。カスタム動的な負荷分散をサポートし、部屋のスケジューリング機能やその他の高度なサービス間でトラフィックシェーピング。本番環境のRPCサービスの可用性を保護するために、高並行性、高負荷のシナリオに基づいて最適化されています。

対照的なフレームワーク

フレーム 開発言語 サービス管理 クロス言語サポート 呼ばれます 管理センター 注意
ダボ ジャワ 飼育係 基本的にはサポートしていません。 TCP サポート 高いです
gRPC 多言語 行わないでください、あなたは自己実現に必要 サポート HTTP サポートしていません。 高いです
飛躍雲 ジャワ 春の雲 ユーレカ サポートしていません。 HTTP-休息 サポート
Tomcatの ジャワ 領事、飼育係 Javaの、行く、PHP TCP サポート

ダボ対dubbox

また、2012年のオープンソースの後にダボとして、何をする半ば2017年に更新されていないので、详细ベースのダボはdubboxのバージョンを改造しました。以下は、次の機能を長くdubboxとダボの比較であります:

  • dubboxサポート残りプロトコル:HTTP + JSON安らかなスタイルの、自分自身の唯一の方法は、TCPダボ
  • dubboxのサポート、より効率的なシリアライズツール:KryoとFST、JSON
  • dubbox比較的ダボクライアントのZooKeeperをアップグレード
  • 組み込みのTomcatに基づいてHTTPリモーティング支援システム。
  • 春はバージョン3.xにアップグレード

2、ダボ全体的なアーキテクチャ

1、ライフサイクルのフレームワーク

ここに画像を挿入説明
上記内部図ダボ、などとの相互作用:

  • サービスプロバイダは、サービスプロバイダを公開します
  • リモートサービスの消費者サービス呼び出し消費者
  • レジストリサービスの登録と発見レジストリ
  • センターサービスおよび通話時間の監視を呼び出し統計の数を監視

调用流程如下所述:
1、服务启动,包括服务提供者和消费者的启动,封装服务调用链路。
2、服务提供者在启动时,向注册中心注册自己提供的服务。
3、服务消费者在启动时,向注册中心订阅自己所需的服务。
4、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
5、服务消费者,从提供者地址列表中,基于服务路由信息、负载均衡规则,选一台提供者进行调用。
6、服务消费者和提供者,在内存中累计调用次数和调用时间,定时发送一次统计数据到监控中心。
7、服务提供方停止服务或者服务调用方关闭JVM的时候,会将provider及consumer进行销毁处理。

2、层级架构

ここに画像を挿入説明
Dubbo框架设计一共划分了10个层,而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。

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

3、源码模块

可以通过Dubbo的代码(使用Maven管理)组织,与上面的模块进行比较。简单说明各个包的情况:

  • dubbo-common 公共逻辑模块,包括Util类和通用模型。
  • dubbo-remoting 远程通讯模块,相当于Dubbo协议的实现,如果RPC用RMI协议则不需要使用此包。
  • dubbo-rpc 远程调用模块,抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。
  • dubbo-cluster 集群模块,将多个服务提供方伪装为一个提供方,包括:负载均衡、容错、路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。
  • dubbo-registry 注册中心模块,基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。
  • dubbo-monitor 监控模块,统计服务调用次数,调用时间的,调用链跟踪的服务。
  • dubbo-config 配置模块,是Dubbo对外的API,用户通过Config使用Dubbo,隐藏Dubbo所有细节。
  • dubbo-container 容器模块,是一个Standalone的容器,以简单的Main加载Spring启动,因为服务通常不需要Tomcat/JBoss等Web容器的特性,没必要用Web容器去加载服务。

二、基础技术

1、dubbo网络通信remoting及线程模型
dubbo中网络通信主要借助通过Netty来实现server及client。在netty接收完消息后,将通过不同的线程模型分配进行业务处理。
1、Dubbo中线程派发Dispatcher分配类型包括:
all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
direct 所有消息都不派发到线程池,全部在 IO 线程上直接执行。
message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
connection 在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。

2、ThreadPool线程池类型:
fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
cached 缓存线程池,空闲一分钟自动删除,需要时重建。
limited 可伸缩线程池,但池中的线程数只会增长不会收缩。只增长不收缩的目的是为了避免收缩时突然来了大流量引起的性能问题。
eager 优先创建Worker线程池。在任务数量大于corePoolSize但是小于maximumPoolSize时,优先创建Worker来处理任务。当任务数量大于maximumPoolSize时,将任务放入阻塞队列中。阻塞队列充满时抛出RejectedExecutionException。(相比于cached:cached在任务数量超过maximumPoolSize时直接抛出异常而不是将任务放入阻塞队列)

3、消息发送涉及到:同步、异步、单向方式
4、dubbo数据包结构:Dubbo 数据包分为消息头和消息体,消息头用于存储一些元信息,比如魔数(Magic),数据包类型(Request/Response),消息体长度(Data Length)等。消息体中用于存储具体的调用消息

5、序列化:在远程通信过程中涉及到序列化内容,主要采用Hessian2。

2、SPI机制

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。
Dubbo中SPI机制类为ExtensionLoader,ExtensionLoader是扩展点载入器,用于载入Dubbo中的各种可配置组件,比如:动态代理方式(ProxyFactory)、负载均衡策略(LoadBalance)、RCP协议(Protocol)、拦截器(Filter)、容器类型(Container)、集群方式(Cluster)和注册中心类型(RegistryFactory)。
SPI 做了三个方面的扩展:
方便获取扩展实现:JDK SPI仅仅通过接口类名获取所有实现,而ExtensionLoader则通过接口类名和key值获取一个实现;
IOC依赖注入功能:Adaptive实现,就是生成一个代理类,这样就可以根据实际调用时的一些参数动态决定要调用的类了。
采用装饰器模式进行功能增强,自动包装实现,这种实现的类一般是自动激活的,常用于包装类,比如:Protocol的两个实现类:ProtocolFilterWrapper、ProtocolListenerWrapper。

Adaptive自适应扩展机制

自适应拓展机制的实现逻辑比较复杂,首先 Dubbo 会为拓展接口(Adaptive )生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类、

当 Adaptive 注解在类上时,Dubbo 不会为该类生成代理类。注解在方法(接口方法)上时,Dubbo 则会为该方法生成代理逻辑。

Adaptive 注解在类上的情况很少,在 Dubbo 中,仅有两个类被 Adaptive 注解了,分别是 AdaptiveCompiler 和 AdaptiveExtensionFactory。此种情况,表示拓展的加载逻辑由人工编码完成。更多时候,Adaptive 是注解在接口方法上的,表示拓展的加载逻辑需由框架自动生成。Adaptive 注解的地方不同,相应的处理逻辑也是不同的。

三、核心功能拆解

1、服务启动

服务启动包括服务暴露及服务引入,主要涉及Exporter及Invoker的包装。

1、服务暴露

Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。整个逻辑大致可分为三个部分,
第一部分是前置工作,主要用于检查参数,组装 URL。

第二部分是导出服务,包含导出服务到本地 (JVM),和导出服务到远程两个过程。

第三部分是向注册中心注册服务,用于服务发现。

ここに画像を挿入説明

2、服务引入

Dubbo 服务引用的时机有两个,第一个是在 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务,第二个是在 ReferenceBean 对应的服务被注入到其他类中时引用。这两个引用服务的时机区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下,Dubbo 使用懒汉式引用服务。如果需要使用饿汉式,可通过配置 dubbo:reference 的 init 属性开启。下面我们按照 Dubbo 默认配置进行分析,整个分析过程从 ReferenceBean 的 getObject 方法开始。当我们的服务被注入到其他类中时,Spring 会第一时间调用 getObject 方法,并由该方法执行服务引用逻辑。按照惯例,在进行具体工作之前,需先进行配置检查与收集工作。接着根据收集到的信息决定服务用的方式,有三种,第一种是引用本地 (JVM) 服务,第二是通过直连方式引用远程服务,第三是通过注册中心引用远程服务。不管是哪种引用方式,最后都会得到一个 Invoker 实例。如果有多个注册中心,多个服务提供者,这个时候会得到一组 Invoker 实例,此时需要通过集群管理类 Cluster 将多个 Invoker 合并成一个实例。合并后的 Invoker 实例已经具备调用本地或远程服务的能力了,但并不能将此实例暴露给用户使用,这会对用户业务代码造成侵入。此时框架还需要通过代理工厂类 (ProxyFactory) 为服务接口生成代理类,并让代理类去调用 Invoker 逻辑。避免了 Dubbo 框架代码对业务代码的侵入,同时也让框架更容易使用。
ここに画像を挿入説明

2、注册中心注册及订阅

服务注册就是把已经暴露的服务信息注册到第三方平台,以供消费者使用。服务注册主要涉及的逻辑在RegistryProtocol.export方法。
服务订阅是消费端订阅所需的服务,并执行服务引用,服务订阅主要在RegistryProtocol 的 refer 方法逻辑。消费端完成订阅后,若注册中心存在服务提供者,那么消费端将对服务为服务做成服务目录,供调用的时候获取地址列表。
目前dubbo支持的注册中心包括zookeeper和redis等,笔者将在详细文档中做源码讲解,下面介绍下消费端如何维护服务列表。

服务字典
服务目录目前内置的实现有两个,分别为 StaticDirectory 和 RegistryDirectory,实际环境中主要使用RegistryDirectory,当注册中心节点信息发生变化后,RegistryDirectory 可以通过此接口方法得到变更信息,并根据变更信息动态调整内部 Invoker 列表。

RegistryDirectory服务字典
RegistryDirectory 收到变更通知后,可根据配置变更信息刷新 Invoker 列表。RegistryDirectory 中有几个比较重要的逻辑,第一是 Invoker 的列举逻辑,第二是接收服务配置变更的逻辑,第三是 Invoker 列表的刷新逻辑。

3、调用链路

ここに画像を挿入説明
Dubbo 服务调用过程比较复杂,包含众多步骤,比如发送请求、编解码、服务降级、过滤器链处理、序列化、线程派发以及响应请求等步骤。
Dubbo 支持同步和异步两种调用方式,其中异步调用还可细分为“有返回值”的异步调用和“无返回值”的异步调用。所谓“无返回值”异步调用是指服务消费方只管调用,但不关心调用结果,此时 Dubbo 会直接返回一个空的 RpcResult。若要使用异步特性,需要服务消费方手动进行配置。默认情况下,Dubbo 使用同步调用方式。
从下往上看,首先服务消费者通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务。这就是一个远程调用请求的发送与接收过程。

1、服务路由

服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由,筛选出符合路由规则的服务提供者。在详细分析服务路由的源码之前,先来介绍一下服务路由是什么。服务路由包含一条路由规则,路由规则决定了服务消费者的调用目标,即规定了服务消费者可调用哪些服务提供者。Dubbo 目前提供了三种服务路由实现,分别为条件路由 ConditionRouter、脚本路由 ScriptRouter 和标签路由 TagRouter。其中条件路由是我们最常使用的。

2、集群

ここに画像を挿入説明
集群工作过程可分为两个阶段:
第一个阶段是在服务消费者初始化期间,集群 Cluster 实现类为服务消费者创建 Cluster Invoker 实例,即上图中的 merge 操作。
第二个阶段是在服务消费者进行远程调用时。以 FailoverClusterInvoker 为例,该类型 Cluster Invoker 首先会调用 Directory 的 list 方法列举 Invoker 列表(可将 Invoker 简单理解为服务提供者)。Directory 的用途是保存 Invoker,可简单类比为 List。其实现类 RegistryDirectory 是一个动态服务目录,可感知注册中心配置的变化,它所持有的 Invoker 列表会随着注册中心内容的变化而变化。每次变化后,RegistryDirectory 会动态增删 Invoker,并调用 Router 的 route 方法进行路由,过滤掉不符合路由规则的 Invoker。当 FailoverClusterInvoker 拿到 Directory 返回的 Invoker 列表后,它会通过 LoadBalance 从 Invoker 列表中选择一个 Invoker。最后 FailoverClusterInvoker 会将参数传给 LoadBalance 选择出的 Invoker 实例的 invoker 方法,进行真正的远程调用。

Dubbo 主要提供了这样几种容错方式:

  • Failover Cluster - 失败自动切换 最为常用
  • Failfast Cluster - 快速失败
  • Failsafe Cluster - 失败安全
  • Failback Cluster - 失败自动恢复
  • Forking Cluster - 并行调用多个服务提供者

3、负载均衡

在 Dubbo 中,也有负载均衡的概念和相应的实现。Dubbo 需要对服务消费者的调用请求进行分配,避免少数服务提供者负载过大。服务提供者负载过大,会导致部分请求超时。因此将负载均衡到每个服务提供者上,是非常必要的。Dubbo 提供了4种负载均衡实现:

  • 基于权重随机算法的 RandomLoadBalance
  • 基于最少活跃调用数算法的 LeastActiveLoadBalance
  • 基于 hash 一致性的 ConsistentHashLoadBalance
  • 基于加权轮询算法的 RoundRobinLoadBalance

4、Fifter链及Monitor监控统计

filter在dubbo中的应用非常广泛,它通过在启动中对服务端及消费端方法前注入fifter链,使得在调用的时候它可以对服务端、消费端的调用过程进行拦截,从而对dubbo进行功能上的扩展。
dubbo中比较常见的fifter链包括:EchoFilter、GenericFilter、TokenFilter、MonitorFilter、ContextFilter等。
其中GenericFilter是泛化调用的核心,它能将调用泛化的url地址转换为真实的类及方法地址。
MonitorFilter是监控统计的核心,MonitorFilter统计计算数据,然后通过DubboMonitor将数据进行聚合,并发送给外界。
GenericFilter及MonitorFilter笔者将在详细文档中做源码剖析。

5、服务优雅销毁停机

呼び出しが全体のリンクを完了した後、レジストリからサービスをキャンセルし、サービスプロバイダを破壊する時間を必要としている点が常にあります。古いサービスでのサービスの切り替え処理で正常にシャットダウンされていない場合、この時間は、それはとても上品なシャットダウンがダボの重要な部分であり、メモリの問題が解消原因に簡単です。
ダボ優雅ダウンタイムは、JDK ShutdownHook機能に依存しています。主に、実行時に登録したフック関数に関連して、フック関数を呼び出すためのイニシアチブを破壊。

公開された72元の記事 ウォン称賛52 ビュー210 000 +

おすすめ

転載: blog.csdn.net/niyuelin1990/article/details/103974106