Knative流量的秘密

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

内容简介: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
                }
            },
            ...
        }
    ]
}

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

查看所有标签

猜你喜欢:

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

零基础学算法

零基础学算法

戴艳 / 机械工业出版社 / 2009-1 / 59.80元

零基础学算法,ISBN:9787111284048,作者:戴艳 等编著一起来看看 《零基础学算法》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具