Dubbo Cluster

简介

  • 集群 Cluster 用途是将多个服务提供者合并为一个 Cluster Invoker,并将这个 Invoker 暴露给服务消费者

  • 集群模块是服务提供者和服务消费者的中间层,为服务消费者屏蔽了服务提供者的情况,这样服务消费者就可以专心处理远程调用相关事宜

集群容错

cluster

集群工作过程可分为两个阶段:

  1. 在服务消费者初始化期间,集群 Cluster 实现类为服务消费者创建 Cluster Invoker 实例,即上图中的 merge 操作

  2. 在服务消费者进行远程调用时。以 FailoverClusterInvoker 为例,该类型 Cluster Invoker

    • 首先会调用 Directorylist 方法列举 Invoker 列表(可将 Invoker 简单理解为服务提供者)。Directory 的用途是保存 Invoker,可简单类比为 List<Invoker>

    • 注册中心内容变化后,RegistryDirectory 会动态增删 Invoker,并调用 Routerroute 方法进行路由,过滤掉不符合路由规则的 Invoker

    • FailoverClusterInvoker 拿到 Directory 返回的 Invoker 列表后,它会通过 LoadBalanceInvoker 列表中选择一个 Invoker

    • 最后 FailoverClusterInvoker 会将参数传给 LoadBalance 选择出的 Invoker 实例的 invoke 方法,进行真正的远程调用

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

  • Failover Cluster - 失败自动切换

  • Failfast Cluster - 快速失败

  • Failsafe Cluster - 失败安全

  • Failback Cluster - 失败自动恢复

  • Forking Cluster - 并行调用多个服务提供者

源码分析

1 Cluster 实现类分析

Cluster 是接口,而 Cluster Invoker 是一种 Invoker。服务提供者的选择逻辑,以及远程调用失败后的的处理逻辑均是封装在 Cluster Invoker

  • FailoverCluster: 用于创建 FailoverClusterInvoker 对象

  • FailbackCluster: 用于创建 FailbackClusterInvoker 对象

2 Cluster Invoker 分析

  • AbstractClusterInvoker: 各种 Cluster Invoker 的父类

  • AbstractClusterInvoker+invoke(final Invocation invocation): 用于列举 Invoker,以及加载 LoadBalance。最后再调 doInvoke 进行后续操作

  • AbstractClusterInvoker#doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance): 抽象方法,由子类实现

  • AbstractClusterInvoker#list(Invocation invocation): 调用 Directorylist 方法

2.1 FailoverClusterInvoker

FailoverClusterInvoker 在调用失败时,会自动切换 Invoker 进行重试。默认配置下,Dubbo 会使用这个类作为缺省 Cluster Invoker

  • doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance):

    • 获取重试次数

    • 根据重试次数进行循环调用,失败后进行重试。在 for 循环内:

      • 通过负载均衡组件选择一个 Invoker

      • 再通过这个 Invokerinvoke 方法进行远程调用

      • 如果失败了,记录下异常,并进行重试。重试时会再次调用父类的 list 方法列举 Invoker

  • select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected):

    • 获取 sticky 配置,sticky 表示粘滞连接。所谓粘滞连接是指让服务消费者尽可能的调用同一个服务提供者,除非该提供者挂了再进行切换

    • 检测 invokers 列表中是否包含 stickyInvoker,如果不包含,则认为该 stickyInvoker 不可用,此时将其置空。这里的 invokers 列表可以看做是存活着的服务提供者列表

    • 如果 stickyInvoker 存在于 invokers 列表中,检测 selected 中是否包含 stickyInvoker

      • 如果包含,说明 stickyInvoker 在此之前没有成功提供服务(但其仍然处于存活状态)

      • 如果不包含,此时还需要进行可用性检测,比如检测服务提供者网络连通性等

    • 当可用性检测通过,才可返回 stickyInvoker,否则调用 doSelect 方法选择 Invoker

    • 如果 stickytrue,此时会将 doSelect 方法选出的 Invoker 赋值给 stickyInvoker

  • doSelect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected):

    1. 通过负载均衡组件选择 Invoker

    2. 如果选出来的 Invoker 不稳定,或不可用,此时需要调用 reselect 方法进行重选

  • reselect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected, boolean availablecheck):

    1. 查找可用的 Invoker,并将其添加到 reselectInvokers 集合中

    2. 如果 reselectInvokers 不为空,则通过负载均衡组件再次进行选择

2.2 FailbackClusterInvoker

FailbackClusterInvoker

  • doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance): 负责初次的远程调用

  • addFailed(Invocation invocation, AbstractClusterInvoker<?> router): 在开始阶段会根据 retryFuture 为空与否,来决定是否开启定时任务

  • retryFailed(): 包含了失败重试的逻辑

    • failed 进行遍历

    • 依次对 Invoker 进行调用

    • 调用成功则将 Invokerfailed 中移除,调用失败则忽略失败原因

2.3 FailfastClusterInvoker

FailfastClusterInvoker

  • doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance):

    • 通过 select 方法选择 Invoker

    • 进行远程调用。如果调用失败,则立即抛出异常

2.4 FailsafeClusterInvoker

失败安全是指,当调用过程中出现异常时,FailsafeClusterInvoker 仅会打印异常,而不会抛出异常

  • 应用场景:写入审计日志等操作

  • doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)

2.5 ForkingClusterInvoker

ForkingClusterInvoker: 在运行时通过线程池创建多个线程,并发调用多个服务提供者。只要有一个服务提供者成功返回了结果,doInvoke 方法就会立即结束运行

  • 应用场景:在一些对实时性要求比较高读操作(注意是读操作,并行写操作可能不安全)下使用,但这将会耗费更多的资源

  • doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance):

    • 选出 forksInvoker,为接下来的并发调用提供输入

    • 通过线程池并发调用多个 Invoker,并将结果存储在阻塞队列中

    • 从阻塞队列中获取返回结果,并对返回结果类型进行判断。如果为异常类型,则直接抛出,否则返回

2.6 BroadcastClusterInvoker

BroadcastClusterInvoker 会逐个调用每个服务提供者,如果其中一台报错,在循环调用结束后,BroadcastClusterInvoker 会抛出异常

  • 应用场景:通知所有提供者更新缓存或日志等本地资源信息

  • doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)

References