原创分享 dubbo-go 中如何实现路由策略功能

joke59 for dubbogo 开源团队 · 2020年04月23日 · 853 次阅读

可在控制面对服务的路由进行精细控制,是一个成熟 RPC 系统必备的能力之一。作为一个逐步走向成熟的 RPC 系统,Apache/dubbo-go(以下简称 dubbo-go )的最新版本 v1.4 中已经实现了 Condition Router 和 Health Instance First Router 等路由。

实现一个功能,首先要清楚其本质。那到底什么是路由规则,我们为什么需要路由规则?设想这么一个场景:现在要对某服务的新版本进行一次灰度发布,需要将一些对实验流量进行引流到灰度机器,其余流量依旧使用正常服务。此时就可以考虑使用路由策略达到目的。

路由规则( routing rule )是为了改变网络流量所经过的途径而修改路由信息的技术,通过改变路由属性(包括可达性)达到引流的目的。在发起一次 RPC 调用前,它会过滤目标服务器地址,将消费端最终发起 RPC 调用的目标范围限定在过滤后的地址列表。

目标

路由策略的关键点在于:

  1. 设定规则:用户可通过什么方式把路由规则传递给使用方;
  2. 解析规则:涉及到的路由规则的语法,以及对语法的解析。比如,要考虑规则是否支持逻辑运算;
  3. 规则匹配:如何判断一个服务实例是否匹配某条路由规则。

综上,可以总结出 dubbo-go 路由规则的目标有:

  • 支持从多个地方,如本地文件、远程配置中心,读取路由规则信息;
  • 设计一套定义路由规则的简单语法;
  • 保持与 Dubbo 的兼容,降低学习成本;

总体设计

首先要考虑的是:路由规则应该放在整个服务治理周期的哪个阶段呢?dubbo-go 的架构图如下:

可以看到图中的 Router 介于 Cluster 和 LB(load balance) 之间,这就意味着一个请求被发送到哪个服务器,是经过了 Cluster - Router - LB 三层处理的。可以将 Router 看做是一种较小范围的逻辑分组。

而在 Router 内部,将经历三个步骤:读取路由规则,解析路由规则,执行匹配。为了提高程序效率,路由规则的读取和解析都是可以提前完成的,比如在应用启动的时候。

根据上面图中流程,可清楚地明晰 Router 的路由流程。

接口设计

根据前面的目标和总体设计,我们很容易地设计出 Router 的接口。

路由规则接口

Router 是 dubbo-go 路由最核心的接口。它可以理解为,当一个请求(或者说一次调用)过来的时候,判断哪些实例是满足该规则的抽象。其实际代码定义如下:

其核心在于 Route 方法,执行匹配逻辑。目前该接口的实现有:

  • ListenableRouter
  • AppRouter
  • ConditionRouter
  • HealthCheckRouter
  • FileConditionRouter 在现实实现中,不同的不同的路由规则是有优先级的,即 Router 的另一个重要特性:Priority 。它决定了的是路由规则的组织方式。

路由规则链式接口

除了优先级,多个路由规则的执行是有顺序的。有路由规则的 Chain 接口如下:

Chain 实现了对不同路由规则的组织。从命名也可以看出,它是责任链模式的一种应用,通过该接口可将路由规则组成一条链,链中每条规则的输出都是下一条规则的输入。至于整个链路中不同规则的顺序,取决于每个规则的 Priority ,它决定了每条路由规则的排序。

读取路由规则接口

读取路由规则对应 FileRouterFactory 和 RouterFactory 两个接口。一般地,只需要一个 RouterFactory 接口就可以,但考虑到路由规则的不同来源,比如规则可能是从配置文件里面读取过来,也可能是直接在服务的 URL 解析而来,所以我们抽象出来了两个接口:

FileRouterFactory

RouterFactory

我们一般将这两个接口对应本地和远程两种情况:

  • 本地路由规则配置:在原配置加载阶段,新增读取路由配置文件步骤。使用 FileRouterFactory 解析后,生成对应路由规则,然后加载到缓存中。
  • 远程路由规则配置:读取远程配置并且监听其变化,筛选符合路由规则配置信息,通过 RouterFactory 生成对应路由规则,同样加载到缓存中备用。

实现

从图里面可以看出,实现路由规则以兼容 dubbo 为首要目标,降低使用者的学习成本为辅助目标。与配置中心模块相结合,实现路由规则远程统一管理与下发。

规则类型

下面介绍一下 dubbo-go 现有的路由规则实现。

条件路由

Condition Router 作为 dubbo-go 中第一个支持的路由规则实现,允许用户通过配置文件及配置中心管理路由规则。与之相似的一个概念是 dubbo-go 的 group,但是条件路由提供了更加细粒度的控制手段和更加丰富的表达语义。比较典型的使用场景是黑白名单设置,灰度以及测试等。

健康检查路由

在 RPC 调用中,如果希望尽可能地将请求命中到那些处理能力快、处于健康状态的实例,即可以考虑该路由。该路由判定断定某个服务提供者的不健康度,优先调用那些健康的服务实例。对 "健康" 度的判定,dubbo-go 默认的实现策略是:某服务的错误比例到达某一个阈值或者请求活跃数大于上限,则认为其不健康,颇类似于服务熔断。dubbo-go 当然亦允许用户扩展其健康检测策略。

标签路由

以 Provider 为维度,将某一个或多个服务的提供者划分到同一个分组,约束流量只在指定分组中流转,从而实现流量隔离的目的,即为标签路由。它可以作为蓝绿发布、灰度发布等场景的能力基础。

  • 静态打标:根据配置文件所配置的标签,固定给 Provider 设置标签。
  • 动态打标:基于健康检查路由,根据服务不同时刻,不同状态,动态在 Provider 设置适合的标签。

示例

下面以条件路由在 zookeeper 实现为例,对服务提供者与服务消费者进行整体流程分析。

如何配置条件路由规则

可以直接通过 dubbo-admin 进行配置:

这些配置可以分成全局配置和服务配置两类。

全局配置

对应应用级全局路由规则配置。例如:

/dubbo/config/dubbo/user-info-server(应用名).condition-router

上面 schema 配置中,应用名配置为为 user-info-server,即该条规则只对该应用生效。后缀 ".condition-router" 表明该条规则为条件路由。除此之外,还可用 ".tag-router" 表示标签路由。

服务配置

对应服务级所有路由规则配置。例如有如下规则 schema:

/dubbo/com.ikurento.user.UserProvider(服务名)/routers

该规则中服务名为 com.ikurento.user.UserProvider。

除了在控制面板 Dubbo Admin 中下发路由规则外,还可以在本地文件中配置相应的规则。比如说在文件 router_config.yml 中配置:

# dubbo router yaml configure file
priority: 1
force: true
conditions : ["host = 1.1.1.1 => host = 192.168.199.214"]

更多配置方式请参考 条件路由配置。使用 dubbo-go 的路由功能时,注意以以下方式 引入对应的包

总结

dubbo-go 整体路由规则功能实现,已基本对齐 dubbo 2.7.x 版本,目前上文中描述过的条件路由、标签路由与健康检测路由,且支持本地及远端配置路由规则,能满足基本使用场景,但距离完善还有还长远的路。dubbo-go 未来路由功能计划如下:

  1. 更多的配置中心【如 etcd/consul 等】支持,理论上已经支持,但还没测试;
  2. service-router(未支持);
  3. 标签路由-配置中心(未支持);
  4. 目前路由与配置中心结合的代码,对新增路由规则并不友好,有一定接入成本。

本文对 dubbo-go 已有的路由功能进行了总结,至于源码级的分析,本文不作展开。欢迎大家持续关注 dubbo-go 项目【https://github.com/apache/dubbo-go】。

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio
cloudy GoCN 每日新闻 (2020-04-24) 中提及了此贴 04月24日 09:27
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册