可在控制面对服务的路由进行精细控制,是一个成熟 RPC 系统必备的能力之一。作为一个逐步走向成熟的 RPC 系统,Apache/dubbo-go(以下简称 dubbo-go )的最新版本 v1.4 中已经实现了 Condition Router 和 Health Instance First Router 等路由。
实现一个功能,首先要清楚其本质。那到底什么是路由规则,我们为什么需要路由规则?设想这么一个场景:现在要对某服务的新版本进行一次灰度发布,需要将一些对实验流量进行引流到灰度机器,其余流量依旧使用正常服务。此时就可以考虑使用路由策略达到目的。
路由规则( routing rule )是为了改变网络流量所经过的途径而修改路由信息的技术,通过改变路由属性(包括可达性)达到引流的目的。在发起一次 RPC 调用前,它会过滤目标服务器地址,将消费端最终发起 RPC 调用的目标范围限定在过滤后的地址列表。
目标
路由策略的关键点在于:
1、设定规则:用户可通过什么方式把路由规则传递给使用方;
2、解析规则:涉及到的路由规则的语法,以及对语法的解析。比如,要考虑规则是否支持逻辑运算;
3、规则匹配:如何判断一个服务实例是否匹配某条路由规则。
综上,可以总结出 dubbo-go 路由规则的目标有:
1、支持从多个地方,如本地文件、远程配置中心,读取路由规则信息;
2、设计一套定义路由规则的简单语法;
3、保持与 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
我们一般将这两个接口对应本地和远程两种情况:
1、本地路由规则配置:在原配置加载阶段,新增读取路由配置文件步骤。使用 FileRouterFactory 解析后,生成对应路由规则,然后加载到缓存中。
2、远程路由规则配置:读取远程配置并且监听其变化,筛选符合路由规则配置信息,通过 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 filepriority: 1force: trueconditions : ["host = 1.1.1.1 => host = 192.168.199.214"]
更多配置方式请参考条件路由配置。使用 dubbo-go 的路由功能时,注意以以下方式 引入对应的包:
条件路由配置:
http://dubbo.apache.org/zh-cn/docs/user/demos/routing-rule.html
总结
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
作者信息:
邹毅贤,Github ID @zouyx,开源爱好者,就职于 SheIn 供应链部门,负责供应链开放平台。
本文缩略图:icon by cg尐愳