【Knative系列】理解 Knative Serving扩缩容系统的设计

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【Knative系列】理解 Knative Serving扩缩容系统的设计相关的知识,希望对你有一定的参考价值。

参考技术A

Knative Serving 是 Knative 系统的核心,而理解 Knative Serving 系统内的组件能更容易了理解 Knative Serving 系统的实现:
了解其中的控制流和数据流的走向,了解其在扩缩容过程中的作用。因篇幅有限,这里只对组件进行简要描述,后续会针对每个组件进行详细的单独讲解。

queue-proxy 是 一个伴随着用户容器运行的 Sidecar 容器,跟用户容器运行在同一个 Pod 中。每个请求到达业务容器之前都会经过 queue-proxy 容器,
这也是它问什么叫 proxy 的原因。

queue-proxy 的主要作用是统计和限制到达业务容器的请求并发量,当对一个 Revision 设置了并发量之后(比如设置了5), queue-proxy 会确保不会同时有超过5个请求打到业务容器。当有超过5个请求到来时, queue-proxy 会先把请求暂存在自己的队列 queue 里,(这也是为什么名字里有个 queue的缘故)。 queue-proxy 同时会统计进来的请求量,同时会通过指定端口提供平均并发量和 rps(每秒请求量)的查询。

Autoscaler 是 Knative Serving 系统中一个重要的 pod,它由三部分组成:

PodAutoscaler reconciler 会监测 PodAutoscaler (KPA)的变更,然后交由 Collector 和 Decider 处理

Collector 主要负责从应用的 queue-proxy 那里收集指标, Collector 会收集每个实例的指标,然后汇总得到整个系统的指标。为了实现扩缩容,会搜集所有应用实例的样本,并将收集到的样本反映到整个集群。

Decider 得到指标之后,来决定多少个Pod 被扩容出来。简单的计算公式如下:

另外,扩缩容的量也会受到 Revision 中最大最小实例数的限制。同时 Autoscaler 还会计算当前系统中剩余多少突发请求容量(可扩缩容多少实例)进来决定 请求是否走 Activator 转发。

Activator 是整个系统中所用应用共享的一个组件,是可以扩缩容的,主要目的是缓存请求并给 Autoscaler 主动上报请求指标

Activator 主要作用在从零启动和缩容到零的过程,能根据请求量来对请求进行负载均衡。当 revision 缩容到零之后,请求先经过 Activator 而不是直接到 revision 。 当请求到达时, Activator 会缓存这这些请求,同时携带请求指标(请求并发数)去触发 Autoscaler 扩容实例,当实例 ready后, Activator 才会将请求从缓存中取出来转发出去。同时为了避免后端的实例过载, Activator 还会充当一个负载均衡器的作用,根据请求量决定转发到哪个实例(通过将请求分发到后端所有的Pod上,而不是他们超过设置的负载并发量)。 Knative Serving 会根据不同的情况来决定是否让请求经过 Activator ,当一个应用系统中有足够多的pod实例时, Activator 将不再担任代理转发角色,请求会直接打到 revision 来降低网络性能开销。

跟 queue-proxy 不同, Activator 是通过 websocket 主动上报指标给 Autoscaler ,这种设计当然是为了应用实例尽可能快的冷启动。 queue-proxy 是被动的拉取: Autoscaler 去 queue-proxy 指定端口拉取指标。

API: podautoscalers.autoscaling.internal.knative.dev

PodAutoscaler 是对扩缩容的一个抽象,简写是 KPA 或 PA ,每个 revision
会对应生成一个 PodAutoscaler 。
可通过下面的指令查看

API: serverlessservices.networking.internal.knative.dev

ServerlessServices 是 KPA 产生的,一个 KPA 生成一个 SKS , SKS 是对 k8s service 之上的一个抽象,
主要是用来控制数据流是直接流向服务 revision (实例数不为零) 还是经过 Activator (实例数为0)。

对于每个 revision ,会对应生成两个k8s service ,一个 public service ,一个 private service .

private service 是标准的 k8s service,通过label selector 来筛选对应的deploy 产生的pod,即 svc 对应的 endpoints 由 k8s 自动管控。

public service 是不受 k8s 管控的,它没有 label selector,不会像 private service 一样 自动生成 endpoints。 public service 对应的 endpoints
由 Knative SKS reconciler 来控制。

SKS 有两种模式: proxy 和 serve

下面看几种情况下的数据流向,加深对Knative 扩缩容系统机制的理解。

稳定状态下的工作流程如下:

缩容到零过程的工作流程如下:

冷启动过程的工作流程如下:

当 revision 缩容到零之后,此时如果有请求进来,则系统需要扩容。因为 SKS 在 proxy 模式,流量会直接请求到 Activator 。 Activator 会统计请求量并将 指标主动上报到 Autoscaler , 同时 Activator 会缓存请求,并 watch SKS 的 private service , 直到 private service 对应的endpoints产生。

Autoscaler 收到 Activator 发送的指标后,会立即启动扩容的逻辑。这个过程的得出的结论是至少一个Pod要被创造出来, AutoScaler 会修改 revision 对应 Deployment 的副本数为为N(N>0), AutoScaler 同时会将 SKS 的状态置为 serve 模式,流量会直接到导到 revision 对应的 pod上。

Activator 最终会监测到 private service 对应的endpoints的产生,并对 endpoints 进行健康检查。健康检查通过后, Activator 会将之前缓存的请求转发到
健康的实例上。

最终 revison 完成了冷启动(从零扩容)。

Knative 是 Serverless 平台,还是换个方式写 YAML?

又来吐槽谷歌和 K8s 了,个人胡言乱语,如有理解错误还请留言指出。


在今天召开的 Google Cloud Next ’18 中,Google 发布了很多新的有意思的服务或产品,比如 K8s on-prem , serverless container 等,和 Serverless 相关的产品就有这些:



其中这个 Knative 是一个在 k8s 上实现 Serverless 的产品,本文也将重点介绍下这个产品。


Knative 不是 GCP 上的一个服务,而是一套开源平台,可以在 GitHub 上看到该项目。而且作者也不只有 Google 一家, 基本大厂都到齐了:


  • Google LLC

  • Pivotal Software, Inc.

  • IBM Corp

  • Red Hat, Inc.

  • Cisco Systems, Inc.


( Pivotal 和 Red Hat 有成为 Google 小弟的倾向,大厂也都在忙着结盟)


What's Serverless ?


首先来看一下现在的 Serverless 有多乱。有两种 Serverless ,一种是 类似 Lambda 的 FaaS(Function as a Service),另一种是 Serverless infrastructure (类似 AWS 的 fargate 和 hyper.sh/pi )。若问什么是 Serverless,一般都会以 Lambda 为例来进行说明,大家的认识中,也基本认为 Serverless(FaaS)≒Lambda 。


关于 Serverless infrastructure ,可以参考旧闻: 


但我不使用 AWS 啊,怎么办?放心,几乎哪个商业产品都会有人“山寨”出开源版本。


关于 FaaS,在 CNCF landscape 上至少就有这么多产品:


  • Fission

  • Kubeless

  • OpenFaaS


产品虽然不少,但是大家都是各搞各的,不通用也不兼容,并没有统一标准,很容易被绑定到某一产品,万一有坑,沉没成本还是非常巨大的。


理想和现实之间的鸿沟


不管喜不喜欢,K8s 都在变成事实上的标准。


K8s 太复杂,太麻烦,不管是应用程序的打包和部署,还是基础设施的部署和实施,和传统方式都有很大的不同。学习成本高,维护成本高,要想帮助用户从传统到 K8s ,最简单快速的方式就是有一个强大的工具(最好连 YAML 都不要我们自己写)帮我们填补技能之间的“鸿沟”。


软件设计讲究抽象,不关心没必要关心的问题。只要程序能运行,没必要关心它是怎么运行的(这不是一句无责任的话,比如是否 OOM 还是要开发人员自己负责的)。


Knative 就是在 K8s 之上的又一个抽象平台。这个 K ,应该就是 K8s 的 K 。


Knative 是 Serverless 平台,还是换个方式写 YAML?


Knative 架构


Knative 由 3 个松耦合的组件组成,每个组件都通过 K8s 的 CRD 的方式实现。

  • Build

  • Event

  • Serving


Build


K8s 的大前提,就是基于容器的,而现在容器的镜像也是基本以 Docker 为主,因此要想上 K8s ,首先需要将应用程序打包成容器镜像,即 Build ,但并不一定直接是 docker build 命令。


构建容器镜像可以使用下面这些技术,


  • Buildpack (Cloud Foundry)

  • Google Container Builder

  • Bazel

  • Kaniko

  • Jib


Buildpack 是 CF 和 Heroku 等 PaaS 平台使用很久的构建技术了。


基本 build 也就分这几步,和 Docker build 类似:

  • 获取源代码

  • 顺序执行构建任务

    • 安装依赖

    • 运行单元测试或集成测试

  • 构建容器镜像

  • 推送镜像或者部署镜像


Event


Serverless 基本都采用 Event Driven 架构实现,通过 Event 实现 Pub/Sub ,再通过消息来触发 Function 或应用。



Knative 是 Serverless 平台,还是换个方式写 YAML?



Buses


Buses 提供了一个 K8s 原生的消息总线,类似 NATS 或 Kafka 。这个抽象层基于 Pub-Sub 模式,消息被发送到 Channel,Bus将消息路由给订阅者。


现在支持的 Bus 实现有 Stub (基于内存,无第三方依赖)、Kafka 和 GCP 的 PubSub 。


Sources


Source 用于对来源于 k8s 之外的消息进行抽象,并将这些消息通过 Feed 的形式路由到 k8s 集群。现在支持的 source 类型包括 Feed、EventType/ClusterEventType 和 EventSource/ClusterEventSource 。Source 的实现也有3种,包括 K8s event , GitHub 和 GCP PubSub。K8s event 收集 K8s 的事件,GitHub 收集 PR 通知。


Flows


Flow 是一个高层次的抽象,这也是用户面对的最顶层的概念,用于规范从 Source 到 endpoint 的绑定,描述了外部事件到达目的地的路径和处理。用户可以选择 Bus 或 Channel用于进行路由。


Knative 只有一种 Flow 实现,是随 Knative event 安装的。


Serving


Serving 实现计算资源的调度和生命周期管理,网络端口映射等功能。


Knative 是 Serverless 平台,还是换个方式写 YAML?


这些组件都通过 CRD 的方式实现。


  • Service: 管理应用及其相关资源的生命周期。包括应用、路由、配置和版本管理。

  • Route: 将网络 endpoint 映射到某一应用版本。

  • Configuration: 管理应用的状态,这也是遵循 12 要素应用的原则,将代码和配置分离。修改配置也会创建一个新的版本。

  • Revision: 为每次应用或配置的变更生成版本记录。


集成 Istio


Istio 1.0 即将发布,Knative 也深度集成了 Istio 。knative-ingressgateway 根据 host header 来对请求进行路由。


使用示例


官方有很多入门指南,帮助用户在各种环境下安装 Knative,不管是 Cloud,还是 minikube 等。一切皆在 https://github.com/knative/docs 。


如果你懒(估计大部分人都不一定去看 GitHub 的文档),这里简单介绍一下其中的一个例子。


这个示例很简单,只是输出运行时传递的环境变量 TARGET。下面是这个服务的定义:


Knative 是 Serverless 平台,还是换个方式写 YAML?


然后通过 kubectl 命令即可创建该服务:


kubectl apply -f service.yaml



虽然不用写 K8s 的 deploy 和 service 了,可我还是得写一大坨不同语法的 YAML 文件。


因此付此图在文末。

 


“计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决,...”,我想你是知道后半句的。







以上是关于【Knative系列】理解 Knative Serving扩缩容系统的设计的主要内容,如果未能解决你的问题,请参考以下文章

Knative Serving 健康检查机制分析

Knative 是 Serverless 平台,还是换个方式写 YAML?

serverless-knative serving安装实战

serverless-knative serving安装实战

serverless-knative serving安装实战

Knative路由管理