-
Notifications
You must be signed in to change notification settings - Fork 19
服务路由
当 A 服务调用 B 服务时,先从注册中心获取全量 B 服务地址信息。当没有服务路由,直接进行负载均衡时,根据负载均衡算法从全量 B 服务地址中挑选一个服务实例发起服务调用。 当加入服务路由阶段后,挑选服务实例分为两个阶段:
- 阶段一:从全量服务地址中根据路由规则选取一批目标服务地址
- 阶段二:从阶段一选取的一批目标服务地址中,再根据负载均衡算法挑选一个实例
需要明确一下概念:
- 服务路由 :根据路由规则从全量实例列表中,挑选一部分实例
- 负载均衡 :根据负载均衡算法,从一批实例中挑选一个实例
服务路由具有广泛的使用场景,例如金丝雀发布、灰度发布、蓝绿发布、按机房收敛流量等。
gRPC-Java不具备服务路由的能力。 gRPC-Java-polaris
则在SubchannelPicker扩展了路由能力。集成了 Polaris 的路由功能,提供了开箱即用的路由能力。
服务路由实现的原理非常简单,从注册中心获取全量的健康的服务实例列表,再经过一系列的 RouterFilter 插件过滤出满足条件的实例列表。不同的服务路由类型即是其中一个 RouterFilter 实现,用户也可以自定义 RouterFilter 以实现自身特殊的服务路由场景。
目前 gRPC-Java-polaris
内置了基于规则的服务路由能力
元数据路由和就近路由本质上是基于服务实例的元数据进行筛选,是为了支持具体特定的场景而内置的服务路由能力。无需下发任何路由规则,使用起来非常简单。
而实际业务场景非常复杂,例如以下几种典型的业务场景:
- 内部员工路由到一套生产灰度环境,外部普通用户则路由到生产正式环境。(ps:灰度环境是一种特殊的生产环境,只是服务于内部员工,常用于新版本灰度)
- VIP 客户路由到一套高保环境,普通客户路由到普通环境
以上两种业务场景,则无法通过元数据路由或者就近路由实现。因为涉及到业务请求参数,而不是系统维度的环境变量。
规则路由就是用于满足复杂业务场景而实现的一套基于规则的服务路由实现。由于规则模型设计的非常灵活,所以能够满足绝大多数复杂的业务场景。简化的架构图如下图所示:
从以上介绍可知,规则路由的核心在于服务路由的规则模型,后续讲会详细讲解规则模型。
无论哪种服务路由,在服务注册发现领域模型里,本质上就是实例以及实例的元数据标签。所以规则路由通常也依赖于服务实例的元数据打标能力。
Map<String, String> metadata = new HashMap<>();
metadata.put("env", args[0]);
Server polarisGrpcServer = PolarisGrpcServerBuilder
.forPort(0)
.namespace("default")
.applicationName("RouterServerGRPCJava")
.metadata(metadata)
.heartbeatInterval(5)
.build();
还是以 OrderSerivce
调用 UserService
为例,
OrderSerivce
称为主调端,而 UserSerivce
称为被调端。
这里需要理解一下,路由规则附属的实体以及实际执行路由规则的实体的定义。
路由规则附属的实体
路由规则附属的实体,指的是在界面上配置路由规则时,是在哪个服务上配置路由规则。既可以配置在主调端的 Outbound 规则上,也可以配置再被调端的 Inbound 规则上。当有规则冲突时,主调端的 Outbound 规则优先级高于 被调端的 Inbound 规则。
执行路由规则的实体
执行路由规则的实体,指的是实际运行时发起服务调用并按照路由规则路由的实体,所以执行路由规则的实体是主调端,也就是 OrderService
。
路由本质上解决的是 “哪些请求,去哪里” 的问题,所以拆解来看,模型核心是两部分,既 “哪些请求” 和 “去哪里”。
“哪些请求” 也就是流量筛选,例如:
- 来自调用方 OrderService 的请求
- 用户 id 末尾是偶数的请求
- 请求中带有某个流量标签的请求
“去哪里” 也就是流量目的地,例如:
- 满足某些条件的流量去蓝组,其它请求去绿组
- 满足某些条件的流量去高保环境分组,其它请求去普通环境分组
这部分很好理解,在界面上新建路由规则时,对应以下截图部分:
在服务调用,服务治理模型里,如何区分请求?答案是通过流量标签。标签是最高维度的抽象,所有不同的业务场景到流量治理层面都转化为标签。例如,uid 是一个标签,env 也是一个标签。
把 gRPC 请求里的某些字段作为流量标签,是最常见的场景。例如 Metadata 有一个 uid 字段,期望通过 uid 来过滤流量。为了支持这种场景,我们定义了一套标签规则表达式,
例如 grpc.header.uid
表示请求 Metadata 里的 uid 字段,如下图所示,表示 uid=1000 的用户。
支持的标签规则表达式如下:
- grpc.header.xxx
- 表示请求头里的参数
- grpc.ctx.xxx
- 表示请求上下文里的参数
- sys.env.xxx
- 表示当前进程的系统上下文环境
流量目的地则非常简单,主调方通过从注册中心获取到实例信息,并且每一个实例都会有元数据信息。通过实例的元信息来划分流量目的地分组。 如下图所示:
筛选之后的流量,50% 去 env=blue
组,50% 去 env=green
组。
只要理解了 “哪些流量,去哪里” 并且“在服务调用,服务治理领域里最高抽象是标签” 这两个核心点,就很好理解。