Skip to content

服务路由之规则路由

Haotian Zhang edited this page Jul 4, 2024 · 14 revisions

目录

规则路由简介

元数据路由和就近路由本质上是基于服务实例的元数据进行筛选,是为了支持具体特定的场景而内置的服务路由能力。无需下发任何路由规则,使用起来非常简单。

而实际业务场景非常复杂,例如以下几种典型的业务场景:

  • 内部员工路由到一套生产灰度环境,外部普通用户则路由到生产正式环境。(ps:灰度环境是一种特殊的生产环境,只是服务于内部员工,常用于新版本灰度)
  • VIP 客户路由到一套高保环境,普通客户路由到普通环境

以上两种业务场景,则无法通过元数据路由或者就近路由实现。因为涉及到业务请求参数,而不是系统维度的环境变量。

规则路由就是用于满足复杂业务场景而实现的一套基于规则的服务路由实现。由于规则模型设计的非常灵活,所以能够满足绝大多数复杂的业务场景。简化的架构图如下图所示:

image

从以上介绍可知,规则路由的核心在于服务路由的规则模型,后续讲会详细讲解规则模型。

规则路由操作篇

步骤一:基础操作

注意:1.5.0 版本后才支持规则数据路由

请参考 服务路由基础操作 文档,引入依赖以及增加配置。

步骤二:服务实例染色

服务实例染色即服务实例启动的时候,通过某些方式获取到当前实例的元信息,并注册到注册中心时携带元信息。如何染色请参考 服务注册元数据

步骤三:通过控制面下发路由规则

还是以 OrderSerivce 调用 UserService 为例,

image

OrderSerivce 称为主调端,而 UserSerivce 称为被调端。

这里需要理解一下,路由规则附属的实体以及实际执行路由规则的实体的定义。

路由规则附属的实体

路由规则附属的实体,指的是在界面上配置路由规则时,是在哪个服务上配置路由规则。既可以配置在主调端的 Outbound 规则上,也可以配置再被调端的 Inbound 规则上。当有规则冲突时,主调端的 Outbound 规则优先级高于 被调端的 Inbound 规则。

执行路由规则的实体

执行路由规则的实体,指的是实际运行时发起服务调用并按照路由规则路由的实体,所以执行路由规则的实体是主调端,也就是 OrderService

路由规则模型详解

路由本质上解决的是 “哪些请求,去哪里” 的问题,所以拆解来看,模型核心是两部分,既 “哪些请求” 和 “去哪里”。

“哪些请求” 也就是流量筛选,例如:

  • 来自调用方 OrderService 的请求
  • 用户 id 末尾是偶数的请求
  • 请求中带有某个流量标签的请求

“去哪里” 也就是流量目的地,例如:

  • 满足某些条件的流量去蓝组,其它请求去绿组
  • 满足某些条件的流量去高保环境分组,其它请求去普通环境分组

流量筛选

根据主调方服务名

这部分很好理解,在界面上新建路由规则时,对应以下截图部分: image

根据标签筛选请求

在服务调用,服务治理模型里,如何区分请求?答案是通过流量标签。标签是最高维度的抽象,所有不同的业务场景到流量治理层面都转化为标签。例如,uid 是一个标签,env 也是一个标签。

流量标签来源一:链路传递的元数据

可以通过两种方式在流量链路上传递元数据标签。

方式一:起始节点 Transitive 标签

例如 SvcA -> SvcB -> SvcC 链路,SvcA 节点定义的 Transitive 标签,都会自动在链路上传递。例如 SvcA 定义了

`SCT_METADATA_CONTENT_ENV=dev1`
`SCT_METADATA_CONTENT_TRANSITIVE=ENV`

这样 ENV=dev1 就会在链路上传递,每个节点都可以拿到 ENV 信息。

image

方式二:请求 Header 中设置传递标签

很多公司都会把网关作为流量的入口,网关全局一套,这样就无法通过起始节点的环境变量来区分流量链路了。所以需要一种动态请求打标的能力,如下图所示:

image

网关的主调方通过在请求里增加 X-SCT-Metadata-Transitive-${key}=value 就能对流量进行动态打标。

流量标签来源二:请求 Query、Header、Cookie 等参数解析

把 Http 请求里的某些字段作为流量标签,并且只针对带有某些标签的请求进行限流。例如 Query Param 有一个 uid 字段,期望只对某些 uid 限流。

场景一:SCT 版本 < 1.8.1,Polaris 版本 < 1.12.0

老版本的 SCT 和 Polaris 为了支持这种场景,我们定义了一套标签规则表达式,例如 ${http.query.uid} 表示请求 Query Param 里的 uid 字段,如下图所示,表示 uid=1000 的用户。

image

当前支持的标签规则表达式如下:

  • ${http.query.xxx}
    • 表示查询请求的参数
  • ${http.header.xxx}
    • 表示请求头里的参数
  • ${http.cookie.xxx}
    • 表示 cookie 里的参数
  • ${http.method}
    • 表示请求的方法,GET、POST、PUT 等
  • ${http.uri}
    • 表示请求的 Path,注意 / 开头,例如:/user

场景二:SCT < 1.8.1,Polaris 版本 >= 1.12.0

北极星从 1.12.0 之后,支持了页面选择 HeaderQuery 等参数表单,但是格式有所不同,例如 $header.user,所以低版本的 SCT 解析不了这种格式。

image

SCT 1.8.1 版本之后,兼容了 $header.user 格式。所以如果您的 SCT 版本低于 1.8.1 可通过自定义标签来实现,表达式格式和上一节一致,如下图所示:

image

场景三:SCT 版本 >= 1.8.1

高版本的 SCT 兼容了所有格式。

流量标签来源三:自定义 SPI 解析 Http Request

在一些复杂的场景下,内置的标签表达式可能无法支持,比如请求 Body 业务对象中的某个参数等。此时可以通过实现 RouterLabelResolver SPI 来自定义从请求中获取标签。

流量目的地

流量目的地则非常简单,主调方通过从注册中心获取到实例信息,并且每一个实例都会有元数据信息。通过实例的元信息来划分流量目的地分组。 如下图所示:

image

筛选之后的流量,50%env=blue 组,50% 去 env=green 组。

Actuator Endpoint

Spring Cloud Tencent 扩展了 Spring Boot 标准的 Actuator 能力,通过 Actuator 接口,可以实时查询当前运行实例内存里下发的路由规则,便于排查问题。详细可以参考: Actuator Endpoint 扩展

规则路由原理篇

只要理解了 “哪些流量,去哪里” 并且“在服务调用,服务治理领域里最高抽象是标签” 这两个核心点,就很好理解。

以 feign 调用为例,例如调用 http://user-serivce/user/get

  1. 根据服务名(user-service)获取目标服务全量实例地址集合
  1. 根据元数据路由规则从全量实例中挑出部分满足规则的实例子集
  • 这一步中,SCT 会执行一次地址 Filter 链,输入是全量地址,输出是经过所有地址 Filter 之后的结果。其中一个 Filter 就是规则路由 Filter RuleBasedRouter。执行 Filter 链的调用代码请参考:PolarisLoadBalancerCompositeRule#doRouter
  • RuleBasedRouter 的核心逻辑就是根据下发的路由规则去匹配流量以及根据权重挑选流量目的地。
  1. 根据第二步的实例子集,执行负载均衡策略,选中其中一个实例。并替换请求 Url 例如:http://192.168.1.1:8080/user/get
Clone this wiki locally