大规模服务网格性能优化 | Aeraki xDS 按需加载

语言: CN / TW / HK

钟华,腾讯云专家工程师,Istio project member、contributor,专注于容器和服务网格,在容器化和服务网格生产落地方面具有丰富经验,目前负责 Tencent Cloud Mesh 研发工作。

Istio 在大规模场景下 xDS 性能瓶颈

xDS 是 istio 控制面和数据面 envoy 之间的通信协议,x 表示包含多种协议的集合,比如:LDS 表示监听器,CDS 表示服务和版本,EDS 表示服务和版本有哪些实例,以及每个服务实例的特征,RDS 表示路由。可以简单的把 xDS 理解为,网格内的服务发现数据和治理规则的集合。 xDS 数据量的大小和网格规模是正相关的。

当前 istio 下发 xDS 使用的是全量下发策略,也就是网格里的所有 sidecar,内存里都会有整个网格内所有的服务发现数据。比如下图,虽然 workload 1 在业务逻辑上只依赖 service 2, 但是 istiod 会把全量的服务发现数据(service 2、3、4)都发送给 workload 1。

这样的结果是,每个 sidecar 内存都会随着网格规模增长而增长,下图是我们 对网格规模和内存消耗做的一个性能测试 ,x 轴是网格规模,也就是包含多少个服务实例,y 轴是单个 envoy 的内存消耗。

可以看出,如果网格规模超过 1万个实例,单个 envoy 的内存超过了 250 兆,而整个网格的开销还要再乘以网格规模大小。

Istio 当前优化方案

针对这个问题,社区提供了一个方案,就是 Sidecar [1] 这个 CRD,这个配置可以显式的定义服务之间的依赖关系,或者说可见性关系。比如下图这个配置的意思就是 workload 1 只依赖 service 2 ,这样配置以后,istiod 只会下发 service 2 的信息给 workload 1。

这个方案本身是有效的。但这种方式在大规模场景下很难落地:首先这个方案需要用户提前配置服务间完整的依赖关系,大规模场景下的服务依赖关系很难梳理清楚,而且通常依赖关系也会随着业务的变化而变化。

Aeraki Lazy xDS

针对上述问题, TCM [2] 团队设计了一套无入侵的 xDS 按需加载方案,并开源到 github Aeraki [3] 项目,这是 Lazy xDS 具体的实现细节:

我们在网格里增加2个组件, 一个是 Lazy xDS Egress ,Egress 充当类似网格模型中默认网关角色, 另一个是 Lazy xDS Controller ,用来分析并补全服务间的依赖关系。

  1. 首先配置 Egress 的服务中转能力:Egress 会获取网格内所有服务信息,并配置所有 HTTP 服务的路由,这样充当默认网关的 Egress 就可以转发网格内任意 HTTP 服务的流量。

  2. 第2步,对于开启了按需加载特性的服务(图中 Workload 1),利用 envoyfilter,将其访问网格内 http 服务的流量,都路由到 egress。

  3. 第3步,利用 istio sidecar CRD,限制 Workload 1 的服务可见性。

  4. 经过步骤3后,Workload 1 初始只会加载最小化的 xDS。

  5. 当 Workload 1 发起对 Service 2 的访问时,(因为步骤2)流量会转发到 Egress。

  6. (因为步骤 1)Egress 会分析接收到的流量特征,并将流量转发到 Service 2。

  7. Egress 会将访问日志,异步地上报给 Lazy xDS Controller,上报服务是利用 Access Log Service [4]

  8. Lazy xDS Controller 会对接收到的日志进行访问关系分析,然后把新的依赖关系(Workload 1 -> Service 2)表达到 sidecar CRD 中。

  9. 同时 Controller 还会将(步骤2) Workload 1 需要转发 Service 2 流量到 Egress 的规则去除,这样未来 workload 1 再次访问 Service 2 就会是直连。

  10. (因为步骤 8)istiod 更新可见性关系,后续会将 Service 2 的服务信息发给 Workload 1。

  11. Workload 1 通过 xDS 接收到 Service 2 的服务信息。

  12. 当 Workload 1 再次发起对 Service 2 的访问,流量会直达 Service 2(因为步骤9)。

这个方案的好处:

  • 首先不需要用户提前配置服务间的依赖,而且服务间依赖是允许动态的增加的。

  • 最终每个 envoy 只会获得自身需要的 xDS,性能最优。

  • 这个实现对用户流量影响也比较小,用户的流量不会阻塞。性能损耗也比较小,只有前几次请求会在 Egress 做中转,后面都是直连的。

  • 此方案对 istio 和 envoy 没有任何入侵,我们没有修改 istio/envoy 源码,使得这套方案能很好的适应未来 istio 的迭代。

目前我们只支持七层协议服务的按需加载,原因是 流量在 Egress 这里中转的时候,Egress 需要通过七层协议里的 header 判断原始目的地 。纯 TCP 协议是没有办法设置额外的 header。不过因为 istio 主要目的就是为了做七层流量的治理,当网格的大部分请求都是七层的,这个情况目前可以接受的。

Lazy xDS 性能测试

测试方案

在同一网格内的不同 namespace 中,我们创建了 2 组 book info,左边 namespace lazy-on 中 productpage 开启按需加载,右边 namespace lazy-off 保持默认情况。

然后在这个网格内,我们逐渐增加服务数量,使用的是 istio 官方 负载测试工具集 [5] (以下简称「负载服务」),每个 namespace 里有 19 个服务, 其中4个 tcp 服务,15个 http 服务,每个服务初始 pod 数目为 5,共95个 pod(75 个http,20 个tcp)。我们逐渐增加负载服务的 namespace 数量, 用于模拟网格规模增长。

性能对比

首先是 CDS 和 EDS 的对比,下图每组数据代表负载服务 namespace 的增加,每组数据里 4 个值:前 2 个值是开启按需加载后的 CDS 和 EDS,后面 2个值是没开启按需加载的 CDS 和 EDS。

接下来是内存对比,绿色数据表示开启按需加载后 envoy 的内存消耗,红色的是未开启的情况。900 pods 规模 mesh,envoy 内存减少 14M ,降低比例约 40%;一万 pods 规模 mesh,envoy 内存减少约 150M,降低比例约 60%。

随着服务可见性的限制,envoy 不会再接收全量的 xDS 更新,下图是在测试周期内 envoy 接收到 CDS 更新次数的对比,开启按需加载后,更新次数从 6 千次降低到了 1 千次。

小结

Lazy xDS 已经在 github 开源,请访问 lazyxds README [6] 了解如何使用。

Lazy xDS 功能还在持续演进,未来我们将 支持多集群模式、ServiceEntry 按需加载 等功能。

如果您希望了解更多关于 Aeraki 的内容,欢迎访问 Github 主页: https://github.com/aeraki-framework/aeraki

参考资料

[1]

Sidecar: 【 https://istio.io/latest/docs/reference/config/networking/sidecar/

[2]

TCM: https://cloud.tencent.com/product/tcm

[3]

Aeraki: https://github.com/aeraki-framework/aeraki

[4]

Access Log Service: https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/accesslog/v3/als.proto.html

[5]

负载测试工具集: https://github.com/istio/tools/tree/master/perf/load

[6]

lazyxds README: https://github.com/aeraki-framework/aeraki/blob/master/lazyxds/README.md

重磅介绍

【燎原社】推出了专业而又系统的线下云原生技术实战营,需要系统化深入学习的同学,可扫码报名云原生技术实战营课程,腾讯云技术专家现场教学,3天搞定云原生容器化改造过程中的实际问题,扫码一键直达:

往期精选推荐  

点个 “在看” 每天学习最新技术