乐趣区

关于service-mesh:Slime-2022-展望把-Istio-的复杂性塞入智能的黑盒

一、导读

网易数帆轻舟微服务团队很早就开始应用 Istio 做服务网格。在实际过程中,咱们开发了很多 Istio 周边模块,不便了本身及网易团体外部客户应用 Istio。为了回馈社区,咱们零碎整顿了这些模块,并抉择了一部分,在 2021 年初开源出 Slime 我的项目。

Slime 我的项目旨在解决 Istio 应用上的痛点,不便用户应用 Istio 的高级性能,并始终保持 能够无缝对接 Istio,无需任何的定制化革新 的准则,极大升高了应用门槛。

这一年多来,Slime 在架构、性能、工程方面做了很多变动和尝试,失去了很大晋升,并且在 2021 年 12 月受邀退出 Istio 生态,正式成为 Istio Ecosystem – integrations 的成员。

明天,本文将会介绍 Slime 现阶段的次要能力,以懒加载和智能限流模块为主,并展望未来倒退,心愿能让更多的 ServiceMesher 理解 Slime,参加 Slime,一起更轻松地应用服务网格。

二、懒加载

2.1 背景

Istio 的全量推送性能问题,是所有 Istio 使用者都要面对的问题。

家喻户晓,晚期 Istio 的配置下发十分毛糙,间接全量推送。这意味着,随着服务网格中业务规模的不断扩大,管制面须要下发的内容越来越多,数据面须要接管的内容也一直增长,这必然带来性能问题。集群中往往有多个业务零碎。一个业务零碎的利用感知所有业务零碎的配置,这意味着推送大量冗余配置,也是不合理的。如下图左侧所示,A 只和 B 有关系,却被推送了 C 和 D 的配置。另一个问题是,推送的频率会很高。当一个服务发生变化,管制面要告诉数据面所有 SidecarProxy。

于是,Istio 1.1 版本提供了解决方案 – Sidecar CRD(本文会称之为 SidecarScope,以和 Envoy 实现的 SidecarProxy 做辨别)。用户能够在 SidecarScope 中形容 SidecarProxy 须要关怀的服务信息,借此屏蔽无关的服务配置下发。后果如上图右侧所示,服务配置了 SidecarScope 后,收到的配置精简了,不再蕴含无关的配置。同时,不相干服务的配置变动也不会再告诉,缩小了推送频率。

一个典型的 SidecarScope 样例如下,样例示意容许匹配的 SidecarProxy 感知 Namespace prod1 和 istio-system 中的所有服务以及 Namespace prod2 中 ratings 服务配置信息。

apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
  name: default
  namespace: prod1
spec:
  egress:
  - hosts:
    - "prod1/*"
    - "prod2/ratings.prod2.svc.cluster.local"
    - istio-system/*

Istio 提供的 SidecarScope 能够解决配置全量下发的问题,看起来问题解决了。然而在实践中,手动治理 SidecarScope 很艰难。一方面是服务依赖的信息不好整顿,另一方面一旦配置有误,会导致调用呈现问题。这十分不利于服务网格大规模落地。咱们迫切希望可能更智能地治理 SidecarScope。

2.2 价值

懒加载模块就是用于解决上述问题。懒加载可 主动对接服务网格,在转发过程中反对 Istio 所有网络治理能力,无性能问题。它能够帮忙业务人员应用了 SidecarScope,而无需间接治理它。

咱们认为,服务依赖关系能够分成运行过程中一直变动的动静服务依赖和业务人员能够提前通晓的动态服务依赖两类。对于动静依赖,咱们设计了一套机制,实时获取服务依赖并批改 SidecarScope;对于动态依赖,咱们着重简化了配置规定,使其更加人性化。

2.3 动静配置更新

懒加载蕴含 Global-sidecar 和 Lazyload Controller 两个组件。

  • Global-sidecar: 兜底组件,当源服务无奈找到指标服务时,进行兜底转发,并生成相应的服务依赖 Metric
  • Lazyload Controller: 管制组件,解决 Global-sidecar 上报的 Metric,批改源服务的 SidecarScope,为其减少相应配置

简化的动静配置更新流程如下所示

  • 服务 A 的 SidecarScope 初始是空白,没有服务 B 的配置信息
  • 服务 A 发动对服务 B 的第一次拜访,因为服务 A 的 SidecarProxy 没有服务 B 的配置信息,申请发送到兜底组件 Global-Sidecar
  • 兜底组件 Global-Sidecar 领有全量服务配置信息,天然蕴含服务 B,转发申请到服务 B,首次申请胜利,并生成 Metric(A->B)
  • Lazyload Controller 感知到 Metric(A->B),批改 SidecarScope A,为其减少服务 B 的配置
  • 服务 A 第二次拜访服务 B 时,服务 A 的 SidecarProxy 曾经有服务 B 的配置,申请中转服务 B

具体的流程图如下

其中 ServiceFence 是懒加载中引入的 CRD,作用是存储与服务相干的 Metric,实现 SidecarScope 的更新。具体的介绍可参考 懒加载教程 - 架构

2.4 动态配置加强

懒加载倒退晚期,咱们聚焦于动静服务依赖关系的获取,这看起来智能又省心。然而在实践中,咱们发现很多用户出于平安思考,往往心愿间接配置一些规定到 SidecarScope 中,即配置动态服务依赖关系。于是,咱们开始思考如何灵便配置动态依赖关系。

于是,咱们设计出一套很好用的动态规定,并将其写到 ServiceFence 中(是的,就是动静配置更新中用于存储 Metric 的 CRD,它在这里施展了新作用)。之后 Lazyload Controller 依据这些规定更新相应的 SidecarScope。

当初咱们提供的动态配置规定有三类:

  • 依赖某些 Namespace 所有服务
  • 依赖具备某些 label 的所有服务
  • 依赖某个特定服务

此处以 label 匹配举个例子,如果利用部署如下图所示

当初为服务 productpage 启用懒加载,已知 productpage 的依赖规定为

  • 具备 label app: details的所有服务
  • 具备 label app: reviews version: v2 的所有服务

那么对应的 ServiceFence 写法如下

---
apiVersion: microservice.slime.io/v1alpha1
kind: ServiceFence
metadata:
  name: productpage
  namespace: default
spec:
  enable: true
  labelSelector: # Match service label, multiple selectors are 'or' relationship
    - selector:
        app: details
    - selector: # labels in one selector are 'and' relationship
        app: reviews
        version: v2

Lazyload Controller 会依据理论匹配后果,填充 SidecarScope。理论失去的 SidecarScope 如下,上图中绿色的服务全副选中

apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
  name: productpage
  namespace: default
spec:
  egress:
  - hosts:
    - '*/details.ns1.svc.cluster.local'
    - '*/details.ns2.svc.cluster.local'
    - '*/details.ns3.svc.cluster.local'
    - '*/reviews.ns2.svc.cluster.local'
    - istio-system/* # istio 部署的 ns
    - mesh-operator/* # lazyload 部署的 ns
  workloadSelector:
    labels:
      app: productpage

终于,咱们不必在上线前重复确认,是否填齐了所有服务依赖,更不必在服务依赖关系变更时,手动批改 SidecarScope。配置两三条 ServiceFence 的规定就可搞定所有。

具体的介绍可参考 懒加载教程 – 动态服务依赖关系增加

2.5 Metric 类型

在 2.3 章节中,咱们解释了 Metric 是动静依赖关系生成的基本。目前懒加载反对的 Metric 类型有两个:Prometheus 和 AccessLog。

应用 Prometheus Mode,指标由各个业务利用的 SidecarProxy 产生。Lazyload Controller 查问 Prometheus 获取指标。此模式须要服务网格对接 Prometheus。

应用 AccessLog Mode,指标起源是 Global-sidecar 的 AccessLog。Global-sidecar 在兜底转发的同时,会生成固定格局的 AccessLog,发给 Lazyload Controller 进行解决。此模式无需内部依赖,更为轻便。

2.6 应用模式

懒加载模块有两种应用模式,Namespace 模式和 Cluster 模式。两种模式中,Lazyload Controller 都是全局惟一的,不同点在于前者的 Global-sidecar 是 Namespace 级别,后者是 Cluster 级别。如下图所示

对于 N 个 Namespace,Namespace 模式的懒加载组件数是 O(N),Cluster 模式则是 O(1)。当初咱们更举荐应用 Cluster 模式。如上图所示,每个集群只须要部署两个 Deployment,简洁明了。

具体的介绍可参考 懒加载教程 – 装置和应用

三、智能限流

3.1 背景

随着 Istio 移除 Mixer,在服务网格中实现限流变得艰难起来。

  • 场景少:Envoy 的本地限流组件性能简略,不能实现全局均分、全局共享限流等高阶用法
  • 配置简单:本地限流须要借助 Envoy 内建插件 envoy.local.ratelimit,用户不得不面对简单的 EnvoyFilter 配置
  • 条件固定:没有依据资源使用率等理论状况,主动调整限流配置的能力

3.2 价值

为了解决这个问题,咱们推出了智能限流模块。智能限流模块具备很多劣势,具体来说

  • 场景多:反对本地限流、全局均分限流、全局共享限流
  • 配置不便:配置简略,可读性好,无需配置 EnvoyFilter
  • 条件自适应:限流触发的条件可联合 Prometheus Metric,动静计算,实现自适应限流成果

3.3 实现

咱们设计了一个新的 CRD – SmartLimiter,其配置规定靠近天然语义。模块的逻辑分成两局部

  • SmartLimiter Controller 获取监控数据,更新 SmartLimiter CR
  • SmartLimiter CR 到 EnvoyFilter 的转换

限流模块架构如下

红色是本地限流,绿色是全局均分限流,而蓝色是全局共享限流。具体的介绍可参考 智能限流教程 – 架构

3.4 本地限流

本地限流是最根底的应用场景。SmartLimiter 替服务的每个 Pod 设置固定的限流数值。底层依赖 Envoy 内建插件 envoy.local.ratelimit。标识字段是action.strategy: single

一个样例如下,示意 reviews 服务每个 Pod 的 9080 端口每分钟限流 60 次。

apiVersion: microservice.slime.io/v1alpha2
kind: SmartLimiter
metadata:
  name: reviews
  namespace: default
spec:
  sets:
    _base:   # 匹配所有服务,关键词 _base,也能够是你定义的 subset,如 v1 
      descriptor:   
      - action:    # 限流规定
          fill_interval:
            seconds: 60
          quota: '100'
          strategy: 'single'  
        condition: 'true'  # 永远执行该限流
        target:
          port: 9080

3.5 全局均分限流

全局均分限性能依据用户设置的总的限流数,而后平均分配到各个 Pod。底层依赖 Envoy 内建插件 envoy.local.ratelimit。标识字段是action.strategy: average

一个样例如下,示意 reviews 服务所有 Pod 的 9080 端口每分钟一共限流 60 次,具体到每个 Pod 的限流次数由 action.quota计算得出。

apiVersion: microservice.slime.io/v1alpha2
kind: SmartLimiter
metadata:
  name: reviews
  namespace: default
spec:
  sets:
    _base:
      descriptor:
      - action:
          fill_interval:
            seconds: 60
          quota: '100/{{._base.pod}}' # 如果 reviews 实例数是 2, 则每个 Pod 限流每分钟 50 次
          strategy: 'average'  
        condition: 'true'
        target:
          port: 9080

3.6 全局共享限流

全局共享限流限度指标服务的所有 Pod 可拜访的总次数,不会像全局均分限流限度在平均值,比拟实用于拜访不均的场景。此场景会保护一个全局计数器,底层依赖 Envoy 插件 envoy.filters.http.ratelimit和 RLS 服务提供的全局计数能力。标识字段是action.strategy: global

一个样例如下,示意 reviews 服务所有 Pod 的 9080 端口每分钟一共限流 60 次,不均分到每个 Pod。

apiVersion: microservice.slime.io/v1alpha2
kind: SmartLimiter
metadata:
  name: reviews
  namespace: default
spec:
  sets:
    _base:
      #rls: 'outbound|18081||rate-limit.istio-system.svc.cluster.local' 如果不指定默认是该地址
      descriptor:
      - action:
          fill_interval:
            seconds: 60
          quota: '100'
          strategy: 'global'
        condition: 'true'
        target:
          port: 9080 

3.7 自适应限流

上述三个场景中,触发限流的条件字段 condition 除了能够是固定数值(true),还能够是 Prometheus Query 的计算结果。后者就是自适应限流。此场景和上述三个场景是穿插关系。

用户能够自定义须要获取的监控指标,比方定义一个 handler cpu.sum,其数值等于 sum(container_cpu_usage_seconds_total{namespace="$namespace",pod=~"$pod_name",image=""}),前面就能够将触发限流的 condition 设置为{{._base.cpu.sum}}>100 的模式,实现自适应限流。

一个样例如下,示意 reviews 服务每个 Pod 的 9080 端口只有当 CPU 应用值大于 100 时,每分钟限流 60 次。比照 3.4 中的例子,condition不再永远为真,是否触发限流,由 SmartLimiter Controller 依据利用理论状态判断,更加智能化。

apiVersion: microservice.slime.io/v1alpha2
kind: SmartLimiter
metadata:
  name: reviews
  namespace: default
spec:
  sets:
    _base:   # 匹配所有服务,关键词 _base,也能够是你定义的 subset,如 v1 
      descriptor:   
      - action:    # 限流规定
          fill_interval:
            seconds: 60
          quota: '100'
          strategy: 'single'  
        condition: '{{._base.cpu.sum}}>100'  如果服务的所有负载大于 100,则执行该限流
        target:
          port: 9080

四、我的项目架构

这一节简略介绍下 Slime 的我的项目架构,帮忙大家了解 Slime 多模块场景下的代码仓库和部署状态。架构如下图所示

Slime 的我的项目架构恪守“高内聚,低耦合”的设计思维,蕴含三块

  • Modules: 提供某个性能的独立模块,像懒加载、智能限流都属于 Modules
  • Framework: 模块的底座,提供 Modules 须要的根底能力,比方日志输入、监控指标获取
  • Slime-boot: 启动组件,负责拉起 Framework 和指定的 Modules

整个代码仓库分成 1+N。Slime-boot 和 Framework 位于 slime 主仓库 slime-io/slime,懒加载等模块全副位于独立仓库。

部署模式也是 1+N 的,即一个 Slime Deployment 蕴含一个专用的 Framework 和用户想要的 N 个模块。益处是,无论应用多少 Slime 模块,部署时都是一个 Deployment,很好解决了微服务组件过多的保护痛点。

五、瞻望

Slime 开源至今一年多的工夫,除了模块层面新性能的增加、已有性能的欠缺,还通过了一次架构大调整和 Metric 体系的重构,能够说,当初 Slime 的倒退曾经走上正轨,进入新的阶段。将来布局能够分为已有模块的晋升和新模块的引入,上面具体阐明。

5.1 懒加载布局

个性 个性阐明 性质 打算公布工夫
灾备兜底能力 革新 Global-Sidecar 组件,欠缺其兜底能力,使懒加载可用于一些灾备场景 确定性 2022.Q2
多服务注册核心反对 懒加载目前次要适配 Kubernetes 场景,打算通过对 ServiceEntry 的反对,适配多服务注册核心场景 确定性 2022.Q2
更灵便的动态配置 通过更高维度的形象,实现 ServiceFence 的主动配置,反对更高级的动态规定 确定性 2022.Q3
多协定懒加载 懒加载目前反对 Http 服务,打算反对其余协定服务的懒加载,比方 Dubbo 等 探索性 2022.H2
跨集群懒加载 懒加载目前反对同集群服务,打算反对多集群服务网格场景下的跨集群服务懒加载 探索性 2022.H2

5.2 智能限流布局

个性 个性阐明 性质 打算公布工夫
多服务注册核心反对 智能限流目前次要适配 Kubernetes 场景,打算通过对 ServiceEntry 的反对,适配多服务注册核心场景 确定性 2022.Q2
出流量侧限流 智能限流目前反对入流量侧限流,这能够满足大多数场景,然而从能力齐备度上,打算反对出流量侧限流 确定性 2022.Q3
多协定智能限流 智能限流目前反对 Http 服务,打算反对其余协定服务的智能限流,比方 Dubbo 等 探索性 2022.H2
跨集群智能限流 智能限流目前反对同集群服务,打算反对多集群服务网格场景下的跨集群智能限流 探索性 2022.H2

5.3 新模块布局

模块名(布局) 模块阐明 性质 打算公布工夫
IPerf 专为 Istio 打造的性能测试工具集,集成 Istio 测试框架,增加自定义测试用例,可直观比照不同版本的性能变动 确定性 2022.H2
Tracetio 服务网格的全链路自动化运维,进步排障效率,给出智能化判断 确定性 2022.H2
I9s 相似 K9s,实用于服务网格场景的黑屏半命令行半图形化运维工具 确定性 2022.H2

心愿下面的这些布局能尽快与大家见面。Slime 相干信息能够查阅 Slime – Home,欢送大家多多与咱们交换。

相干浏览

  • Slime:让 Istio 服务网格变得更加高效与智能
  • Slime 我的项目地址:https://github.com/slime-io/s…
  • 网易数帆开源我的项目概览:https://sf.163.com/opensource…

作者简介: 王晨宇,网易数帆资深服务端开发工程师,Istio 社区成员,Slime Maintainer,相熟 Istio 与 Kubernetes,次要负责 Slime 及网易数帆轻舟服务网格的设计与研发,具备多年云原生相干畛域的实践经验。


Istio 社区第二届寰球峰会 IstioCon 2022 将于线上举办,来自 Google、网易、IBM、腾讯等公司的 80+ 服务网格技术专家将带来 60+ 场技术分享。 4 月 28 日 10:40网易数帆资深架构师 Yonka Fang 将为寰球开发者和用户分享《Istio 推送的性能优化教训》,精彩不容错过,欢送扫码预约直播!链接:https://www.crowdcast.io/e/is…

退出移动版