HTTP 请求流程¶
虽然 概述 描述了逻辑组件,而 架构 描述了 Knative Serving 的整体架构,但本页介绍了在 Knative Serving 上运行的应用程序的 HTTP 请求的行为和流程。
下图显示了 Knative Serving 的不同请求流和控制平面循环。请注意,某些组件(例如自动缩放器和 apiserver)不会在每个请求上更新,而是定期测量系统(这称为控制平面)。
HTTP 路由器、激活器和自动缩放器都是共享的集群级资源;这减少了新 Knative 服务在服务未被使用时仅需要元数据的开销,并允许更有效地管理和升级这些共享组件。
路由决策在 HTTP 路由器(可插拔的入口层)的每个请求级别上完成一次,并在请求中的内部标头中记录。一旦请求被分配到修订版,后续路由取决于测量的流量流;在低流量或无流量的情况下,传入请求将被路由到激活器,而在高流量级别(备用容量大于 target-burst-capacity
)流量将直接路由到应用程序 Pod。
从零开始扩展¶
当某个特定修订版的流量很低或为零时,HTTP 路由器将流量发送到激活器,包括一个指示所选修订版的标头。激活器充当传入请求的缓冲区或队列——如果请求被路由到当前没有可用容量的修订版,激活器将延迟请求并向自动缩放器发出信号,表示需要额外的容量。
当自动缩放器检测到修订版的可用容量低于请求的容量时,它会 增加 Kubernetes 请求的 Pod 数量.
当这些新的 Pod 变得就绪或现有 Pod 有容量时,激活器将把延迟的请求转发到就绪的 Pod。如果需要启动一个新的 Pod 来处理请求,则称为冷启动。
高规模¶
当修订版有大量流量(备用容量大于 target-burst-capacity
)时,入口路由器将直接使用修订版 Pod 的地址进行编程,并且激活器将从流量流中删除。这减少了延迟并提高了效率,因为在不需要激活器的额外缓冲时,效率会更高。在所有情况下,队列代理都保留在请求路径中。
如果流量降至爆发容量阈值以下(计算方式为:current_demand + target-burst-capacity > (pods * concurrency-target)
),则入口路由器将被重新编程以将流量发送到激活器 Pod。
入口和激活器之间的流量路由是通过将激活器端点的一个子集写入修订版服务的端点来完成的。与修订版对应的 Kubernetes 服务是 无选择器,并且可以包含修订版的 Pod 端点或激活器端点。使用无选择器服务的原因如下
-
一些入口实现不允许跨命名空间的服务引用。激活器在
knative-serving
命名空间中运行。 -
一些入口实现无法无缝地处理更改路由端点的后备 Kubernetes 服务。
-
通过在每个修订版基础上使用子集,传入请求被引导到少数激活器,这些激活器可以更有效地做出就绪/未就绪容量决策。每个修订版的有效激活器数量不多不是缩放问题,因为当修订版按比例扩展以接收更多流量时,激活器将从请求路径中删除。
队列代理¶
队列代理组件实现了许多功能来提高 Knative 的可靠性和可伸缩性
-
衡量自动缩放器的并发请求,尤其是在激活器从请求路径中删除时。
-
实现
containerConcurrency
对请求并发的硬限制(如果请求)。 -
处理 Pod 终止时的优雅关闭(拒绝新请求,失败就绪检查,继续服务现有请求)。
-
报告来自用户容器外部的 HTTP 指标和跟踪,以便可以测量基础设施延迟贡献。
-
在启动期间(在就绪之前),更积极地探测用户容器,以实现比 Kubelet 探测更早的服务(Kubelet 探测最多每秒探测一次)。
-
为了支持此功能,Knative Serving 将用户容器的
readinessProbe
重写为队列代理的参数;队列代理的就绪检查同时包含队列代理自身的就绪和用户容器的就绪。