kitex icon indicating copy to clipboard operation
kitex copied to clipboard

Proposal: Kitex support xDS Protocol

Open CoderPoet opened this issue 3 years ago • 4 comments

背景

希望 Kitex 能够原生支持 xDS 协议 ,让 Kitex 服务能够以 Proxyless 的模式被服务网格统一纳管,从而丰富网格数据面部署架构形态,让用户可以在不同场景下有更多更适合特定场景的部署形态选择

目标

  • 完成 Kitex 对接 xDS 之后整体架构形态设计
  • 完成 Kitex 框架治理能力如何适配 xDS 模型的概要设计

设计介绍

整体架构

image

整体主要有几个模块组成:

  • Control Plane:控制面,负责管理数据面并基于 xDS 协议下发治理规则
  • Kitex Application:Kitex 内部整体主要分为两层
    • xDS 层:
      • xDS Client:封装基于 xDS 协议与控制面交互逻辑
      • xDS Resource Manger:管理 xDS 各协议资源的缓存,并对外提供发布订阅能力
    • 治理能力层:基于框架提供的治理能力拓展机制,来适配 xDS 模型,实现各种数据面治理能力

框架治理能力适配

为了对接治理能力,框架需要做的适配包括以下几部分:

  • [x] 添加 RouterMW,顺序在内置中间件的第一位(动态路由后才能确定之后的配置)。
  • [x] 扩展 Resolver 接口实现 XdsResolver,判断服务发现类型,基于 eds 获取实例信息。
  • [ ] 扩展 LoadBalancer 接口实现 XdsLoadbalancer,根据 cds 动态调整负载均衡策略。

各种治理能力适配思路如下

1. 服务注册

Istio 虽然本身不提供服务注册中心,但是内部维护了统一的服务模型和服务注册表,并且支持集成两种类型的服务注册中心 Provider

  • Kubernetes:基于 K8S APIServer List-Watch ,注册并发现 Kubernetes 上的服务
  • External:注册并发现外部服务,其中外部服务以 ServiceEntries 的形式定义,可以直接 ServiceEntry CRD 描述,也可以通过 MCP-over-xDS 的方式,以外部数据源的方式注册进来

因此,我们在该方案中无需去设计并实现一套服务注册流程了,只需要直接去对接现有的服务注册中心即可。

2. 动态路由

流程大致如下所示: image

  1. 增加一个 xDS Router MW 来负责 Pick Cluster(路由),watch 目标服务的 LDS 及 RDS
  2. 感知 LDS 变化,并提取目标服务的 LDS 中的 Filter Chain 及其 inline RDS
  3. 感知 RDS 变化,根据 VirtualHost 和 ServiceName 来匹配(支持前缀、后缀、精确、通配),获取目标服务的路由配置
  4. 遍历处理匹配到的 RDS 中的路由规则,路由规则主要分为两部分(参考:路由规范定义):
  5. Match(支持前缀、后缀、精确、通配等),目前版本我们支持以下两种即可: 1. Path(必须项):从 rpcinfo 提取 Method进行匹配 2. HeaderMatcher(可选项):可自定义需要匹配的元数据,比如 metainfo 内的 key-value。
  6. Route: 1. Cluster:标准 Cluster 2. WeightedClusters(权重路由):MW 内根据权重来选择 cluster 3. 将选择到的 Cluster 写入 EndpointInfo.Tag,用于之后的服务发现。

3. 服务发现

基于 Kitex 的 Resolver 接口,拓展一个 XDSResolver 来进行服务发现。

  • 根据 RDS 找到对应的 CDS (Pick Cluster)之后,进入 Resolve 阶段,通过根据 CDS 获取对应的 Cluster 配置,包括负载均衡策略、熔断等。之后拉取 EDS 资源以获取实例信息,并根据对应的 LB 策略,pick 出最终的一个 Endpoint。

服务发现类型包括以下几种:

  • Static:直接返回实例的地址
  • Static DNS:数据面需要执行 DNS 解析,以获得所有的实例信息。(异步、周期性地解析)
  • Logical DNS:执行 DNS 解析,只有当需要建立连接时才使用返回实例信息中的第一个。static DNS 的返回结果是完整的实例信息,当两次的结果不同,则需要清理连接。而 logic DNS 则会维持连接,直至被回收。
  • EDS:与控制面交互,发送 eds 请求,以获得实例信息。

4. 负载均衡

Lb policy 包含在 CDS 内,所以 lb 策略的变化是在动态路由选定 cluster 之后获取并应用的。 Kitex 支持自定义 LoadBalancer,实际上就是根据lb策略,从服务发现获得的实例列表内选取一个实例进行调用。

type Loadbalancer interface {
   GetPicker(discovery.Result) Picker // 之后添加入参ctx
   Name() string // unique key
}

如果希望动态调整 lb 策略,需要扩展一个 XDSLoadBalancer 。 在 GetPicker 的实现内完成 lb 策略的获取 (CDS),及不同策略的实现。

5. 超时控制

根据 RDS 中的 timeout 配置来动态调整 RPC Timeout Middleware 的 RPCInfo 中的超时时间即可,实现方式:

  1. xdsRouterMW 内获取到 timeout 配置,设置到 rpcinfo 的 config 中,之后会被用于请求的超时时间设置。

6. 熔断器

Istio 支持的熔断配置相较于 Kitex 会更丰富些,除了异常检测之外,还额外支持对连接池的控制,并且每种熔断策略支持的可配置项也非常完备

我们这期先支持基础的异常检测熔断策略,大致流程如下:

  1. 在 xDS Router MW 中,我们完成 Pick Cluster 的同时,也会拿到相应目标 Cluster 的熔断策略,比如连续请求错误个数(这期我们只考虑异常检测这种熔断策略)
  2. 启用熔断,并调用 CBSuite 的 UpdateServiceCBConfig 和 UpdateInstanceCBConfig 来动态更新 Key 的阈值

7. 重试

RDS 中会携带 retry policy 规则,Kitex 可以根据这个动态调整其客户端重试策略

CoderPoet avatar May 20 '22 03:05 CoderPoet

Hi, @CoderPoet! I am interested in this proposal, is there anything I could help with?

Jacob953 avatar May 24 '22 05:05 Jacob953

Hi, @CoderPoet! I am interested in this proposal, is there anything I could help with?

Very welcome, I have drawn you into the working group, we will dismantle some tasks later!

CoderPoet avatar May 24 '22 07:05 CoderPoet

Istio 服务发现是基于 Kubernetes 实现的. Istio 控制面中,Pilot 组件负责管理服务网格内部的服务和流量策略。Pilot 将服务信息和路由策略转换为 xDS 接口的标准数据结构,下发到数据面的 Envoy. 个人理解,如果只是简单的应用开发,其实不用考虑 xDS 协议底层到底做了些什么,“应用” 和 “网络” 做到解耦。过不过kitex 能从底层支持 xDS 协议,是最好不过了,这样更贴近“云原生”,在相关场景下的应用会更广泛。

dongpoge avatar Jun 16 '22 02:06 dongpoge

Istio 服务发现是基于 Kubernetes 实现的. Istio 控制面中,Pilot 组件负责管理服务网格内部的服务和流量策略。Pilot 将服务信息和路由策略转换为 xDS 接口的标准数据结构,下发到数据面的 Envoy. 个人理解,如果只是简单的应用开发,其实不用考虑 xDS 协议底层到底做了些什么,“应用” 和 “网络” 做到解耦。过不过kitex 能从底层支持 xDS 协议,是最好不过了,这样更贴近“云原生”,在相关场景下的应用会更广泛。

嗯嗯,对的,目的就是为了丰富网格数据面部署架构形态,让用户可以在不同场景下有更多更适合特定场景的部署形态选择

另外稍微补充下 Kubernetes 只是 istio 的服务注册及发现的其中一种,并作为默认的 provider 存在,其实还可以对接外部注册中心的哈

CoderPoet avatar Jun 19 '22 07:06 CoderPoet