FaaS流量转发
冷启动的流量转发
Public Service 和 Private Service,它们是决定流量走向 Pod IP 还是 Activator 的关键。
Public Service:由 Knative 管控,其 EndPoints 是可变的。如果当前的 Revision 存在 User Pod,那么 Public Service 的 EndPoints 会与 Private Service 的保持一致,指向这些实例;
而如果不存在 User Pod,那么冷启动流程时,其 EndPoints 将指向 Activator 的 IP 地址。
Private Service:通过 Label Selector 来筛选图中对应的 Deployment 产生的 User Pod,其他组件可以通过监听 Private Service 的 EndPoints 情况,来了解当前的 Revision 是否有 User Pod 存在。因为其本身不做流量的转发,在图中用灰色体现。
冷启动的实际请求流向
步骤 0:这里要完成的是准备工作。当你打包好函数镜像,创建好 Knative Service 之后,Knative 会根据定义来创建 Route、Configuration(cfg)资源,然后 cfg 会创建对应的 Revision 版本。Revision 又会创建 Deployment 提供服务。
步骤 1:当请求到达 Istio Ingress Gateway 后,Istio Ingress Gateway 会根据 Gateway 和 virtualService 配置信息,将请求转发给 Public Service。
步骤 2:由于此时集群中还没有 User Pod(图中的 User Pod 需要等到 AutoScaler 扩容后才有),而 Public Service 的 EndPoints 配置的是 Activator,所以请求接下来会交给 Activator 处理。
步骤 3:Activator 会将收到的请求暂存,同时统计请求对应 Revision 的实际流量并上报给 AutoScaler。另外,Activator 还会不断监听 Private Service,检查是否已经存在 User Pod 了。
步骤 4:AutoScaler 根据流量情况控制对应 Revision 的 Deployment 来实现 User Pod 的扩容。在冷启动过程中,会至少保证创建一个 Pod 出来。
步骤 5:Deployment 创建新的 User Pod,同时会更新 Private Service 的 EndPoints,将 Private Service 的 EndPoints 指向新生成的 User Pod。
步骤 6:Activator 检测到 Private Service 关联的 EndPoints 后,会将请求直接转发到新的 User Pod。User Pod 收到请求后,就会执行业务逻辑。
在从 0 到 1 的过程中,还有一点需要说明的,那就是在 User Pod 创建成功后,AutoScaler 会触发 SKS 的模式为 server,同时将 Public Service 的 EndPoints 同步为 Private Service 的 Endpoints,也就是切换回了常规流量的处理模式。而新的流量到来后,就会通过 Public Service 直接到达 User Pod,不再走 Activator 代理。但 Knative 本身引入了一个 TBC(Target Burst Capacity)来控制什么情况下 Activator 会从流量路径中摘除,这样做的好处是为了防止流量突然的增大,导致单个 Pod 失衡,进而影响到请求的丢失。这就是 Knative 在冷启动下的流程机制,可以看出,Knative 针对流量从 0 到 1 的启动过程,考虑到了流量的突增的因素,在流量入口,考虑到了便捷的扩展能力,能够更好地复用网络组件。
流量分流机制
Service 负责创建 Route、Configuration 以及 Revision 资源,通过 Service 可以将流量路由到指定的 Revision 中。而在指定的过程中,分流的核心是 Route,它负责把网络端点映射到一个或多个 Revision,可以通过多种方式管理流量,包括灰度流量和重命名路由。
在 Knative Service 部署到 default namespace 后,Knative 就会创建 Route 对象,因为Knative 用了 Istio 作为网络组件,所以还会继续创建 Istio VirtualService(traffic-demo-ingress)。
可以看到第一个 VirtualService 关联了 Knative 创建的两个 Gateway,第二个关联的 Gateway 是 “mesh”,这是 Istio 保留的一个关键字,意思是将 VirtualService 的规则应用到集群里所有的 sidecar。
在 Knative 中,通常可以通过修改 config-domain 的配置来自定义一个域名后缀,使得外部请求的时候可以访问。再由 istio ingress gateway 根据 virtualService 中配置的这些策略实现分流。
异步下的流量调度
异步下的流量调度过程。请求首先会到达异步处理模块,并按照顺序排队,这也是异步处理模块通常会结合消息队列实现的原因。当轮到你的请求被处理时,异步处理服务会再将请求发到对应的函数实例进行执行,并将执行结果反馈到监控日志上。
除此之外,像 AWS、阿里等主流的函数计算平台还会支持异步的执行策略,可以根据每次异步执行的最终结果来配置“执行成功”和“执行失败”的下游服务。
总的来说,异步调用主要通过事件 / 消息队列的方式来缓冲一步,然后通过异步处理模块,按照同步请求的请求机制来处理。流量的转发除了在入口处不一样之外,后续的同步请求依然跟上面类似。
多并发下的流量转发
首先,需要是 HttpServer 的服务类型。
如果是基于云厂商的标准运行时,就需要看一下他是否支持。\当请求到来时,除了以 HttpServer 的形式运行之外,还会通过 go func 的形式进行处理,这种方式可以从一定程度上进一步提升函数的并发处理能力。
其次,你的服务需要能在框架中暴露端口,供流量转发进来。
第三,需要有一个组件来控制并发。由于云厂商没有公布实现,回到 Knative 中来看,提供了 queue-proxy 和 AutoScaler 的搭配能力,完美解决了流量的并发问题。
queue-proxy 是 一个伴随着用户容器运行的 Sidecar 容器,跟用户容器运行在同一个 Pod 中。每个请求到达业务容器 User Container 之前,都会经过 queue-proxy 容器。它的主要作用是统计和限制到达 User Container 的请求并发量。当你对一个 Revision 设置了并发之后,比如设置了 10,那么 queue-proxy 就会确保不会有超过 10 个的请求达到 User Container。那么,如果有超过 10 个请求到来,又该怎么办呢?它会先暂存在自己的队列 queue 里面,同时通过 9090 端口,统计当前 User Pod 的并发情况,提供给 AutoScaler 采集和扩缩容参考。