dubbo-go中如何实现路由规则功能
路由规则( routing rule )是为了改变网络流量所经过的途径而修改路由信息的技术,主要通过改变路由属性(包括可达性)来实现。在发起一次 RPC 调用前起到过滤目标服务器地址的作用,过滤后的地址列表,将作为消费端最终发起 RPC 调用的备选地址。
路由规则设计
在设计之初,首先要考虑的是路由规则应该放在整个服务治理周期的哪个阶段呢?
以下是架构图:
可以看到图中的Router就是路由规则插入的位置,目前路由规则主要用于控制Consumer到Provider之间的网络流量的路由路径。
除此之外还有几个问题需要优先考虑:
-
需要什么功能?
- 通过配置信息生成路由规则,包括:读取并解析本地配置文件,读取并解析配置中心的配置。以责任链模式串联起来。
- 通过路由规则,匹配本地信息与远端服务信息,过滤出可以调用的远端节点,再进行负载均衡。
-
如何设计接口?
通过第一点,我们能设计出来以下接口来实现所需功能。
- 路由规则接口:同于路由规则过滤出可以调用的远端节点。
- 路由规则责任链接口:允许执行多个路由规则。
- 配置信息生成路由规则接口:解析内部配置信息(common.URL)生成对应的路由规则
- 配置文件生成路由规则接口:解析配置文件生成对应的路由规则
-
如何实现本地与远程路由规则配置加载?
- 本地路由规则配置:在原配置加载阶段,新增读取路由配置文件。使用FileRouterFactory解析后生成对应的路由规则,放置到内存中备用。
- 远程路由规则配置:在zookeeper注册并监听静态资源目录后。读取静态资源,筛选符合路由规则配置信息,通过RouterFactory生成对应路由规则,放置到内存中备用。
Router
匹配及过滤远程实例的路由规则
// Router
type Router interface {
// Route determine the target invoker list.
Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker
// Priority return priority in router
// 0 to ^int(0) is better
Priority() int64
// URL return URL in router
URL() common.URL
}
目前已有实现类包括:
- listenableRouter
- AppRouter
- ConditionRouter
- HealthCheckRouter
- FileConditionRouter
RouterChain
执行多个路由规则的责任链
// Chain
type Chain interface {
// Route determine the target invokers list with chain.
Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker
// AddRouters add routers
AddRouters([]Router)
}
FileRouterFactory
生成解析配置文件生成路由规则的工厂类
// RouterFactory router creates factory use for parse config file
type FileRouterFactory interface {
// NewFileRouter create file router with config file
NewFileRouter([]byte) (Router, error)
}
RouterFactory
通过配置信息生成路由规则的工厂类
// RouterFactory router create factory
type RouterFactory interface {
// NewRouter creates router instance with URL
NewRouter(*common.URL) (Router, error)
}
实现
规则类型
条件路由
dubbo-go 中第一个支持的路由规则,允许用户通过配置文件及配置中心管理路由规则。
与之相似的一个概念是 dubbo-go 里面的 group 概念,但是条件路由提供了更加细粒度的控制手段和更加丰富的表达语义。比较典型的使用场景是黑白名单设置,灰度以及测试等。
健康检查路由
在 RPC 调用中,我们希望尽可能地将请求命中到那些处理能力快、处于健康状态的实例,该路由的功能就是通过某种策略断定某个实例不健康,并将其排除在候选调用列表,优先调用那些健康的实例。这里的”健康”可以是我们自己定义的状态,默认实现即当错误比例到达某一个阈值时或者请求活跃数大于上限则认为其不健康,允许用户扩展健康检测策略。
在我们服务治理里面,核心的问题其实就在于如何判断一个实例是否可用。无论是负载均衡、
熔断还是限流,都是对这个问题的解答。所以,这个 feature 是一个很好的尝试。因为我们接下来计划提供的特性,基于规则的限流以及动态限流,都是要解决 “如何断定一个实例是否可用” 这么一个问题。
所以欢迎大家使用这个特性,并向社区反馈各自设定的健康指标。这对我们接下来的工作会有很大的帮助。
标签路由
以 Provider 为维度,通过将某一个或多个服务的提供者划分到同一个分组,约束流量只在指定分组中流转,从而实现流量隔离的目的,可以作为蓝绿发布、灰度发布等场景的能力基础。
- 静态打标:根据配置文件所配置的标签,固定给 Provider 设置标签。
- 动态打标:基于健康检查路由,根据服务不同时刻,不同状态,动态在 Provider 设置适合的标签。
分析
接着,以条件路由在 zookeeper 实现为例,对服务提供者与服务消费者进行整体流程分析。
如何配置条件路由规则
配置条件路由规则既可以通过本地配置文件也能通过远程配置中心进行配置,配置生效流程都是:配置文件 => dubbo 内部协议 => 缓存至应用级内存 => 过滤出可调用节点。
dubbo-admin 【服务治理/条件路由】增加路由规则配置,zookeeper 中会自动生成其对应配置节点,内容均为 dubbo-admin 中设置的配置。
实现Router
以下为必须实现的方法,以下方法用于获取过滤服务端节点配置。
- Route: 根据配置,调用节点与被调用节点,过滤出可调用节点。
- Priority: 路由规则优先级,需要是个正整数。
- URL: 通过路由规则转换出来的 dubbo 内部协议。
使用方法
经过上面设计与实现的分析,大概也能猜测到如何使用:
import (
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/protocol"
_ "github.com/apache/dubbo-go/config_center/zookeeper"
_ "github.com/apache/dubbo-go/cluster/router/condition"
)
如图所示,使用路由规则并不复杂,只需要把对应的依赖引入进来。在包初始化的时候,会创建出来对应的路由规则的实现。比如说加载条件路由、健康检测路由或者标签作为路由规则: