Knative流量的秘密

栏目: 后端 · 发布时间: 7年前

内容简介:knative在service里面实现了serverless的功能,其中最重要的莫过于按需来启动服务,并基于流量来弹性伸缩。在社区的文档里面找到这样一张架构设计图,先初略理解一下,详细介绍一下其流量转发流程。这里说的模型,其实就是knative的service里面关于CRD的定义。其中声明在外的莫属

knative在service里面实现了serverless的功能,其中最重要的莫过于按需来启动服务,并基于流量来弹性伸缩。在社区的文档里面找到这样一张架构设计图,先初略理解一下,详细介绍一下其流量转发流程。

Knative流量的秘密

模型抽象

这里说的模型,其实就是knative的service里面关于CRD的定义。其中声明在外的莫属 serviceconfigurationrevision 以及 route 。但是要真正搞明白整个模型的原作原理,理解清楚所有CRD的关联关系是非常有必要的。

Knative流量的秘密

上图展示了从 service 衍生出来的所有CRD的血缘关系,下面简述其流程和个CRD的作用。

  1. 当用户创建一个knative的service的时候,其controller会对应创建出 configurationroute ;这一块较简单,因为service的spec里面其实是包含了对configuration和traffic的定义的。
  2. 花开两支, configuration 一方面基于配置创建对应的 revision ;另一方面, route 除了创建externalService类型的 service 用于将流量指向istio网关外,同时还创建了 clusterIngress (作用很重要)。
  3. clusterIngress 是对各种可用于knative流量入口组件的抽象。对于底层是istio的环境,networkController会将clusterIngress资源转化为istio的 virtualService 配置,从而提供将外部流量转发到集群内部的功能。
  4. 对于 revision 来讲,其controller一方面基于资源描述创建出 deploymentimageCache 等资源;另一方面,为了提供serverless功能,controller还对应创建了 podAutoScaler 。需要知道的是 podAutoScaler 有两种实现,分别对应kpa和hpa。
  5. autoscaler controller又实现了基于 podAutoScaler 创建对应的 sks (serverlessService)。如果策略是基于kpa的,就需要一套监控流量和并发请求量的机制,于是又创建了private和public的 service 专用于访问实例上监控组件sidecar的端口。

代码实现

上面的分析,具体的代码实现流程见下图。

Knative流量的秘密

流量转发

当外部流量需要访问内部服务时,其流量的转发流程如何?接下来分小节介绍主要的流量转发逻辑。

流量入口

服务映射

之前在将CRD资源的时候有提到 clusterIngress 资源,以及对应的的ExternalService类型的 service ,这里是一个简单的实例。

[root@k8s-master knative]# kc describe svc autoscale-go
Name:              autoscale-go
Namespace:         default
Labels:            serving.knative.dev/route=autoscale-go
Annotations:       <none>
Selector:          <none>
Type:              ExternalName
IP:
External Name:     istio-ingressgateway.istio-system.svc.cluster.local
Session Affinity:  None
Events:            <none>

该service的作用是,当请求 autoscale-go.default.example.com 时(cluster名字换成环境的cluster name),DNS会直接返回external name istio-ingressgateway.istio-system.svc.cluster.local 作为响应。相当于就将对autoscale-go服务的访问,重定向到了istio的ingressgateway上。而Istio上早已按照 clusterIngress 的要求,配置好了流量转发规则。

转发规则

serverlessservice有两种模式, proxyservice 。其中 proxy 会将流量转发到activator上,而 service 则会将流量转发到对应的后端实例上真正处理业务。

我们先假设此时后端的deployment并没有启动起来,或者是很久没有请求流量,pod已经被autoscaler出于节约资源消耗的目的干掉了,即serverlessservice处于 proxy 模式。此时istio的配置如下。

[root@k8s-master ~]# istioctl pc listener istio-ingressgateway-67cbb7f6c6-bqv2h.istio-system
ADDRESS     PORT      TYPE
0.0.0.0     80        HTTP
0.0.0.0     15090     HTTP

[root@k8s-master ~]# istioctl pc route istio-ingressgateway-67cbb7f6c6-bqv2h.istio-system -o json
[
    {
        "name": "http.80",
        "virtualHosts": [
            {
                "name": "autoscale-go.default.example.com:80",
                "domains": [
                    "autoscale-go.default.example.com",
                    "autoscale-go.default.example.com:80"
                ],
                "routes": [
                    {
                        "match": {
                            "prefix": "/",
                            "headers": [
                                {
                                    "name": ":authority",
                                    "regexMatch": "^autoscale-go\\.default(?::\\d{1,5})?$"
                                }
                            ]
                        },
                        "route": {
                            "cluster": "outbound|80||autoscale-go-52f52.default.svc.cluster.local",
                            "timeout": "600s",
                            "retryPolicy": {
                                "retryOn": "connect-failure,refused-stream,unavailable,cancelled,resource-exhausted,retriable-status-codes",
                                "numRetries": 3,
                                "perTryTimeout": "600s",
                                "retryHostPredicate": [
                                    {
                                        "name": "envoy.retry_host_predicates.previous_hosts"
                                    }
                                ],
                                "hostSelectionRetryMaxAttempts": "3",
                                "retriableStatusCodes": [
                                    503
                                ]
                            },
                            "maxGrpcTimeout": "600s"
                        },
                        ...
                    }
                ]
            }
        ]
    }
]

查看EDS的配置信息,发现其对应的路由为IP 10.244.0.234 的8012端口。

[root@k8s-master ~]# istioctl pc endpoint istio-ingressgateway-67cbb7f6c6-bqv2h.istio-system -o json

{
        ...
        "name": "outbound|80||autoscale-go-52f52.default.svc.cluster.local",
        "addedViaApi": true,
        "hostStatuses": [
            {
                "address": {
                    "socketAddress": {
                        "address": "10.244.0.234",
                        "portValue": 8012
                    }
                },
                ...
            }
        ]
}

在来看此时该IP是activator对应的pod IP地址。

[root@k8s-master ~]# kc get pod -o wide --all-namespaces | grep 10.244.0.234
knative-serving      activator-5b7d897458-xv4tp                      1/1     Running   0          132m   10.244.0.234    k8s-master   <none>           <none>

查看service上面的流量以及对应的转发目标变为activator。

[root@k8s-master knative]# kc get svc
NAME                         TYPE           CLUSTER-IP       EXTERNAL-IP                                           PORT(S)             AGE
alertmanager-operated        ClusterIP      None             <none>                                                9093/TCP,6783/TCP   7d2h
autoscale-go                 ExternalName   <none>           istio-ingressgateway.istio-system.svc.cluster.local   <none>              148m
autoscale-go-52f52           ClusterIP      10.108.134.58    <none>                                                80/TCP              148m
autoscale-go-52f52-metrics   ClusterIP      10.109.214.47    <none>                                                9090/TCP            148m
autoscale-go-52f52-priv      ClusterIP      10.106.251.157   <none>                                                80/TCP              148m
kubernetes                   ClusterIP      10.96.0.1        <none>                                                443/TCP             66d
prometheus-operated          ClusterIP      None             <none>                                                9090/TCP            7d2h


[root@k8s-master knative]# kc get ep
NAME                         ENDPOINTS                                               AGE
autoscale-go-52f52           10.244.0.234:9090,10.244.0.234:8012,10.244.0.234:8013   148m
autoscale-go-52f52-metrics   <none>                                                  148m
autoscale-go-52f52-priv      <none>                                                  148m

所以,我们可以判断:当很久没有流量请求的时候,serverlessservice会切换到 proxy 模式,其autoscaler逻辑会将pod全干掉;而此时,为了检测到外部的流量请求,Istio将流量转发到activator上面。

弹性伸缩

通过上面的分析,相信大家对serverlessservice的弹性伸缩都有了一个直观的了解。接下来该部分通过两个小节介绍弹性伸缩的工作原理。

弹性伸缩分为 hpakpa :

hpa
kpa

触发器

前面提到的activator就是触发器,它的作用就是为那些几乎没有流量访问的服务充当看门人。显然这个看门人并不是只为某个VIP客户服务,而是为大家一起服务的。那activator都做了些什么?当流量到了的时候,它又是如何通知正处于放空状态的服务实例的呢?

作用

  1. 当service的实例数为0的时候,activator代替service接收流量,统计流量和并发数量,并通过websocket上报到autoscaler服务。
  2. 当service的实例启动起来后,activator通过获取revision和serverlessservice来找到对应的service,并探测该service的服务是否已经可以访问,一旦准备好,就发送流量。
  3. 通过一系列的handler链来打印日志,记录trace信息,限速,零时存储请求内容,响应probe和healthcheck等。

核心工作流程

  1. 作为代理看门人,activator收到外部访问service的请求后,第一件事请就是去除报文中的header信息,按照revision name作为key产生一条event。
  2. 如果从来没有改key的event,就可以判断这是到某一个客户的第一条请求,此时看门人需要立刻通过websocket上报到autoscaler(autoscaler的逻辑会创建service的实例)。
  3. 当然,activator并非只做这些,它还记录日志,trace信息等,最重要的一点,activator会基于报文header中的信息来知道其所请求的revision以及sks。
  4. 通过查询sks的privateService来找到该service的healthCheck probe地址,探测其服务是否ready。一旦probe成功就会将缓存的报文发送到目标服务。

代码实现

Knative流量的秘密

其代码住逻辑分为三块,也对应三个goroutine,分别是:

  1. 监控上报
  2. 监控数据统计
  3. 报文处理(包含多个处理链)

弹性伸缩逻辑

在触发器的流程中,我们提到当触发器发现某个报文是对某个revision的第一个请求时,会通过websocket上报到autoscaler controller。接下来,我们看看autoscaler的处理流程。

功能

  1. autoscalr的核心作用就是做弹性伸缩的决策,为了做决策,它需要实现对上报监控指标的采集,这又分为两种形式。
    • 通过websocket上报来收集activator的报文请求指标;
    • 通过定时pull的形势来从metrics service获取queue中统计的指标;
  2. 基于metric指标来做弹性伸缩决策并下发。

代码实现

Knative流量的秘密

由于这里重点讲流量,该代码基本是按照功能来实现,这里就不再做讲解。

这里重点讲一下autoscaler将service的pod拉起来了之后的动作,通过代码里面可以看到, ks.applyScale 最后会走到 c.reconcileSKS 。这里其实是更改serverlessservice的模式,从 proxy 切换到 service ,而接下来的又做了什么?请参考service controller的逻辑。

当pod启动起来之后,对应的private Service会基于selector而选中新起来的pod,从而监控流量将从pod的8012端口采集。

流量监控

上面提到,当pod启动之后,autoscaler会从pod的8012端口采集监控指标。这里的监控指标是如何产生的?应用需要关注吗?这些问题在这一节来解答。

作用

首先,knative中的revision在创建deploy的时候,会为其自动加入一个sidecar,这个container就是queue-proxy;在整个平台中,queue-proxy的作用非常重要。

  1. 基于一层反向代理,收集访问业务container的流量情况,对外暴露9090(即:metrics的访问端口)
  2. 在反向代理上,基于配置的并发数来限制外部访问的请求速率;
  3. 对外提供对主容器进行healthcheck以及drain的接口(admin的端口:8022),(业务代理端口: http1:8012,http2:8013);

代码实现

Knative流量的秘密

实验

autoscaler通过周期性的抓取每一个业务容器对应queue-proxy的metrics来感知实时流量情况的。当外部往service发包的时候,在pod的queue container网卡上抓包可以发现有很多的prometheus metrics的报文,collector拉取指标的频率为每秒4次,具体指标见下图的抓包细节:

Knative流量的秘密

在报文里面发现来收集metrics的IP地址为 10.244.0.235 , 通过在k8s里面查询,发现该IP为autoscaler的地址。

[root@k8s-master ~]# kc get pod -o wide --all-namespaces | grep 10.244.0.235
knative-serving      autoscaler-74f47bfff8-7znzv                     1/1     Running   0          15d   10.244.0.235    k8s-master   <none>           <none>

当服务启动后,各服务的具体内容如下:

[root@k8s-master ~]# kc get serverlessservice
NAME                 SERVICENAME          PRIVATESERVICENAME        READY   REASON
autoscale-go-52f52   autoscale-go-52f52   autoscale-go-52f52-priv   True

[root@k8s-master ~]# kc get revisions
NAME                 SERVICE NAME         GENERATION   READY   REASON
autoscale-go-52f52   autoscale-go-52f52   1            True


[root@k8s-master ~]# kc get deploy
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
autoscale-go-52f52-deployment   1/1     1            1           141m


[root@k8s-master ~]# kc get svc
NAME                         TYPE           CLUSTER-IP       EXTERNAL-IP                                           PORT(S)             AGE
autoscale-go                 ExternalName   <none>           istio-ingressgateway.istio-system.svc.cluster.local   <none>              142m
autoscale-go-52f52           ClusterIP      10.108.134.58    <none>                                                80/TCP              142m
autoscale-go-52f52-metrics   ClusterIP      10.109.214.47    <none>                                                9090/TCP            142m
autoscale-go-52f52-priv      ClusterIP      10.106.251.157   <none>                                                80/TCP              142m


[root@k8s-master ~]# kc get ep
NAME                         ENDPOINTS            AGE
alertmanager-operated        <none>               7d2h
autoscale-go-52f52           10.244.0.18:8012     142m
autoscale-go-52f52-metrics   10.244.0.18:9090     142m
autoscale-go-52f52-priv      10.244.0.18:8012     142m
kubernetes                   10.200.204.76:6443   66d
prometheus-operated          <none>               7d2h


[root@k8s-master ~]# istioctl  ps
NAME                                                   CDS        LDS        EDS               RDS        PILOT                            VERSION
istio-ingressgateway-67cbb7f6c6-bqv2h.istio-system     SYNCED     SYNCED     SYNCED (100%)     SYNCED     istio-pilot-75984f55cc-5brpc     1.1.3


[root@k8s-master ~]# istioctl pc endpoint istio-ingressgateway-67cbb7f6c6-bqv2h.istio-system -o json
{
    "name": "outbound|80||autoscale-go-52f52.default.svc.cluster.local",
    "addedViaApi": true,
    "hostStatuses": [
        {
            "address": {
                "socketAddress": {
                    "address": "10.244.0.18",
                    "portValue": 8012
                }
            },
            ...
        }
    ]
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro JavaScript Techniques

Pro JavaScript Techniques

John Resig / Apress / 2006-12-13 / USD 44.99

Pro JavaScript Techniques is the ultimate JavaScript book for the modern web developer. It provides everything you need to know about modern JavaScript, and shows what JavaScript can do for your web s......一起来看看 《Pro JavaScript Techniques》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具